comparison old-trunk/lwlink/readfiles.c @ 339:eb230fa7d28e

Prepare for migration to hg
author lost
date Fri, 19 Mar 2010 02:54:14 +0000
parents
children
comparison
equal deleted inserted replaced
338:e7885b3ee266 339:eb230fa7d28e
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 <config.h>
26
27 #include <argp.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "lwlink.h"
34 #include "util.h"
35
36 void read_lwobj16v0(fileinfo_t *fn);
37 void read_lwar1v(fileinfo_t *fn);
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 */
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
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 {
71 if (inputfiles[i] -> islib)
72 {
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);
91 break;
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 }
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
126 read_file(inputfiles[i]);
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
132 #define NEXTBYTE() do { cc++; if (cc > fn -> filesize) { fprintf(stderr, "%s: invalid file format\n", fn -> filename); exit(1); } } while (0)
133 // this macro is used to refer to the current byte in the stream
134 #define CURBYTE() (fn -> filedata[cc < fn -> filesize ? cc : fn -> filesize - 1])
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
151
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
161 cc = 8;
162
163 // init data
164 fn -> sections = NULL;
165 fn -> nsections = 0;
166
167 while (1)
168 {
169 // NEXTBYTE();
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;
190 s -> processed = 0;
191 s -> file = fn;
192
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 }
230 // skip terminating NUL
231 NEXTBYTE();
232
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;
248 s -> exportedsyms = se;
249 se -> sym = fp;
250 se -> offset = val;
251 }
252 // skip terminating NUL
253 NEXTBYTE();
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();
268 rp -> flags = RELOC_NORM;
269
270 // parse the expression
271 while (CURBYTE())
272 {
273 int tt = CURBYTE();
274 NEXTBYTE();
275 switch (tt)
276 {
277 case 0xFF:
278 // a flag specifier
279 tt = CURBYTE();
280 rp -> flags = tt;
281 NEXTBYTE();
282 term = NULL;
283 break;
284
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
316 term = lw_expr_term_create_sym(NULL, 1);
317 break;
318
319 default:
320 fprintf(stderr, "%s (%s): bad relocation expression (%02X)\n", fn -> filename, s -> name, tt);
321 exit(1);
322 }
323 if (term)
324 {
325 lw_expr_stack_push(rp -> expr, term);
326 lw_expr_term_free(term);
327 }
328 }
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();
337 }
338 // skip the NUL terminating the relocations
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 }
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
384 for (l = cc; cc < fn -> filesize && fn -> filedata[cc]; cc++)
385 /* do nothing */ ;
386
387 cc++;
388
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
398 flen = (fn -> filedata[cc++] << 24);
399 flen |= (fn -> filedata[cc++] << 16);
400 flen |= (fn -> filedata[cc++] << 8);
401 flen |= (fn -> filedata[cc++]);
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;
420 fn -> subs[fn -> nsubs] -> forced = fn -> forced;
421 read_file(fn -> subs[fn -> nsubs]);
422 fn -> nsubs++;
423 cc += flen;
424 }
425 }