Mercurial > hg-old > index.cgi
annotate lwlink/readfiles.c @ 205:42df94f30d82
checkpoint
author | lost |
---|---|
date | Sun, 19 Apr 2009 17:44:46 +0000 |
parents | 048ebb85f6ef |
children | d6cba9d66979 |
rev | line source |
---|---|
116 | 1 /* |
2 readfiles.c | |
118 | 3 Copyright © 2009 William Astle |
116 | 4 |
5 This file is part of LWLINK. | |
6 | |
7 LWLINK is free software: you can redistribute it and/or modify it under the | |
8 terms of the GNU General Public License as published by the Free Software | |
9 Foundation, either version 3 of the License, or (at your option) any later | |
10 version. | |
11 | |
12 This program is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 more details. | |
16 | |
17 You should have received a copy of the GNU General Public License along with | |
18 this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 | |
21 Reads input files | |
22 | |
23 */ | |
24 | |
25 #ifdef HAVE_CONFIG_H | |
26 #include "config.h" | |
27 #endif | |
28 | |
29 #include <argp.h> | |
30 #include <errno.h> | |
31 #include <stdio.h> | |
32 #include <stdlib.h> | |
171 | 33 #include <string.h> |
116 | 34 |
35 #include "lwlink.h" | |
36 #include "util.h" | |
37 | |
38 void read_lwobj16v0(fileinfo_t *fn); | |
171 | 39 void read_lwar1v(fileinfo_t *fn); |
116 | 40 |
41 /* | |
42 The logic of reading the entire file into memory is simple. All the symbol | |
43 names in the file are NUL terminated strings and can be used directly without | |
44 making additional copies. | |
45 */ | |
171 | 46 void read_file(fileinfo_t *fn) |
47 { | |
48 if (!memcmp(fn -> filedata, "LWOBJ16", 8)) | |
49 { | |
50 // read v0 LWOBJ16 file | |
51 read_lwobj16v0(fn); | |
52 } | |
53 else if (!memcmp(fn -> filedata, "LWAR1V", 6)) | |
54 { | |
55 // archive file | |
56 read_lwar1v(fn); | |
57 } | |
58 else | |
59 { | |
60 fprintf(stderr, "%s: unknown file format\n", fn -> filename); | |
61 exit(1); | |
62 } | |
63 } | |
64 | |
116 | 65 void read_files(void) |
66 { | |
67 int i; | |
68 long size; | |
69 FILE *f; | |
70 long bread; | |
71 for (i = 0; i < ninputfiles; i++) | |
72 { | |
180 | 73 if (inputfiles[i] -> islib) |
116 | 74 { |
180 | 75 char *tf; |
76 int s; | |
77 int j; | |
78 | |
79 f = NULL; | |
80 | |
81 for (j = 0; j < nlibdirs; j++) | |
82 { | |
83 s = strlen(libdirs[j]) + 7 + strlen(inputfiles[i] -> filename); | |
84 tf = lw_malloc(s + 1); | |
85 sprintf(tf, "%s/lib%s.a", libdirs[j], inputfiles[i] -> filename); | |
86 f = fopen(tf, "rb"); | |
87 if (!f) | |
88 { | |
89 free(tf); | |
90 continue; | |
91 } | |
92 free(tf); | |
93 } | |
94 if (!f) | |
95 { | |
96 fprintf(stderr, "Can't open library: -l%s\n", inputfiles[i] -> filename); | |
97 exit(1); | |
98 } | |
99 } | |
100 else | |
101 { | |
102 f = fopen(inputfiles[i] -> filename, "rb"); | |
103 if (!f) | |
104 { | |
105 fprintf(stderr, "Can't open file %s:", inputfiles[i] -> filename); | |
106 perror(""); | |
107 exit(1); | |
108 } | |
116 | 109 } |
110 fseek(f, 0, SEEK_END); | |
111 size = ftell(f); | |
112 rewind(f); | |
113 | |
114 inputfiles[i] -> filedata = lw_malloc(size); | |
115 inputfiles[i] -> filesize = size; | |
116 | |
117 bread = fread(inputfiles[i] -> filedata, 1, size, f); | |
118 if (bread < size) | |
119 { | |
120 fprintf(stderr, "Short read on file %s (%ld/%ld):", inputfiles[i] -> filename, bread, size); | |
121 perror(""); | |
122 exit(1); | |
123 } | |
124 | |
125 fclose(f); | |
126 | |
171 | 127 read_file(inputfiles[i]); |
116 | 128 } |
129 } | |
130 | |
131 // this macro is used to bail out if we run off the end of the file data | |
132 // while parsing - it keeps the code below cleaner | |
124 | 133 #define NEXTBYTE() do { cc++; if (cc > fn -> filesize) { fprintf(stderr, "%s: invalid file format\n", fn -> filename); exit(1); } } while (0) |
116 | 134 // this macro is used to refer to the current byte in the stream |
124 | 135 #define CURBYTE() (fn -> filedata[cc < fn -> filesize ? cc : fn -> filesize - 1]) |
116 | 136 // this one will leave the input pointer past the trailing NUL |
137 #define CURSTR() read_lwobj16v0_str(&cc, fn) | |
138 unsigned char *read_lwobj16v0_str(long *cc1, fileinfo_t *fn) | |
139 { | |
140 int cc = *cc1; | |
141 unsigned char *fp; | |
142 fp = &CURBYTE(); | |
143 while (CURBYTE()) | |
144 NEXTBYTE(); | |
145 NEXTBYTE(); | |
146 *cc1 = cc; | |
147 return fp; | |
148 } | |
149 // the function below can be switched to dealing with data coming from a | |
150 // source other than an in-memory byte pool by adjusting the input data | |
151 // in "fn" and the above two macros | |
171 | 152 |
116 | 153 void read_lwobj16v0(fileinfo_t *fn) |
154 { | |
155 unsigned char *fp; | |
156 long cc; | |
157 section_t *s; | |
158 int val; | |
159 symtab_t *se; | |
160 | |
161 // start reading *after* the magic number | |
126 | 162 cc = 8; |
116 | 163 |
164 // init data | |
165 fn -> sections = NULL; | |
166 fn -> nsections = 0; | |
167 | |
168 while (1) | |
169 { | |
126 | 170 // NEXTBYTE(); |
116 | 171 // bail out if no more sections |
172 if (!(CURBYTE())) | |
173 break; | |
174 | |
175 fp = CURSTR(); | |
176 | |
177 // we now have a section name in fp | |
178 // create new section entry | |
179 fn -> sections = lw_realloc(fn -> sections, sizeof(section_t) * (fn -> nsections + 1)); | |
180 s = &(fn -> sections[fn -> nsections]); | |
181 fn -> nsections += 1; | |
182 | |
183 s -> localsyms = NULL; | |
184 s -> flags = 0; | |
185 s -> codesize = 0; | |
186 s -> name = fp; | |
187 s -> loadaddress = 0; | |
188 s -> localsyms = NULL; | |
189 s -> exportedsyms = NULL; | |
190 s -> incompletes = NULL; | |
119 | 191 s -> processed = 0; |
192 s -> file = fn; | |
193 | |
116 | 194 // read flags |
195 while (CURBYTE()) | |
196 { | |
197 switch (CURBYTE()) | |
198 { | |
199 case 0x01: | |
200 s -> flags |= SECTION_BSS; | |
201 break; | |
202 | |
203 default: | |
204 fprintf(stderr, "%s (%s): unrecognized section flag %02X\n", fn -> filename, s -> name, (int)(CURBYTE())); | |
205 exit(1); | |
206 } | |
207 NEXTBYTE(); | |
208 } | |
209 // skip NUL terminating flags | |
210 NEXTBYTE(); | |
211 | |
212 // now parse the local symbol table | |
213 while (CURBYTE()) | |
214 { | |
215 fp = CURSTR(); | |
216 | |
217 // fp is the symbol name | |
218 val = (CURBYTE()) << 8; | |
219 NEXTBYTE(); | |
220 val |= (CURBYTE()); | |
221 NEXTBYTE(); | |
222 // val is now the symbol value | |
223 | |
224 // create symbol table entry | |
225 se = lw_malloc(sizeof(symtab_t)); | |
226 se -> next = s -> localsyms; | |
227 s -> localsyms = se; | |
228 se -> sym = fp; | |
229 se -> offset = val; | |
230 } | |
124 | 231 // skip terminating NUL |
232 NEXTBYTE(); | |
233 | |
116 | 234 // now parse the exported symbol table |
235 while (CURBYTE()) | |
236 { | |
237 fp = CURSTR(); | |
238 | |
239 // fp is the symbol name | |
240 val = (CURBYTE()) << 8; | |
241 NEXTBYTE(); | |
242 val |= (CURBYTE()); | |
243 NEXTBYTE(); | |
244 // val is now the symbol value | |
245 | |
246 // create symbol table entry | |
247 se = lw_malloc(sizeof(symtab_t)); | |
248 se -> next = s -> exportedsyms; | |
128 | 249 s -> exportedsyms = se; |
116 | 250 se -> sym = fp; |
251 se -> offset = val; | |
252 } | |
124 | 253 // skip terminating NUL |
254 NEXTBYTE(); | |
116 | 255 |
256 // now parse the incomplete references and make a list of | |
257 // external references that need resolution | |
258 while (CURBYTE()) | |
259 { | |
260 reloc_t *rp; | |
261 lw_expr_term_t *term; | |
262 | |
263 // we have a reference | |
264 rp = lw_malloc(sizeof(reloc_t)); | |
265 rp -> next = s -> incompletes; | |
266 s -> incompletes = rp; | |
267 rp -> offset = 0; | |
268 rp -> expr = lw_expr_stack_create(); | |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
269 rp -> flags = RELOC_NORM; |
116 | 270 |
271 // parse the expression | |
272 while (CURBYTE()) | |
273 { | |
274 int tt = CURBYTE(); | |
275 NEXTBYTE(); | |
276 switch (tt) | |
277 { | |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
278 case 0xFF: |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
279 // a flag specifier |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
280 tt = CURBYTE(); |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
281 rp -> flags = tt; |
205 | 282 NEXTBYTE(); |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
283 term = NULL; |
205 | 284 break; |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
285 |
116 | 286 case 0x01: |
287 // 16 bit integer | |
288 tt = CURBYTE() << 8; | |
289 NEXTBYTE(); | |
290 tt |= CURBYTE(); | |
291 NEXTBYTE(); | |
292 // normalize for negatives... | |
293 if (tt > 0x7fff) | |
294 tt -= 0x10000; | |
295 term = lw_expr_term_create_int(tt); | |
296 break; | |
297 | |
298 case 0x02: | |
299 // external symbol reference | |
300 term = lw_expr_term_create_sym(CURSTR(), 0); | |
301 break; | |
302 | |
303 case 0x03: | |
304 // internal symbol reference | |
305 term = lw_expr_term_create_sym(CURSTR(), 1); | |
306 break; | |
307 | |
308 case 0x04: | |
309 // operator | |
310 term = lw_expr_term_create_oper(CURBYTE()); | |
311 NEXTBYTE(); | |
312 break; | |
313 | |
314 case 0x05: | |
315 // section base reference (NULL internal reference is | |
316 // the section base address | |
120 | 317 term = lw_expr_term_create_sym(NULL, 1); |
116 | 318 break; |
319 | |
320 default: | |
205 | 321 fprintf(stderr, "%s (%s): bad relocation expression (%02X)\n", fn -> filename, s -> name, tt); |
116 | 322 exit(1); |
323 } | |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
324 if (term) |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
325 { |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
326 lw_expr_stack_push(rp -> expr, term); |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
327 lw_expr_term_free(term); |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
328 } |
116 | 329 } |
127 | 330 // skip the NUL |
331 NEXTBYTE(); | |
332 | |
333 // fetch the offset | |
334 rp -> offset = CURBYTE() << 8; | |
335 NEXTBYTE(); | |
336 rp -> offset |= CURBYTE() & 0xff; | |
337 NEXTBYTE(); | |
116 | 338 } |
124 | 339 // skip the NUL terminating the relocations |
116 | 340 NEXTBYTE(); |
341 | |
342 // now set code location and size and verify that the file | |
343 // contains data going to the end of the code (if !SECTION_BSS) | |
344 s -> codesize = CURBYTE() << 8; | |
345 NEXTBYTE(); | |
346 s -> codesize |= CURBYTE(); | |
347 NEXTBYTE(); | |
348 | |
349 s -> code = &(CURBYTE()); | |
350 | |
351 // skip the code if we're not in a BSS section | |
352 if (!(s -> flags & SECTION_BSS)) | |
353 { | |
354 int i; | |
355 for (i = 0; i < s -> codesize; i++) | |
356 NEXTBYTE(); | |
357 } | |
358 } | |
359 } | |
171 | 360 |
361 /* | |
362 Read an archive file - this will create a "sub" record and farm out the | |
363 parsing of the sub files to the regular file parsers | |
364 | |
365 The archive file format consists of the 6 byte magic number followed by a | |
366 series of records as follows: | |
367 | |
368 - NUL terminated file name | |
369 - 32 bit file length in big endian order | |
370 - the file data | |
371 | |
372 An empty file name indicates the end of the file. | |
373 | |
374 */ | |
375 void read_lwar1v(fileinfo_t *fn) | |
376 { | |
377 unsigned long cc = 6; | |
378 unsigned long flen; | |
379 unsigned long l; | |
380 for (;;) | |
381 { | |
382 if (cc >= fn -> filesize || !(fn -> filedata[cc])) | |
383 return; | |
384 | |
173 | 385 for (l = cc; cc < fn -> filesize && fn -> filedata[cc]; cc++) |
171 | 386 /* do nothing */ ; |
387 | |
173 | 388 cc++; |
389 | |
171 | 390 if (cc >= fn -> filesize) |
391 { | |
392 fprintf(stderr, "Malformed archive file %s.\n", fn -> filename); | |
393 exit(1); | |
394 } | |
395 | |
396 if (cc + 4 > fn -> filesize) | |
397 return; | |
398 | |
173 | 399 flen = (fn -> filedata[cc++] << 24); |
400 flen |= (fn -> filedata[cc++] << 16); | |
401 flen |= (fn -> filedata[cc++] << 8); | |
402 flen |= (fn -> filedata[cc++]); | |
171 | 403 |
404 if (flen == 0) | |
405 return; | |
406 | |
407 if (cc + flen > fn -> filesize) | |
408 { | |
409 fprintf(stderr, "Malformed archive file %s.\n", fn -> filename); | |
410 exit(1); | |
411 } | |
412 | |
413 // add the "sub" input file | |
414 fn -> subs = lw_realloc(fn -> subs, sizeof(fileinfo_t *) * (fn -> nsubs + 1)); | |
415 fn -> subs[fn -> nsubs] = lw_malloc(sizeof(fileinfo_t)); | |
416 memset(fn -> subs[fn -> nsubs], 0, sizeof(fileinfo_t)); | |
417 fn -> subs[fn -> nsubs] -> filedata = fn -> filedata + cc; | |
418 fn -> subs[fn -> nsubs] -> filesize = flen; | |
419 fn -> subs[fn -> nsubs] -> filename = lw_strdup(fn -> filedata + l); | |
420 fn -> subs[fn -> nsubs] -> parent = fn; | |
173 | 421 |
171 | 422 read_file(fn -> subs[fn -> nsubs]); |
423 fn -> nsubs++; | |
173 | 424 cc += flen; |
171 | 425 } |
426 } |