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