Mercurial > hg-old > index.cgi
annotate lwlink/readfiles.c @ 264:61d1db1dfe2a 2.6
Build manual for release
author | lost |
---|---|
date | Tue, 22 Dec 2009 05:27:32 +0000 |
parents | e8d70b95ec41 |
children |
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(); |
243 | 280 switch (tt) |
281 { | |
282 case 0x01: | |
283 rp -> flags |= RELOC_8BIT; | |
284 break; | |
285 case 0x02: | |
286 rp -> flags |= RELOC_0BIT; | |
287 break; | |
288 default: | |
289 fprintf(stderr, "%s (%s): unknown relocation flag (%02X)\n", fn -> filename, s -> name, tt); | |
290 exit(1); | |
291 } | |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
292 rp -> flags = tt; |
205 | 293 NEXTBYTE(); |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
294 term = NULL; |
205 | 295 break; |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
296 |
116 | 297 case 0x01: |
298 // 16 bit integer | |
299 tt = CURBYTE() << 8; | |
300 NEXTBYTE(); | |
301 tt |= CURBYTE(); | |
302 NEXTBYTE(); | |
303 // normalize for negatives... | |
304 if (tt > 0x7fff) | |
305 tt -= 0x10000; | |
306 term = lw_expr_term_create_int(tt); | |
307 break; | |
308 | |
309 case 0x02: | |
310 // external symbol reference | |
311 term = lw_expr_term_create_sym(CURSTR(), 0); | |
312 break; | |
313 | |
314 case 0x03: | |
315 // internal symbol reference | |
316 term = lw_expr_term_create_sym(CURSTR(), 1); | |
317 break; | |
318 | |
319 case 0x04: | |
320 // operator | |
321 term = lw_expr_term_create_oper(CURBYTE()); | |
322 NEXTBYTE(); | |
323 break; | |
324 | |
325 case 0x05: | |
326 // section base reference (NULL internal reference is | |
327 // the section base address | |
120 | 328 term = lw_expr_term_create_sym(NULL, 1); |
116 | 329 break; |
330 | |
331 default: | |
205 | 332 fprintf(stderr, "%s (%s): bad relocation expression (%02X)\n", fn -> filename, s -> name, tt); |
116 | 333 exit(1); |
334 } | |
204
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
335 if (term) |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
336 { |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
337 lw_expr_stack_push(rp -> expr, term); |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
338 lw_expr_term_free(term); |
048ebb85f6ef
Added 8 bit external references for base page addressing mode
lost
parents:
180
diff
changeset
|
339 } |
116 | 340 } |
127 | 341 // skip the NUL |
342 NEXTBYTE(); | |
343 | |
344 // fetch the offset | |
345 rp -> offset = CURBYTE() << 8; | |
346 NEXTBYTE(); | |
347 rp -> offset |= CURBYTE() & 0xff; | |
348 NEXTBYTE(); | |
116 | 349 } |
124 | 350 // skip the NUL terminating the relocations |
116 | 351 NEXTBYTE(); |
352 | |
353 // now set code location and size and verify that the file | |
354 // contains data going to the end of the code (if !SECTION_BSS) | |
355 s -> codesize = CURBYTE() << 8; | |
356 NEXTBYTE(); | |
357 s -> codesize |= CURBYTE(); | |
358 NEXTBYTE(); | |
359 | |
360 s -> code = &(CURBYTE()); | |
361 | |
362 // skip the code if we're not in a BSS section | |
363 if (!(s -> flags & SECTION_BSS)) | |
364 { | |
365 int i; | |
366 for (i = 0; i < s -> codesize; i++) | |
367 NEXTBYTE(); | |
368 } | |
369 } | |
370 } | |
171 | 371 |
372 /* | |
373 Read an archive file - this will create a "sub" record and farm out the | |
374 parsing of the sub files to the regular file parsers | |
375 | |
376 The archive file format consists of the 6 byte magic number followed by a | |
377 series of records as follows: | |
378 | |
379 - NUL terminated file name | |
380 - 32 bit file length in big endian order | |
381 - the file data | |
382 | |
383 An empty file name indicates the end of the file. | |
384 | |
385 */ | |
386 void read_lwar1v(fileinfo_t *fn) | |
387 { | |
388 unsigned long cc = 6; | |
389 unsigned long flen; | |
390 unsigned long l; | |
391 for (;;) | |
392 { | |
393 if (cc >= fn -> filesize || !(fn -> filedata[cc])) | |
394 return; | |
395 | |
173 | 396 for (l = cc; cc < fn -> filesize && fn -> filedata[cc]; cc++) |
171 | 397 /* do nothing */ ; |
398 | |
173 | 399 cc++; |
400 | |
171 | 401 if (cc >= fn -> filesize) |
402 { | |
403 fprintf(stderr, "Malformed archive file %s.\n", fn -> filename); | |
404 exit(1); | |
405 } | |
406 | |
407 if (cc + 4 > fn -> filesize) | |
408 return; | |
409 | |
173 | 410 flen = (fn -> filedata[cc++] << 24); |
411 flen |= (fn -> filedata[cc++] << 16); | |
412 flen |= (fn -> filedata[cc++] << 8); | |
413 flen |= (fn -> filedata[cc++]); | |
171 | 414 |
415 if (flen == 0) | |
416 return; | |
417 | |
418 if (cc + flen > fn -> filesize) | |
419 { | |
420 fprintf(stderr, "Malformed archive file %s.\n", fn -> filename); | |
421 exit(1); | |
422 } | |
423 | |
424 // add the "sub" input file | |
425 fn -> subs = lw_realloc(fn -> subs, sizeof(fileinfo_t *) * (fn -> nsubs + 1)); | |
426 fn -> subs[fn -> nsubs] = lw_malloc(sizeof(fileinfo_t)); | |
427 memset(fn -> subs[fn -> nsubs], 0, sizeof(fileinfo_t)); | |
428 fn -> subs[fn -> nsubs] -> filedata = fn -> filedata + cc; | |
429 fn -> subs[fn -> nsubs] -> filesize = flen; | |
430 fn -> subs[fn -> nsubs] -> filename = lw_strdup(fn -> filedata + l); | |
431 fn -> subs[fn -> nsubs] -> parent = fn; | |
248
e8d70b95ec41
Fixed various problems with determining which files to include in the output and also fixed problem identifying which files actually resolved symbols
lost
parents:
243
diff
changeset
|
432 if (fn -> subs[fn -> nsubs] -> parent -> islib == 0) |
e8d70b95ec41
Fixed various problems with determining which files to include in the output and also fixed problem identifying which files actually resolved symbols
lost
parents:
243
diff
changeset
|
433 fn -> subs[fn -> nsubs] -> forced = fn -> forced; |
e8d70b95ec41
Fixed various problems with determining which files to include in the output and also fixed problem identifying which files actually resolved symbols
lost
parents:
243
diff
changeset
|
434 else |
e8d70b95ec41
Fixed various problems with determining which files to include in the output and also fixed problem identifying which files actually resolved symbols
lost
parents:
243
diff
changeset
|
435 fn -> subs[fn -> nsubs] -> forced = 0; |
171 | 436 read_file(fn -> subs[fn -> nsubs]); |
437 fn -> nsubs++; | |
173 | 438 cc += flen; |
171 | 439 } |
440 } |