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