Mercurial > hg > index.cgi
comparison lwasm/output.c @ 0:2c24602be78f
Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author | lost@l-w.ca |
---|---|
date | Wed, 19 Jan 2011 22:27:17 -0700 |
parents | |
children | 7317fbe024af |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:2c24602be78f |
---|---|
1 /* | |
2 output.c | |
3 Copyright © 2009, 2010 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 #include <errno.h> | |
24 #include <stdio.h> | |
25 #include <string.h> | |
26 #include <unistd.h> | |
27 | |
28 #include <lw_alloc.h> | |
29 #include <lw_expr.h> | |
30 | |
31 #include "lwasm.h" | |
32 | |
33 void write_code_raw(asmstate_t *as, FILE *of); | |
34 void write_code_decb(asmstate_t *as, FILE *of); | |
35 void write_code_rawrel(asmstate_t *as, FILE *of); | |
36 void write_code_obj(asmstate_t *as, FILE *of); | |
37 void write_code_os9(asmstate_t *as, FILE *of); | |
38 | |
39 // this prevents warnings about not using the return value of fwrite() | |
40 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0) | |
41 | |
42 void do_output(asmstate_t *as) | |
43 { | |
44 FILE *of; | |
45 | |
46 if (as -> errorcount > 0) | |
47 { | |
48 fprintf(stderr, "Not doing output due to assembly errors.\n"); | |
49 return; | |
50 } | |
51 | |
52 of = fopen(as -> output_file, "wb"); | |
53 if (!of) | |
54 { | |
55 fprintf(stderr, "Cannot open '%s' for output", as -> output_file); | |
56 perror(""); | |
57 return; | |
58 } | |
59 | |
60 switch (as -> output_format) | |
61 { | |
62 case OUTPUT_RAW: | |
63 write_code_raw(as, of); | |
64 break; | |
65 | |
66 case OUTPUT_DECB: | |
67 write_code_decb(as, of); | |
68 break; | |
69 | |
70 case OUTPUT_RAWREL: | |
71 write_code_rawrel(as, of); | |
72 break; | |
73 | |
74 case OUTPUT_OBJ: | |
75 write_code_obj(as, of); | |
76 break; | |
77 | |
78 case OUTPUT_OS9: | |
79 write_code_os9(as, of); | |
80 break; | |
81 | |
82 default: | |
83 fprintf(stderr, "BUG: unrecognized output format when generating output file\n"); | |
84 fclose(of); | |
85 unlink(as -> output_file); | |
86 return; | |
87 } | |
88 | |
89 fclose(of); | |
90 } | |
91 | |
92 /* | |
93 rawrel output treats an ORG directive as an offset from the start of the | |
94 file. Undefined results will occur if an ORG directive moves the output | |
95 pointer backward. This particular implementation uses "fseek" to handle | |
96 ORG requests and to skip over RMBs. | |
97 | |
98 This simple brain damanged method simply does an fseek before outputting | |
99 each instruction. | |
100 */ | |
101 void write_code_rawrel(asmstate_t *as, FILE *of) | |
102 { | |
103 line_t *cl; | |
104 | |
105 for (cl = as -> line_head; cl; cl = cl -> next) | |
106 { | |
107 if (cl -> outputl <= 0) | |
108 continue; | |
109 | |
110 fseek(of, lw_expr_intval(cl -> addr), SEEK_SET); | |
111 writebytes(cl -> output, cl -> outputl, 1, of); | |
112 } | |
113 } | |
114 | |
115 /* | |
116 raw merely writes all the bytes directly to the file as is. ORG is just a | |
117 reference for the assembler to handle absolute references. Multiple ORG | |
118 statements will produce mostly useless results | |
119 */ | |
120 void write_code_raw(asmstate_t *as, FILE *of) | |
121 { | |
122 line_t *cl; | |
123 | |
124 for (cl = as -> line_head; cl; cl = cl -> next) | |
125 { | |
126 if (cl -> len > 0 && cl -> outputl == 0) | |
127 { | |
128 int i; | |
129 for (i = 0; i < cl -> len; i++) | |
130 writebytes("\0", 1, 1, of); | |
131 continue; | |
132 } | |
133 else if (cl -> outputl > 0) | |
134 writebytes(cl -> output, cl -> outputl, 1, of); | |
135 } | |
136 } | |
137 | |
138 | |
139 /* | |
140 OS9 target also just writes all the bytes in order. No need for anything | |
141 else. | |
142 */ | |
143 void write_code_os9(asmstate_t *as, FILE *of) | |
144 { | |
145 line_t *cl; | |
146 | |
147 for (cl = as -> line_head; cl; cl = cl -> next) | |
148 { | |
149 if (cl -> inmod == 0) | |
150 continue; | |
151 if (cl -> len > 0 && cl -> outputl == 0) | |
152 { | |
153 int i; | |
154 for (i = 0; i < cl -> len; i++) | |
155 writebytes("\0", 1, 1, of); | |
156 continue; | |
157 } | |
158 else if (cl -> outputl > 0) | |
159 writebytes(cl -> output, cl -> outputl, 1, of); | |
160 } | |
161 } | |
162 | |
163 void write_code_decb(asmstate_t *as, FILE *of) | |
164 { | |
165 long preambloc; | |
166 line_t *cl; | |
167 int blocklen = -1; | |
168 int nextcalc = -1; | |
169 unsigned char outbuf[5]; | |
170 int caddr; | |
171 | |
172 for (cl = as -> line_head; cl; cl = cl -> next) | |
173 { | |
174 if (cl -> outputl < 0) | |
175 continue; | |
176 caddr = lw_expr_intval(cl -> addr); | |
177 if (caddr != nextcalc && cl -> outputl > 0) | |
178 { | |
179 // need preamble here | |
180 if (blocklen > 0) | |
181 { | |
182 // update previous preamble if needed | |
183 fseek(of, preambloc, SEEK_SET); | |
184 outbuf[0] = (blocklen >> 8) & 0xFF; | |
185 outbuf[1] = blocklen & 0xFF; | |
186 writebytes(outbuf, 2, 1, of); | |
187 fseek(of, 0, SEEK_END); | |
188 } | |
189 blocklen = 0; | |
190 nextcalc = caddr; | |
191 outbuf[0] = 0x00; | |
192 outbuf[1] = 0x00; | |
193 outbuf[2] = 0x00; | |
194 outbuf[3] = (nextcalc >> 8) & 0xFF; | |
195 outbuf[4] = nextcalc & 0xFF; | |
196 preambloc = ftell(of) + 1; | |
197 writebytes(outbuf, 5, 1, of); | |
198 } | |
199 nextcalc += cl -> outputl; | |
200 writebytes(cl -> output, cl -> outputl, 1, of); | |
201 blocklen += cl -> outputl; | |
202 } | |
203 if (blocklen > 0) | |
204 { | |
205 fseek(of, preambloc, SEEK_SET); | |
206 outbuf[0] = (blocklen >> 8) & 0xFF; | |
207 outbuf[1] = blocklen & 0xFF; | |
208 writebytes(outbuf, 2, 1, of); | |
209 fseek(of, 0, SEEK_END); | |
210 } | |
211 | |
212 // now write postamble | |
213 outbuf[0] = 0xFF; | |
214 outbuf[1] = 0x00; | |
215 outbuf[2] = 0x00; | |
216 outbuf[3] = (as -> execaddr >> 8) & 0xFF; | |
217 outbuf[4] = (as -> execaddr) & 0xFF; | |
218 writebytes(outbuf, 5, 1, of); | |
219 } | |
220 | |
221 void write_code_obj_sbadd(sectiontab_t *s, unsigned char b) | |
222 { | |
223 if (s -> oblen >= s -> obsize) | |
224 { | |
225 s -> obytes = lw_realloc(s -> obytes, s -> obsize + 128); | |
226 s -> obsize += 128; | |
227 } | |
228 s -> obytes[s -> oblen] = b; | |
229 s -> oblen += 1; | |
230 } | |
231 | |
232 | |
233 int write_code_obj_expraux(lw_expr_t e, void *of) | |
234 { | |
235 int tt; | |
236 int v; | |
237 unsigned char buf[16]; | |
238 | |
239 tt = lw_expr_type(e); | |
240 | |
241 switch (tt) | |
242 { | |
243 case lw_expr_type_oper: | |
244 buf[0] = 0x04; | |
245 switch (lw_expr_whichop(e)) | |
246 { | |
247 case lw_expr_oper_plus: | |
248 buf[1] = 0x01; | |
249 break; | |
250 | |
251 case lw_expr_oper_minus: | |
252 buf[1] = 0x02; | |
253 break; | |
254 | |
255 case lw_expr_oper_times: | |
256 buf[1] = 0x03; | |
257 break; | |
258 | |
259 case lw_expr_oper_divide: | |
260 buf[1] = 0x04; | |
261 break; | |
262 | |
263 case lw_expr_oper_mod: | |
264 buf[1] = 0x05; | |
265 break; | |
266 | |
267 case lw_expr_oper_intdiv: | |
268 buf[1] = 0x06; | |
269 break; | |
270 | |
271 case lw_expr_oper_bwand: | |
272 buf[1] = 0x07; | |
273 break; | |
274 | |
275 case lw_expr_oper_bwor: | |
276 buf[1] = 0x08; | |
277 break; | |
278 | |
279 case lw_expr_oper_bwxor: | |
280 buf[1] = 0x09; | |
281 break; | |
282 | |
283 case lw_expr_oper_and: | |
284 buf[1] = 0x0A; | |
285 break; | |
286 | |
287 case lw_expr_oper_or: | |
288 buf[1] = 0x0B; | |
289 break; | |
290 | |
291 case lw_expr_oper_neg: | |
292 buf[1] = 0x0C; | |
293 break; | |
294 | |
295 case lw_expr_oper_com: | |
296 buf[1] = 0x0D; | |
297 break; | |
298 | |
299 default: | |
300 buf[1] = 0xff; | |
301 } | |
302 writebytes(buf, 2, 1, of); | |
303 return 0; | |
304 | |
305 case lw_expr_type_int: | |
306 v = lw_expr_intval(e); | |
307 buf[0] = 0x01; | |
308 buf[1] = (v >> 8) & 0xff; | |
309 buf[2] = v & 0xff; | |
310 writebytes(buf, 3, 1, of); | |
311 return 0; | |
312 | |
313 case lw_expr_type_special: | |
314 v = lw_expr_specint(e); | |
315 switch (v) | |
316 { | |
317 case lwasm_expr_secbase: | |
318 { | |
319 // replaced with a synthetic symbol | |
320 sectiontab_t *se; | |
321 se = lw_expr_specptr(e); | |
322 | |
323 writebytes("\x03\x02", 2, 1, of); | |
324 writebytes(se -> name, strlen(se -> name) + 1, 1, of); | |
325 return 0; | |
326 } | |
327 case lwasm_expr_import: | |
328 { | |
329 importlist_t *ie; | |
330 ie = lw_expr_specptr(e); | |
331 buf[0] = 0x02; | |
332 writebytes(buf, 1, 1, of); | |
333 writebytes(ie -> symbol, strlen(ie -> symbol) + 1, 1, of); | |
334 return 0; | |
335 } | |
336 case lwasm_expr_syment: | |
337 { | |
338 struct symtabe *se; | |
339 se = lw_expr_specptr(e); | |
340 buf[0] = 0x03; | |
341 writebytes(buf, 1, 1, of); | |
342 writebytes(se -> symbol, strlen(se -> symbol), 1, of); | |
343 if (se -> context != -1) | |
344 { | |
345 sprintf(buf, "\x01%d", se -> context); | |
346 writebytes(buf, strlen(buf), 1, of); | |
347 } | |
348 writebytes("", 1, 1, of); | |
349 return 0; | |
350 } | |
351 } | |
352 | |
353 default: | |
354 // unrecognized term type - replace with integer 0 | |
355 // fprintf(stderr, "Unrecognized term type: %s\n", lw_expr_print(e)); | |
356 buf[0] = 0x01; | |
357 buf[1] = 0x00; | |
358 buf[2] = 0x00; | |
359 writebytes(buf, 3, 1, of); | |
360 break; | |
361 } | |
362 return 0; | |
363 } | |
364 | |
365 | |
366 void write_code_obj(asmstate_t *as, FILE *of) | |
367 { | |
368 line_t *l; | |
369 sectiontab_t *s; | |
370 reloctab_t *re; | |
371 exportlist_t *ex; | |
372 struct symtabe *se; | |
373 | |
374 int i; | |
375 unsigned char buf[16]; | |
376 | |
377 // output the magic number and file header | |
378 // the 8 is NOT an error | |
379 writebytes("LWOBJ16", 8, 1, of); | |
380 | |
381 // run through the entire system and build the byte streams for each | |
382 // section; at the same time, generate a list of "local" symbols to | |
383 // output for each section | |
384 // NOTE: for "local" symbols, we will append \x01 and the ascii string | |
385 // of the context identifier (so sym in context 1 would be "sym\x011" | |
386 // we can do this because the linker can handle symbols with any | |
387 // character other than NUL. | |
388 // also we will generate a list of incomplete references for each | |
389 // section along with the actual definition that will be output | |
390 | |
391 // once all this information is generated, we will output each section | |
392 // to the file | |
393 | |
394 // NOTE: we build everything in memory then output it because the | |
395 // assembler accepts multiple instances of the same section but the | |
396 // linker expects only one instance of each section in the object file | |
397 // so we need to collect all the various pieces of a section together | |
398 // (also, the assembler treated multiple instances of the same section | |
399 // as continuations of previous sections so we would need to collect | |
400 // them together anyway. | |
401 | |
402 for (l = as -> line_head; l; l = l -> next) | |
403 { | |
404 if (l -> csect) | |
405 { | |
406 // we're in a section - need to output some bytes | |
407 if (l -> outputl > 0) | |
408 for (i = 0; i < l -> outputl; i++) | |
409 write_code_obj_sbadd(l -> csect, l -> output[i]); | |
410 else if (l -> outputl == 0 || l -> outputl == -1) | |
411 for (i = 0; i < l -> len; i++) | |
412 write_code_obj_sbadd(l -> csect, 0); | |
413 } | |
414 } | |
415 | |
416 // run through the sections | |
417 for (s = as -> sections; s; s = s -> next) | |
418 { | |
419 // write the name | |
420 writebytes(s -> name, strlen(s -> name) + 1, 1, of); | |
421 | |
422 // write the flags | |
423 if (s -> flags & section_flag_bss) | |
424 writebytes("\x01", 1, 1, of); | |
425 | |
426 // indicate end of flags - the "" is NOT an error | |
427 writebytes("", 1, 1, of); | |
428 | |
429 // now the local symbols | |
430 | |
431 // a symbol for section base address | |
432 writebytes("\x02", 1, 1, of); | |
433 writebytes(s -> name, strlen(s -> name) + 1, 1, of); | |
434 // address 0; "\0" is not an error | |
435 writebytes("\0", 2, 1, of); | |
436 for (se = as -> symtab.head; se; se = se -> next) | |
437 { | |
438 lw_expr_t te; | |
439 | |
440 debug_message(as, 200, "Consider symbol %s (%p) for export in section %p", se -> symbol, se -> section, s); | |
441 | |
442 // ignore symbols not in this section | |
443 if (se -> section != s) | |
444 continue; | |
445 | |
446 debug_message(as, 200, " In section"); | |
447 | |
448 if (se -> flags & symbol_flag_set) | |
449 continue; | |
450 | |
451 debug_message(as, 200, " Not symbol_flag_set"); | |
452 | |
453 te = lw_expr_copy(se -> value); | |
454 debug_message(as, 200, " Value=%s", lw_expr_print(te)); | |
455 as -> exportcheck = 1; | |
456 as -> csect = s; | |
457 lwasm_reduce_expr(as, te); | |
458 as -> exportcheck = 0; | |
459 | |
460 debug_message(as, 200, " Value2=%s", lw_expr_print(te)); | |
461 | |
462 // don't output non-constant symbols | |
463 if (!lw_expr_istype(te, lw_expr_type_int)) | |
464 { | |
465 lw_expr_destroy(te); | |
466 continue; | |
467 } | |
468 | |
469 writebytes(se -> symbol, strlen(se -> symbol), 1, of); | |
470 if (se -> context >= 0) | |
471 { | |
472 writebytes("\x01", 1, 1, of); | |
473 sprintf(buf, "%d", se -> context); | |
474 writebytes(buf, strlen(buf), 1, of); | |
475 } | |
476 // the "" is NOT an error | |
477 writebytes("", 1, 1, of); | |
478 | |
479 // write the address | |
480 buf[0] = (lw_expr_intval(te) >> 8) & 0xff; | |
481 buf[1] = lw_expr_intval(te) & 0xff; | |
482 writebytes(buf, 2, 1, of); | |
483 lw_expr_destroy(te); | |
484 } | |
485 // flag end of local symbol table - "" is NOT an error | |
486 writebytes("", 1, 1, of); | |
487 | |
488 // now the exports -- FIXME | |
489 for (ex = as -> exportlist; ex; ex = ex -> next) | |
490 { | |
491 int eval; | |
492 lw_expr_t te; | |
493 line_t tl; | |
494 | |
495 if (ex -> se == NULL) | |
496 continue; | |
497 if (ex -> se -> section != s) | |
498 continue; | |
499 te = lw_expr_copy(ex -> se -> value); | |
500 as -> csect = ex -> se -> section; | |
501 as -> exportcheck = 1; | |
502 tl.as = as; | |
503 as -> cl = &tl; | |
504 lwasm_reduce_expr(as, te); | |
505 as -> exportcheck = 0; | |
506 as -> cl = NULL; | |
507 if (!lw_expr_istype(te, lw_expr_type_int)) | |
508 { | |
509 lw_expr_destroy(te); | |
510 continue; | |
511 } | |
512 eval = lw_expr_intval(te); | |
513 lw_expr_destroy(te); | |
514 writebytes(ex -> symbol, strlen(ex -> symbol) + 1, 1, of); | |
515 buf[0] = (eval >> 8) & 0xff; | |
516 buf[1] = eval & 0xff; | |
517 writebytes(buf, 2, 1, of); | |
518 } | |
519 | |
520 // flag end of exported symbols - "" is NOT an error | |
521 writebytes("", 1, 1, of); | |
522 | |
523 // FIXME - relocation table | |
524 for (re = s -> reloctab; re; re = re -> next) | |
525 { | |
526 int offset; | |
527 lw_expr_t te; | |
528 line_t tl; | |
529 | |
530 tl.as = as; | |
531 as -> cl = &tl; | |
532 as -> csect = s; | |
533 as -> exportcheck = 1; | |
534 | |
535 if (re -> expr == NULL) | |
536 { | |
537 // this is an error but we'll simply ignore it | |
538 // and not output this expression | |
539 continue; | |
540 } | |
541 | |
542 // work through each term in the expression and output | |
543 // the proper equivalent to the object file | |
544 if (re -> size == 1) | |
545 { | |
546 // flag an 8 bit relocation (low 8 bits will be used) | |
547 buf[0] = 0xFF; | |
548 buf[1] = 0x01; | |
549 writebytes(buf, 2, 1, of); | |
550 } | |
551 | |
552 te = lw_expr_copy(re -> offset); | |
553 lwasm_reduce_expr(as, te); | |
554 if (!lw_expr_istype(te, lw_expr_type_int)) | |
555 { | |
556 lw_expr_destroy(te); | |
557 continue; | |
558 } | |
559 offset = lw_expr_intval(te); | |
560 lw_expr_destroy(te); | |
561 | |
562 // output expression | |
563 lw_expr_testterms(re -> expr, write_code_obj_expraux, of); | |
564 | |
565 // flag end of expressions | |
566 writebytes("", 1, 1, of); | |
567 | |
568 // write the offset | |
569 buf[0] = (offset >> 8) & 0xff; | |
570 buf[1] = offset & 0xff; | |
571 writebytes(buf, 2, 1, of); | |
572 } | |
573 | |
574 // flag end of incomplete references list | |
575 writebytes("", 1, 1, of); | |
576 | |
577 // now blast out the code | |
578 | |
579 // length | |
580 buf[0] = s -> oblen >> 8 & 0xff; | |
581 buf[1] = s -> oblen & 0xff; | |
582 writebytes(buf, 2, 1, of); | |
583 | |
584 if (!(s -> flags & section_flag_bss)) | |
585 { | |
586 writebytes(s -> obytes, s -> oblen, 1, of); | |
587 } | |
588 } | |
589 | |
590 // flag no more sections | |
591 // the "" is NOT an error | |
592 writebytes("", 1, 1, of); | |
593 } |