Mercurial > hg-old > index.cgi
comparison lwlink/readfiles.c @ 139:106c2fe3c9d9
repo reorg
author | lost |
---|---|
date | Wed, 28 Jan 2009 05:59:14 +0000 |
parents | lwlink-old/trunk/src/readfiles.c@050864a47b38 |
children | d610b8aef91b |
comparison
equal
deleted
inserted
replaced
138:050864a47b38 | 139:106c2fe3c9d9 |
---|---|
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 #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> | |
33 | |
34 #include "lwlink.h" | |
35 #include "util.h" | |
36 | |
37 void read_lwobj16v0(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_files(void) | |
45 { | |
46 int i; | |
47 long size; | |
48 FILE *f; | |
49 long bread; | |
50 for (i = 0; i < ninputfiles; i++) | |
51 { | |
52 f = fopen(inputfiles[i] -> filename, "rb"); | |
53 if (!f) | |
54 { | |
55 fprintf(stderr, "Can't open file %s:", inputfiles[i] -> filename); | |
56 perror(""); | |
57 exit(1); | |
58 } | |
59 fseek(f, 0, SEEK_END); | |
60 size = ftell(f); | |
61 rewind(f); | |
62 | |
63 inputfiles[i] -> filedata = lw_malloc(size); | |
64 inputfiles[i] -> filesize = size; | |
65 | |
66 bread = fread(inputfiles[i] -> filedata, 1, size, f); | |
67 if (bread < size) | |
68 { | |
69 fprintf(stderr, "Short read on file %s (%ld/%ld):", inputfiles[i] -> filename, bread, size); | |
70 perror(""); | |
71 exit(1); | |
72 } | |
73 | |
74 fclose(f); | |
75 | |
76 if (!memcmp(inputfiles[i] -> filedata, "LWOBJ16", 8)) | |
77 { | |
78 // read v0 LWOBJ16 file | |
79 read_lwobj16v0(inputfiles[i]); | |
80 } | |
81 else | |
82 { | |
83 fprintf(stderr, "%s: unknown file format\n", inputfiles[i] -> filename); | |
84 exit(1); | |
85 } | |
86 } | |
87 } | |
88 | |
89 // this macro is used to bail out if we run off the end of the file data | |
90 // while parsing - it keeps the code below cleaner | |
91 #define NEXTBYTE() do { cc++; if (cc > fn -> filesize) { fprintf(stderr, "%s: invalid file format\n", fn -> filename); exit(1); } } while (0) | |
92 // this macro is used to refer to the current byte in the stream | |
93 #define CURBYTE() (fn -> filedata[cc < fn -> filesize ? cc : fn -> filesize - 1]) | |
94 // this one will leave the input pointer past the trailing NUL | |
95 #define CURSTR() read_lwobj16v0_str(&cc, fn) | |
96 unsigned char *read_lwobj16v0_str(long *cc1, fileinfo_t *fn) | |
97 { | |
98 int cc = *cc1; | |
99 unsigned char *fp; | |
100 fp = &CURBYTE(); | |
101 while (CURBYTE()) | |
102 NEXTBYTE(); | |
103 NEXTBYTE(); | |
104 *cc1 = cc; | |
105 return fp; | |
106 } | |
107 // the function below can be switched to dealing with data coming from a | |
108 // source other than an in-memory byte pool by adjusting the input data | |
109 // in "fn" and the above two macros | |
110 void read_lwobj16v0(fileinfo_t *fn) | |
111 { | |
112 unsigned char *fp; | |
113 long cc; | |
114 section_t *s; | |
115 int val; | |
116 symtab_t *se; | |
117 | |
118 // start reading *after* the magic number | |
119 cc = 8; | |
120 | |
121 // init data | |
122 fn -> sections = NULL; | |
123 fn -> nsections = 0; | |
124 | |
125 while (1) | |
126 { | |
127 // NEXTBYTE(); | |
128 // bail out if no more sections | |
129 if (!(CURBYTE())) | |
130 break; | |
131 | |
132 fp = CURSTR(); | |
133 | |
134 // we now have a section name in fp | |
135 // create new section entry | |
136 fn -> sections = lw_realloc(fn -> sections, sizeof(section_t) * (fn -> nsections + 1)); | |
137 s = &(fn -> sections[fn -> nsections]); | |
138 fn -> nsections += 1; | |
139 | |
140 s -> localsyms = NULL; | |
141 s -> flags = 0; | |
142 s -> codesize = 0; | |
143 s -> name = fp; | |
144 s -> loadaddress = 0; | |
145 s -> localsyms = NULL; | |
146 s -> exportedsyms = NULL; | |
147 s -> incompletes = NULL; | |
148 s -> processed = 0; | |
149 s -> file = fn; | |
150 | |
151 // read flags | |
152 while (CURBYTE()) | |
153 { | |
154 switch (CURBYTE()) | |
155 { | |
156 case 0x01: | |
157 s -> flags |= SECTION_BSS; | |
158 break; | |
159 | |
160 default: | |
161 fprintf(stderr, "%s (%s): unrecognized section flag %02X\n", fn -> filename, s -> name, (int)(CURBYTE())); | |
162 exit(1); | |
163 } | |
164 NEXTBYTE(); | |
165 } | |
166 // skip NUL terminating flags | |
167 NEXTBYTE(); | |
168 | |
169 // now parse the local symbol table | |
170 while (CURBYTE()) | |
171 { | |
172 fp = CURSTR(); | |
173 | |
174 // fp is the symbol name | |
175 val = (CURBYTE()) << 8; | |
176 NEXTBYTE(); | |
177 val |= (CURBYTE()); | |
178 NEXTBYTE(); | |
179 // val is now the symbol value | |
180 | |
181 // create symbol table entry | |
182 se = lw_malloc(sizeof(symtab_t)); | |
183 se -> next = s -> localsyms; | |
184 s -> localsyms = se; | |
185 se -> sym = fp; | |
186 se -> offset = val; | |
187 } | |
188 // skip terminating NUL | |
189 NEXTBYTE(); | |
190 | |
191 // now parse the exported symbol table | |
192 while (CURBYTE()) | |
193 { | |
194 fp = CURSTR(); | |
195 | |
196 // fp is the symbol name | |
197 val = (CURBYTE()) << 8; | |
198 NEXTBYTE(); | |
199 val |= (CURBYTE()); | |
200 NEXTBYTE(); | |
201 // val is now the symbol value | |
202 | |
203 // create symbol table entry | |
204 se = lw_malloc(sizeof(symtab_t)); | |
205 se -> next = s -> exportedsyms; | |
206 s -> exportedsyms = se; | |
207 se -> sym = fp; | |
208 se -> offset = val; | |
209 } | |
210 // skip terminating NUL | |
211 NEXTBYTE(); | |
212 | |
213 // now parse the incomplete references and make a list of | |
214 // external references that need resolution | |
215 while (CURBYTE()) | |
216 { | |
217 reloc_t *rp; | |
218 lw_expr_term_t *term; | |
219 | |
220 // we have a reference | |
221 rp = lw_malloc(sizeof(reloc_t)); | |
222 rp -> next = s -> incompletes; | |
223 s -> incompletes = rp; | |
224 rp -> offset = 0; | |
225 rp -> expr = lw_expr_stack_create(); | |
226 | |
227 // parse the expression | |
228 while (CURBYTE()) | |
229 { | |
230 int tt = CURBYTE(); | |
231 NEXTBYTE(); | |
232 switch (tt) | |
233 { | |
234 case 0x01: | |
235 // 16 bit integer | |
236 tt = CURBYTE() << 8; | |
237 NEXTBYTE(); | |
238 tt |= CURBYTE(); | |
239 NEXTBYTE(); | |
240 // normalize for negatives... | |
241 if (tt > 0x7fff) | |
242 tt -= 0x10000; | |
243 term = lw_expr_term_create_int(tt); | |
244 break; | |
245 | |
246 case 0x02: | |
247 // external symbol reference | |
248 term = lw_expr_term_create_sym(CURSTR(), 0); | |
249 break; | |
250 | |
251 case 0x03: | |
252 // internal symbol reference | |
253 term = lw_expr_term_create_sym(CURSTR(), 1); | |
254 break; | |
255 | |
256 case 0x04: | |
257 // operator | |
258 term = lw_expr_term_create_oper(CURBYTE()); | |
259 NEXTBYTE(); | |
260 break; | |
261 | |
262 case 0x05: | |
263 // section base reference (NULL internal reference is | |
264 // the section base address | |
265 term = lw_expr_term_create_sym(NULL, 1); | |
266 break; | |
267 | |
268 default: | |
269 fprintf(stderr, "%s (%s): bad relocation expression\n", fn -> filename, s -> name); | |
270 exit(1); | |
271 } | |
272 lw_expr_stack_push(rp -> expr, term); | |
273 lw_expr_term_free(term); | |
274 } | |
275 // skip the NUL | |
276 NEXTBYTE(); | |
277 | |
278 // fetch the offset | |
279 rp -> offset = CURBYTE() << 8; | |
280 NEXTBYTE(); | |
281 rp -> offset |= CURBYTE() & 0xff; | |
282 NEXTBYTE(); | |
283 } | |
284 // skip the NUL terminating the relocations | |
285 NEXTBYTE(); | |
286 | |
287 // now set code location and size and verify that the file | |
288 // contains data going to the end of the code (if !SECTION_BSS) | |
289 s -> codesize = CURBYTE() << 8; | |
290 NEXTBYTE(); | |
291 s -> codesize |= CURBYTE(); | |
292 NEXTBYTE(); | |
293 | |
294 s -> code = &(CURBYTE()); | |
295 | |
296 // skip the code if we're not in a BSS section | |
297 if (!(s -> flags & SECTION_BSS)) | |
298 { | |
299 int i; | |
300 for (i = 0; i < s -> codesize; i++) | |
301 NEXTBYTE(); | |
302 } | |
303 } | |
304 } |