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