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 }