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:
|
|
319 writebytes("\x05", 1, 1, of);
|
|
320 break;
|
|
321
|
|
322 case lwasm_expr_import:
|
|
323 {
|
|
324 importlist_t *ie;
|
|
325 ie = lw_expr_specptr(e);
|
|
326 buf[0] = 0x02;
|
|
327 writebytes(buf, 1, 1, of);
|
|
328 writebytes(ie -> symbol, strlen(ie -> symbol) + 1, 1, of);
|
|
329 break;
|
|
330 }
|
|
331 case lwasm_expr_syment:
|
|
332 {
|
|
333 struct symtabe *se;
|
|
334 se = lw_expr_specptr(e);
|
|
335 buf[0] = 0x03;
|
|
336 writebytes(buf, 1, 1, of);
|
|
337 writebytes(se -> symbol, strlen(se -> symbol), 1, of);
|
|
338 if (se -> context != -1)
|
|
339 {
|
|
340 sprintf(buf, "\x01%d", se -> context);
|
|
341 writebytes(buf, strlen(buf), 1, of);
|
|
342 }
|
|
343 writebytes("", 1, 1, of);
|
|
344 break;
|
|
345 }
|
|
346 break;
|
|
347 }
|
|
348
|
|
349 default:
|
|
350 // unrecognized term type - replace with integer 0
|
|
351 buf[0] = 0x01;
|
|
352 buf[1] = 0x00;
|
|
353 buf[2] = 0x00;
|
|
354 writebytes(buf, 3, 1, of);
|
|
355 break;
|
|
356 }
|
|
357 return 0;
|
|
358 }
|
|
359
|
|
360
|
339
|
361 void write_code_obj(asmstate_t *as, FILE *of)
|
|
362 {
|
374
|
363 line_t *l;
|
339
|
364 sectiontab_t *s;
|
374
|
365 reloctab_t *re;
|
375
|
366 exportlist_t *ex;
|
374
|
367 struct symtabe *se;
|
|
368
|
339
|
369 int i;
|
|
370 unsigned char buf[16];
|
|
371
|
|
372 // output the magic number and file header
|
|
373 // the 8 is NOT an error
|
|
374 writebytes("LWOBJ16", 8, 1, of);
|
|
375
|
|
376 // run through the entire system and build the byte streams for each
|
|
377 // section; at the same time, generate a list of "local" symbols to
|
|
378 // output for each section
|
|
379 // NOTE: for "local" symbols, we will append \x01 and the ascii string
|
|
380 // of the context identifier (so sym in context 1 would be "sym\x011"
|
|
381 // we can do this because the linker can handle symbols with any
|
|
382 // character other than NUL.
|
|
383 // also we will generate a list of incomplete references for each
|
|
384 // section along with the actual definition that will be output
|
|
385
|
|
386 // once all this information is generated, we will output each section
|
|
387 // to the file
|
|
388
|
|
389 // NOTE: we build everything in memory then output it because the
|
|
390 // assembler accepts multiple instances of the same section but the
|
|
391 // linker expects only one instance of each section in the object file
|
|
392 // so we need to collect all the various pieces of a section together
|
|
393 // (also, the assembler treated multiple instances of the same section
|
|
394 // as continuations of previous sections so we would need to collect
|
|
395 // them together anyway.
|
|
396
|
374
|
397 for (l = as -> line_head; l; l = l -> next)
|
339
|
398 {
|
374
|
399 if (l -> csect)
|
339
|
400 {
|
|
401 // we're in a section - need to output some bytes
|
374
|
402 if (l -> outputl > 0)
|
|
403 for (i = 0; i < l -> outputl; i++)
|
|
404 write_code_obj_sbadd(l -> csect, l -> output[i]);
|
|
405 else if (l -> outputl == 0)
|
|
406 for (i = 0; i < l -> len; i++)
|
|
407 write_code_obj_sbadd(l -> csect, 0);
|
339
|
408 }
|
|
409 }
|
|
410
|
|
411 // run through the sections
|
|
412 for (s = as -> sections; s; s = s -> next)
|
|
413 {
|
|
414 // write the name
|
|
415 writebytes(s -> name, strlen(s -> name) + 1, 1, of);
|
|
416
|
|
417 // write the flags
|
374
|
418 if (s -> flags & section_flag_bss)
|
339
|
419 writebytes("\x01", 1, 1, of);
|
|
420
|
|
421 // indicate end of flags - the "" is NOT an error
|
|
422 writebytes("", 1, 1, of);
|
|
423
|
|
424 // now the local symbols
|
374
|
425 for (se = as -> symtab.head; se; se = se -> next)
|
339
|
426 {
|
|
427 // ignore symbols not in this section
|
374
|
428 if (se -> section != s)
|
339
|
429 continue;
|
|
430
|
374
|
431 if (se -> flags & symbol_flag_set)
|
339
|
432 continue;
|
|
433
|
374
|
434 // don't output non-constant symbols
|
|
435 if (!lw_expr_istype(se -> value, lw_expr_type_int))
|
339
|
436 continue;
|
374
|
437
|
|
438 writebytes(se -> symbol, strlen(se -> symbol), 1, of);
|
339
|
439 if (se -> context >= 0)
|
|
440 {
|
|
441 writebytes("\x01", 1, 1, of);
|
|
442 sprintf(buf, "%d", se -> context);
|
|
443 writebytes(buf, strlen(buf), 1, of);
|
|
444 }
|
|
445 // the "" is NOT an error
|
|
446 writebytes("", 1, 1, of);
|
|
447
|
|
448 // write the address
|
374
|
449 buf[0] = (lw_expr_intval(se -> value) >> 8) & 0xff;
|
|
450 buf[1] = lw_expr_intval(se -> value) & 0xff;
|
339
|
451 writebytes(buf, 2, 1, of);
|
|
452 }
|
|
453 // flag end of local symbol table - "" is NOT an error
|
|
454 writebytes("", 1, 1, of);
|
|
455
|
374
|
456 // now the exports -- FIXME
|
375
|
457 for (ex = as -> exportlist; ex; ex = ex -> next)
|
339
|
458 {
|
374
|
459 int eval;
|
375
|
460 lw_expr_t te;
|
|
461 line_t tl;
|
|
462
|
|
463 if (ex -> se -> section != s)
|
374
|
464 continue;
|
375
|
465 te = lw_expr_copy(ex -> se -> value);
|
|
466 as -> csect = ex -> se -> section;
|
|
467 as -> exportcheck = 1;
|
|
468 tl.as = as;
|
|
469 as -> cl = &tl;
|
|
470 lwasm_reduce_expr(as, te);
|
|
471 as -> exportcheck = 0;
|
|
472 as -> cl = NULL;
|
|
473 if (!lw_expr_istype(te, lw_expr_type_int))
|
|
474 {
|
|
475 lw_expr_destroy(te);
|
374
|
476 continue;
|
375
|
477 }
|
|
478 eval = lw_expr_intval(te);
|
|
479 lw_expr_destroy(te);
|
374
|
480 writebytes(ex -> symbol, strlen(ex -> symbol) + 1, 1, of);
|
|
481 buf[0] = (eval >> 8) & 0xff;
|
|
482 buf[1] = eval & 0xff;
|
339
|
483 writebytes(buf, 2, 1, of);
|
|
484 }
|
375
|
485
|
339
|
486 // flag end of exported symbols - "" is NOT an error
|
|
487 writebytes("", 1, 1, of);
|
|
488
|
374
|
489 // FIXME - relocation table
|
376
|
490 for (re = s -> reloctab; re; re = re -> next)
|
339
|
491 {
|
376
|
492 int offset;
|
|
493 lw_expr_t te;
|
|
494 line_t tl;
|
|
495
|
|
496 tl.as = as;
|
|
497 as -> cl = &tl;
|
|
498 as -> csect = s;
|
|
499 as -> exportcheck = 1;
|
|
500
|
339
|
501 if (re -> expr == NULL)
|
|
502 {
|
|
503 // this is an error but we'll simply ignore it
|
|
504 // and not output this expression
|
|
505 continue;
|
|
506 }
|
|
507
|
|
508 // work through each term in the expression and output
|
|
509 // the proper equivalent to the object file
|
376
|
510 if (re -> size == 1)
|
339
|
511 {
|
|
512 // flag an 8 bit relocation (low 8 bits will be used)
|
|
513 buf[0] = 0xFF;
|
|
514 buf[1] = 0x01;
|
|
515 writebytes(buf, 2, 1, of);
|
|
516 }
|
376
|
517
|
|
518 te = lw_expr_copy(ex -> se -> value);
|
|
519 lwasm_reduce_expr(as, te);
|
|
520 if (!lw_expr_istype(te, lw_expr_type_int))
|
339
|
521 {
|
376
|
522 lw_expr_destroy(te);
|
|
523 continue;
|
339
|
524 }
|
376
|
525 offset = lw_expr_intval(te);
|
|
526 lw_expr_destroy(te);
|
|
527
|
|
528 // output expression
|
|
529 lw_expr_testterms(re -> expr, write_code_obj_expraux, of);
|
339
|
530
|
|
531 // flag end of expressions
|
|
532 writebytes("", 1, 1, of);
|
|
533
|
|
534 // write the offset
|
376
|
535 buf[0] = (offset >> 8) & 0xff;
|
|
536 buf[1] = offset & 0xff;
|
339
|
537 writebytes(buf, 2, 1, of);
|
|
538 }
|
376
|
539
|
339
|
540 // flag end of incomplete references list
|
|
541 writebytes("", 1, 1, of);
|
|
542
|
|
543 // now blast out the code
|
|
544
|
|
545 // length
|
|
546 buf[0] = s -> oblen >> 8 & 0xff;
|
|
547 buf[1] = s -> oblen & 0xff;
|
|
548 writebytes(buf, 2, 1, of);
|
|
549
|
374
|
550 if (!(s -> flags & section_flag_bss))
|
339
|
551 {
|
|
552 writebytes(s -> obytes, s -> oblen, 1, of);
|
|
553 }
|
|
554 }
|
|
555
|
|
556 // flag no more sections
|
|
557 // the "" is NOT an error
|
|
558 writebytes("", 1, 1, of);
|
|
559 }
|