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