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