Mercurial > hg-old > index.cgi
comparison lwasm/output.c @ 151:427e268e876b
renamed src to lwasm to better reflect its purpose
author | lost |
---|---|
date | Fri, 30 Jan 2009 04:01:55 +0000 |
parents | src/output.c@718998b673ee |
children | 048ebb85f6ef |
comparison
equal
deleted
inserted
replaced
150:f0881c115010 | 151:427e268e876b |
---|---|
1 /* | |
2 output.c | |
3 Copyright © 2009 William Astle | |
4 | |
5 This file is part of LWASM. | |
6 | |
7 LWASM 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 Contains the code for actually outputting the assembled code | |
22 */ | |
23 | |
24 //#include <ctype.h> | |
25 #include <errno.h> | |
26 #include <stdio.h> | |
27 //#include <stdlib.h> | |
28 #include <string.h> | |
29 #include <unistd.h> | |
30 #define __output_c_seen__ | |
31 //#include "instab.h" | |
32 #include "lwasm.h" | |
33 #include "util.h" | |
34 | |
35 void write_code_raw(asmstate_t *as, FILE *of); | |
36 void write_code_decb(asmstate_t *as, FILE *of); | |
37 void write_code_rawrel(asmstate_t *as, FILE *of); | |
38 void write_code_obj(asmstate_t *as, FILE *of); | |
39 | |
40 // this prevents warnings about not using the return value of fwrite() | |
41 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0) | |
42 | |
43 void lwasm_output(asmstate_t *as) | |
44 { | |
45 FILE *of; | |
46 | |
47 if (as -> errorcount > 0) | |
48 { | |
49 fprintf(stderr, "Not doing output due to assembly errors.\n"); | |
50 return; | |
51 } | |
52 | |
53 of = fopen(as -> outfile, "wb"); | |
54 if (!of) | |
55 { | |
56 fprintf(stderr, "Cannot open '%s' for output", as -> outfile); | |
57 perror(""); | |
58 return; | |
59 } | |
60 | |
61 switch (as -> outformat) | |
62 { | |
63 case OUTPUT_RAW: | |
64 write_code_raw(as, of); | |
65 break; | |
66 | |
67 case OUTPUT_DECB: | |
68 write_code_decb(as, of); | |
69 break; | |
70 | |
71 case OUTPUT_RAWREL: | |
72 write_code_rawrel(as, of); | |
73 break; | |
74 | |
75 case OUTPUT_OBJ: | |
76 write_code_obj(as, of); | |
77 break; | |
78 | |
79 default: | |
80 fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); | |
81 fclose(of); | |
82 unlink(as -> outfile); | |
83 return; | |
84 } | |
85 | |
86 fclose(of); | |
87 } | |
88 | |
89 /* | |
90 rawrel output treats an ORG directive as an offset from the start of the | |
91 file. Undefined results will occur if an ORG directive moves the output | |
92 pointer backward. This particular implementation uses "fseek" to handle | |
93 ORG requests and to skip over RMBs. | |
94 | |
95 This simple brain damanged method simply does an fseek before outputting | |
96 each instruction. | |
97 */ | |
98 void write_code_rawrel(asmstate_t *as, FILE *of) | |
99 { | |
100 lwasm_line_t *cl; | |
101 | |
102 for (cl = as -> lineshead; cl; cl = cl -> next) | |
103 { | |
104 if (cl -> codelen == 0) | |
105 continue; | |
106 | |
107 fseek(of, cl -> codeaddr, SEEK_SET); | |
108 writebytes(cl -> bytes, cl -> codelen, 1, of); | |
109 } | |
110 } | |
111 | |
112 /* | |
113 raw merely writes all the bytes directly to the file as is. ORG is just a | |
114 reference for the assembler to handle absolute references. Multiple ORG | |
115 statements will produce mostly useless results | |
116 */ | |
117 void write_code_raw(asmstate_t *as, FILE *of) | |
118 { | |
119 lwasm_line_t *cl; | |
120 | |
121 for (cl = as -> lineshead; cl; cl = cl -> next) | |
122 { | |
123 if (cl -> nocodelen) | |
124 { | |
125 int i; | |
126 for (i = 0; i < cl -> nocodelen; i++) | |
127 writebytes("\0", 1, 1, of); | |
128 continue; | |
129 } | |
130 writebytes(cl -> bytes, cl -> codelen, 1, of); | |
131 } | |
132 } | |
133 | |
134 void write_code_decb(asmstate_t *as, FILE *of) | |
135 { | |
136 long preambloc; | |
137 lwasm_line_t *cl; | |
138 int blocklen = -1; | |
139 int nextcalc = -1; | |
140 unsigned char outbuf[5]; | |
141 | |
142 for (cl = as -> lineshead; cl; cl = cl -> next) | |
143 { | |
144 if (cl -> nocodelen) | |
145 continue; | |
146 if (cl -> codeaddr != nextcalc && cl -> codelen > 0) | |
147 { | |
148 // need preamble here | |
149 if (blocklen > 0) | |
150 { | |
151 // update previous preamble if needed | |
152 fseek(of, preambloc, SEEK_SET); | |
153 outbuf[0] = (blocklen >> 8) & 0xFF; | |
154 outbuf[1] = blocklen & 0xFF; | |
155 writebytes(outbuf, 2, 1, of); | |
156 fseek(of, 0, SEEK_END); | |
157 } | |
158 blocklen = 0; | |
159 nextcalc = cl -> codeaddr; | |
160 outbuf[0] = 0x00; | |
161 outbuf[1] = 0x00; | |
162 outbuf[2] = 0x00; | |
163 outbuf[3] = (nextcalc >> 8) & 0xFF; | |
164 outbuf[4] = nextcalc & 0xFF; | |
165 preambloc = ftell(of) + 1; | |
166 writebytes(outbuf, 5, 1, of); | |
167 } | |
168 nextcalc += cl -> codelen; | |
169 writebytes(cl -> bytes, cl -> codelen, 1, of); | |
170 blocklen += cl -> codelen; | |
171 } | |
172 if (blocklen > 0) | |
173 { | |
174 fseek(of, preambloc, SEEK_SET); | |
175 outbuf[0] = (blocklen >> 8) & 0xFF; | |
176 outbuf[1] = blocklen & 0xFF; | |
177 writebytes(outbuf, 2, 1, of); | |
178 fseek(of, 0, SEEK_END); | |
179 } | |
180 | |
181 // now write postamble | |
182 outbuf[0] = 0xFF; | |
183 outbuf[1] = 0x00; | |
184 outbuf[2] = 0x00; | |
185 outbuf[3] = (as -> execaddr >> 8) & 0xFF; | |
186 outbuf[4] = (as -> execaddr) & 0xFF; | |
187 writebytes(outbuf, 5, 1, of); | |
188 } | |
189 | |
190 void write_code_obj_sbadd(sectiontab_t *s, unsigned char b) | |
191 { | |
192 if (s -> oblen >= s -> obsize) | |
193 { | |
194 s -> obytes = lwasm_realloc(s -> obytes, s -> obsize + 128); | |
195 s -> obsize += 128; | |
196 } | |
197 s -> obytes[s -> oblen] = b; | |
198 s -> oblen += 1; | |
199 } | |
200 | |
201 void write_code_obj(asmstate_t *as, FILE *of) | |
202 { | |
203 lwasm_line_t *l; | |
204 sectiontab_t *s; | |
205 lwasm_symbol_ent_t *se; | |
206 export_list_t *ex; | |
207 section_reloc_list_t *re; | |
208 lwasm_expr_stack_node_t *sn; | |
209 | |
210 int i; | |
211 unsigned char buf[16]; | |
212 | |
213 // output the magic number and file header | |
214 // the 8 is NOT an error | |
215 writebytes("LWOBJ16", 8, 1, of); | |
216 | |
217 // run through the entire system and build the byte streams for each | |
218 // section; at the same time, generate a list of "local" symbols to | |
219 // output for each section | |
220 // NOTE: for "local" symbols, we will append \x01 and the ascii string | |
221 // of the context identifier (so sym in context 1 would be "sym\x011" | |
222 // we can do this because the linker can handle symbols with any | |
223 // character other than NUL. | |
224 // also we will generate a list of incomplete references for each | |
225 // section along with the actual definition that will be output | |
226 | |
227 // once all this information is generated, we will output each section | |
228 // to the file | |
229 | |
230 // NOTE: we build everything in memory then output it because the | |
231 // assembler accepts multiple instances of the same section but the | |
232 // linker expects only one instance of each section in the object file | |
233 // so we need to collect all the various pieces of a section together | |
234 // (also, the assembler treated multiple instances of the same section | |
235 // as continuations of previous sections so we would need to collect | |
236 // them together anyway. | |
237 | |
238 for (l = as -> lineshead; l; l = l -> next) | |
239 { | |
240 if (l -> sect) | |
241 { | |
242 // we're in a section - need to output some bytes | |
243 for (i = 0; i < l -> codelen; i++) | |
244 write_code_obj_sbadd(l -> sect, l -> bytes[i]); | |
245 for (i = 0; i < l -> nocodelen; i++) | |
246 write_code_obj_sbadd(l -> sect, 0); | |
247 | |
248 // do we have a "relocation"? If so, add a reference to the | |
249 // relocation table | |
250 if (l -> relocoff >= 0) | |
251 { | |
252 // build the relocation reference for the linker | |
253 re = lwasm_alloc(sizeof(section_reloc_list_t)); | |
254 re -> next = l -> sect -> rl; | |
255 l -> sect -> rl = re; | |
256 | |
257 re -> offset = l -> codeaddr + l -> relocoff; | |
258 re -> expr = l -> exprs[0]; | |
259 re -> context = l -> context; | |
260 } | |
261 } | |
262 } | |
263 | |
264 // run through the sections | |
265 for (s = as -> sections; s; s = s -> next) | |
266 { | |
267 // write the name | |
268 writebytes(s -> name, strlen(s -> name) + 1, 1, of); | |
269 | |
270 // write the flags | |
271 if (s -> flags & SECTION_BSS) | |
272 writebytes("\x01", 1, 1, of); | |
273 | |
274 // indicate end of flags - the "" is NOT an error | |
275 writebytes("", 1, 1, of); | |
276 | |
277 | |
278 // now the local symbols | |
279 for (se = as -> symhead; se; se = se -> next) | |
280 { | |
281 // ignore symbols not in this section | |
282 if (se -> sect != s) | |
283 continue; | |
284 | |
285 if (se -> flags & SYMBOL_SET) | |
286 continue; | |
287 | |
288 if (se -> flags & SYMBOL_EXTERN) | |
289 continue; | |
290 | |
291 writebytes(se -> sym, strlen(se -> sym), 1, of); | |
292 if (se -> context >= 0) | |
293 { | |
294 writebytes("\x01", 1, 1, of); | |
295 sprintf(buf, "%d", se -> context); | |
296 writebytes(buf, strlen(buf), 1, of); | |
297 } | |
298 // the "" is NOT an error | |
299 writebytes("", 1, 1, of); | |
300 | |
301 // write the address | |
302 buf[0] = (se -> value >> 8) & 0xff; | |
303 buf[1] = se -> value & 0xff; | |
304 writebytes(buf, 2, 1, of); | |
305 } | |
306 // flag end of local symbol table - "" is NOT an error | |
307 writebytes("", 1, 1, of); | |
308 | |
309 // now the exports | |
310 for (ex = s -> exports; ex; ex = ex -> next) | |
311 { | |
312 writebytes(ex -> sym, strlen(ex -> sym) + 1, 1, of); | |
313 buf[0] = (ex -> offset >> 8) & 0xff; | |
314 buf[1] = ex -> offset & 0xff; | |
315 writebytes(buf, 2, 1, of); | |
316 } | |
317 | |
318 // flag end of exported symbols - "" is NOT an error | |
319 writebytes("", 1, 1, of); | |
320 | |
321 // now output the "incomplete references" | |
322 // this being the most complex bit | |
323 for (re = s -> rl; re; re = re -> next) | |
324 { | |
325 if (re -> expr == NULL) | |
326 { | |
327 // this is an error but we'll simply ignore it | |
328 // and not output this expression | |
329 continue; | |
330 } | |
331 | |
332 // work through each term in the expression and output | |
333 // the proper equivalent to the object file | |
334 for (sn = re -> expr -> head; sn; sn = sn -> next) | |
335 { | |
336 switch (sn -> term -> term_type) | |
337 { | |
338 case LWASM_TERM_OPER: | |
339 buf[0] = 0x04; | |
340 buf[1] = sn -> term -> value; | |
341 writebytes(buf, 2, 1, of); | |
342 break; | |
343 | |
344 case LWASM_TERM_INT: | |
345 buf[0] = 0x01; | |
346 buf[1] = (sn -> term -> value >> 8) & 0xff; | |
347 buf[2] = sn -> term -> value & 0xff; | |
348 writebytes(buf, 3, 1, of); | |
349 break; | |
350 | |
351 case LWASM_TERM_SECBASE: | |
352 writebytes("\x05", 1, 1, of); | |
353 break; | |
354 | |
355 case LWASM_TERM_SYM: | |
356 // now for the ugly part - resolve a symbol reference | |
357 // and determine whether it's internal, external, or | |
358 // a section base | |
359 se = lwasm_find_symbol(as, sn -> term -> symbol, re -> context); | |
360 if (!se) | |
361 se = lwasm_find_symbol(as, sn -> term -> symbol, -1); | |
362 if (!se || se -> flags & SYMBOL_EXTERN) | |
363 { | |
364 // not found - assume external reference | |
365 // found but flagged external - handle it | |
366 writebytes("\x02", 1, 1, of); | |
367 writebytes(se -> sym, strlen(se -> sym) + 1, 1, of); | |
368 break; | |
369 } | |
370 // a local symbol reference here | |
371 writebytes("\x03", 1, 1, of); | |
372 writebytes(se -> sym, strlen(se -> sym), 1, of); | |
373 if (se -> context >= 0) | |
374 { | |
375 writebytes("\x01", 1, 1, of); | |
376 sprintf(buf, "%d", se -> context); | |
377 writebytes(buf, strlen(buf), 1, of); | |
378 } | |
379 writebytes("", 1, 1, of); | |
380 break; | |
381 | |
382 default: | |
383 // unrecognized term type - replace with integer 0 | |
384 buf[0] = 0x01; | |
385 buf[1] = 0x00; | |
386 buf[2] = 0x00; | |
387 writebytes(buf, 3, 1, of); | |
388 break; | |
389 } | |
390 } | |
391 | |
392 // flag end of expressions | |
393 writebytes("", 1, 1, of); | |
394 | |
395 // write the offset | |
396 buf[0] = (re -> offset >> 8) & 0xff; | |
397 buf[1] = re -> offset & 0xff; | |
398 writebytes(buf, 2, 1, of); | |
399 } | |
400 // flag end of incomplete references list | |
401 writebytes("", 1, 1, of); | |
402 | |
403 // now blast out the code | |
404 | |
405 // length | |
406 buf[0] = s -> oblen >> 8 & 0xff; | |
407 buf[1] = s -> oblen & 0xff; | |
408 writebytes(buf, 2, 1, of); | |
409 | |
410 if (!(s -> flags & SECTION_BSS)) | |
411 { | |
412 writebytes(s -> obytes, s -> oblen, 1, of); | |
413 } | |
414 } | |
415 | |
416 // flag no more sections | |
417 // the "" is NOT an error | |
418 writebytes("", 1, 1, of); | |
419 } |