comparison src/readfiles.c @ 298:96a35a4245f3

reading files implemented
author lost
date Wed, 21 Jan 2009 03:15:49 +0000
parents
children 48945dac8178
comparison
equal deleted inserted replaced
297:c52ad3135bd3 298:96a35a4245f3
1 /*
2 readfiles.c
3 Copyright © 2008 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])
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 = 7;
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
149 // read flags
150 while (CURBYTE())
151 {
152 switch (CURBYTE())
153 {
154 case 0x01:
155 s -> flags |= SECTION_BSS;
156 break;
157
158 default:
159 fprintf(stderr, "%s (%s): unrecognized section flag %02X\n", fn -> filename, s -> name, (int)(CURBYTE()));
160 exit(1);
161 }
162 NEXTBYTE();
163 }
164 // skip NUL terminating flags
165 NEXTBYTE();
166
167 // now parse the local symbol table
168 while (CURBYTE())
169 {
170 fp = CURSTR();
171
172 // fp is the symbol name
173 val = (CURBYTE()) << 8;
174 NEXTBYTE();
175 val |= (CURBYTE());
176 NEXTBYTE();
177 // val is now the symbol value
178
179 // create symbol table entry
180 se = lw_malloc(sizeof(symtab_t));
181 se -> next = s -> localsyms;
182 s -> localsyms = se;
183 se -> sym = fp;
184 se -> offset = val;
185 se -> realval = val;
186 }
187
188 // now parse the exported symbol table
189 while (CURBYTE())
190 {
191 fp = CURSTR();
192
193 // fp is the symbol name
194 val = (CURBYTE()) << 8;
195 NEXTBYTE();
196 val |= (CURBYTE());
197 NEXTBYTE();
198 // val is now the symbol value
199
200 // create symbol table entry
201 se = lw_malloc(sizeof(symtab_t));
202 se -> next = s -> exportedsyms;
203 s -> localsyms = se;
204 se -> sym = fp;
205 se -> offset = val;
206 se -> realval = val;
207 }
208
209 // now parse the incomplete references and make a list of
210 // external references that need resolution
211 while (CURBYTE())
212 {
213 reloc_t *rp;
214 lw_expr_term_t *term;
215
216 // we have a reference
217 rp = lw_malloc(sizeof(reloc_t));
218 rp -> next = s -> incompletes;
219 s -> incompletes = rp;
220 rp -> offset = 0;
221 rp -> expr = lw_expr_stack_create();
222
223 // parse the expression
224 while (CURBYTE())
225 {
226 int tt = CURBYTE();
227 NEXTBYTE();
228 switch (tt)
229 {
230 case 0x01:
231 // 16 bit integer
232 tt = CURBYTE() << 8;
233 NEXTBYTE();
234 tt |= CURBYTE();
235 NEXTBYTE();
236 // normalize for negatives...
237 if (tt > 0x7fff)
238 tt -= 0x10000;
239 term = lw_expr_term_create_int(tt);
240 break;
241
242 case 0x02:
243 // external symbol reference
244 term = lw_expr_term_create_sym(CURSTR(), 0);
245 break;
246
247 case 0x03:
248 // internal symbol reference
249 term = lw_expr_term_create_sym(CURSTR(), 1);
250 break;
251
252 case 0x04:
253 // operator
254 term = lw_expr_term_create_oper(CURBYTE());
255 NEXTBYTE();
256 break;
257
258 case 0x05:
259 // section base reference (NULL internal reference is
260 // the section base address
261 term = lw_expr_term_create_sym(NULL, 0);
262 break;
263
264 default:
265 fprintf(stderr, "%s (%s): bad relocation expression\n", fn -> filename, s -> name);
266 exit(1);
267 }
268 lw_expr_stack_push(rp -> expr, term);
269 lw_expr_term_free(term);
270 }
271 }
272 // skip the NUL terminatin
273 NEXTBYTE();
274
275 // now set code location and size and verify that the file
276 // contains data going to the end of the code (if !SECTION_BSS)
277 s -> codesize = CURBYTE() << 8;
278 NEXTBYTE();
279 s -> codesize |= CURBYTE();
280 NEXTBYTE();
281
282 s -> code = &(CURBYTE());
283
284 // skip the code if we're not in a BSS section
285 if (!(s -> flags & SECTION_BSS))
286 {
287 int i;
288 for (i = 0; i < s -> codesize; i++)
289 NEXTBYTE();
290 }
291 }
292 }