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
|
|
233 void write_code_obj(asmstate_t *as, FILE *of)
|
|
234 {
|
374
|
235 line_t *l;
|
339
|
236 sectiontab_t *s;
|
374
|
237 reloctab_t *re;
|
375
|
238 exportlist_t *ex;
|
374
|
239 struct symtabe *se;
|
|
240
|
339
|
241 int i;
|
|
242 unsigned char buf[16];
|
|
243
|
|
244 // output the magic number and file header
|
|
245 // the 8 is NOT an error
|
|
246 writebytes("LWOBJ16", 8, 1, of);
|
|
247
|
|
248 // run through the entire system and build the byte streams for each
|
|
249 // section; at the same time, generate a list of "local" symbols to
|
|
250 // output for each section
|
|
251 // NOTE: for "local" symbols, we will append \x01 and the ascii string
|
|
252 // of the context identifier (so sym in context 1 would be "sym\x011"
|
|
253 // we can do this because the linker can handle symbols with any
|
|
254 // character other than NUL.
|
|
255 // also we will generate a list of incomplete references for each
|
|
256 // section along with the actual definition that will be output
|
|
257
|
|
258 // once all this information is generated, we will output each section
|
|
259 // to the file
|
|
260
|
|
261 // NOTE: we build everything in memory then output it because the
|
|
262 // assembler accepts multiple instances of the same section but the
|
|
263 // linker expects only one instance of each section in the object file
|
|
264 // so we need to collect all the various pieces of a section together
|
|
265 // (also, the assembler treated multiple instances of the same section
|
|
266 // as continuations of previous sections so we would need to collect
|
|
267 // them together anyway.
|
|
268
|
374
|
269 for (l = as -> line_head; l; l = l -> next)
|
339
|
270 {
|
374
|
271 if (l -> csect)
|
339
|
272 {
|
|
273 // we're in a section - need to output some bytes
|
374
|
274 if (l -> outputl > 0)
|
|
275 for (i = 0; i < l -> outputl; i++)
|
|
276 write_code_obj_sbadd(l -> csect, l -> output[i]);
|
|
277 else if (l -> outputl == 0)
|
|
278 for (i = 0; i < l -> len; i++)
|
|
279 write_code_obj_sbadd(l -> csect, 0);
|
339
|
280 }
|
|
281 }
|
|
282
|
|
283 // run through the sections
|
|
284 for (s = as -> sections; s; s = s -> next)
|
|
285 {
|
|
286 // write the name
|
|
287 writebytes(s -> name, strlen(s -> name) + 1, 1, of);
|
|
288
|
|
289 // write the flags
|
374
|
290 if (s -> flags & section_flag_bss)
|
339
|
291 writebytes("\x01", 1, 1, of);
|
|
292
|
|
293 // indicate end of flags - the "" is NOT an error
|
|
294 writebytes("", 1, 1, of);
|
|
295
|
|
296 // now the local symbols
|
374
|
297 for (se = as -> symtab.head; se; se = se -> next)
|
339
|
298 {
|
|
299 // ignore symbols not in this section
|
374
|
300 if (se -> section != s)
|
339
|
301 continue;
|
|
302
|
374
|
303 if (se -> flags & symbol_flag_set)
|
339
|
304 continue;
|
|
305
|
374
|
306 // don't output non-constant symbols
|
|
307 if (!lw_expr_istype(se -> value, lw_expr_type_int))
|
339
|
308 continue;
|
374
|
309
|
|
310 writebytes(se -> symbol, strlen(se -> symbol), 1, of);
|
339
|
311 if (se -> context >= 0)
|
|
312 {
|
|
313 writebytes("\x01", 1, 1, of);
|
|
314 sprintf(buf, "%d", se -> context);
|
|
315 writebytes(buf, strlen(buf), 1, of);
|
|
316 }
|
|
317 // the "" is NOT an error
|
|
318 writebytes("", 1, 1, of);
|
|
319
|
|
320 // write the address
|
374
|
321 buf[0] = (lw_expr_intval(se -> value) >> 8) & 0xff;
|
|
322 buf[1] = lw_expr_intval(se -> value) & 0xff;
|
339
|
323 writebytes(buf, 2, 1, of);
|
|
324 }
|
|
325 // flag end of local symbol table - "" is NOT an error
|
|
326 writebytes("", 1, 1, of);
|
|
327
|
374
|
328 // now the exports -- FIXME
|
375
|
329 for (ex = as -> exportlist; ex; ex = ex -> next)
|
339
|
330 {
|
374
|
331 int eval;
|
375
|
332 lw_expr_t te;
|
|
333 line_t tl;
|
|
334
|
|
335 if (ex -> se -> section != s)
|
374
|
336 continue;
|
375
|
337 te = lw_expr_copy(ex -> se -> value);
|
|
338 as -> csect = ex -> se -> section;
|
|
339 as -> exportcheck = 1;
|
|
340 tl.as = as;
|
|
341 as -> cl = &tl;
|
|
342 lwasm_reduce_expr(as, te);
|
|
343 as -> exportcheck = 0;
|
|
344 as -> cl = NULL;
|
|
345 if (!lw_expr_istype(te, lw_expr_type_int))
|
|
346 {
|
|
347 lw_expr_destroy(te);
|
374
|
348 continue;
|
375
|
349 }
|
|
350 eval = lw_expr_intval(te);
|
|
351 lw_expr_destroy(te);
|
374
|
352 writebytes(ex -> symbol, strlen(ex -> symbol) + 1, 1, of);
|
|
353 buf[0] = (eval >> 8) & 0xff;
|
|
354 buf[1] = eval & 0xff;
|
339
|
355 writebytes(buf, 2, 1, of);
|
|
356 }
|
375
|
357
|
339
|
358 // flag end of exported symbols - "" is NOT an error
|
|
359 writebytes("", 1, 1, of);
|
|
360
|
374
|
361 // FIXME - relocation table
|
|
362 /* for (re = s -> rl; re; re = re -> next)
|
339
|
363 {
|
|
364 if (re -> expr == NULL)
|
|
365 {
|
|
366 // this is an error but we'll simply ignore it
|
|
367 // and not output this expression
|
|
368 continue;
|
|
369 }
|
|
370
|
|
371 // work through each term in the expression and output
|
|
372 // the proper equivalent to the object file
|
|
373 if (re -> relocsize == 1)
|
|
374 {
|
|
375 // flag an 8 bit relocation (low 8 bits will be used)
|
|
376 buf[0] = 0xFF;
|
|
377 buf[1] = 0x01;
|
|
378 writebytes(buf, 2, 1, of);
|
|
379 }
|
|
380 for (sn = re -> expr -> head; sn; sn = sn -> next)
|
|
381 {
|
|
382 switch (sn -> term -> term_type)
|
|
383 {
|
|
384 case LWASM_TERM_OPER:
|
|
385 buf[0] = 0x04;
|
|
386 buf[1] = sn -> term -> value;
|
|
387 writebytes(buf, 2, 1, of);
|
|
388 break;
|
|
389
|
|
390 case LWASM_TERM_INT:
|
|
391 buf[0] = 0x01;
|
|
392 buf[1] = (sn -> term -> value >> 8) & 0xff;
|
|
393 buf[2] = sn -> term -> value & 0xff;
|
|
394 writebytes(buf, 3, 1, of);
|
|
395 break;
|
|
396
|
|
397 case LWASM_TERM_SECBASE:
|
|
398 writebytes("\x05", 1, 1, of);
|
|
399 break;
|
|
400
|
|
401 case LWASM_TERM_SYM:
|
|
402 // now for the ugly part - resolve a symbol reference
|
|
403 // and determine whether it's internal, external, or
|
|
404 // a section base
|
|
405 se = lwasm_find_symbol(as, sn -> term -> symbol, re -> context);
|
|
406 if (!se)
|
|
407 se = lwasm_find_symbol(as, sn -> term -> symbol, -1);
|
|
408 if (!se || se -> flags & SYMBOL_EXTERN)
|
|
409 {
|
|
410 // not found - assume external reference
|
|
411 // found but flagged external - handle it
|
|
412 writebytes("\x02", 1, 1, of);
|
|
413 writebytes(se -> sym, strlen(se -> sym) + 1, 1, of);
|
|
414 break;
|
|
415 }
|
|
416 // a local symbol reference here
|
|
417 writebytes("\x03", 1, 1, of);
|
|
418 writebytes(se -> sym, strlen(se -> sym), 1, of);
|
|
419 if (se -> context >= 0)
|
|
420 {
|
|
421 writebytes("\x01", 1, 1, of);
|
|
422 sprintf(buf, "%d", se -> context);
|
|
423 writebytes(buf, strlen(buf), 1, of);
|
|
424 }
|
|
425 writebytes("", 1, 1, of);
|
|
426 break;
|
|
427
|
|
428 default:
|
|
429 // unrecognized term type - replace with integer 0
|
|
430 buf[0] = 0x01;
|
|
431 buf[1] = 0x00;
|
|
432 buf[2] = 0x00;
|
|
433 writebytes(buf, 3, 1, of);
|
|
434 break;
|
|
435 }
|
|
436 }
|
|
437
|
|
438 // flag end of expressions
|
|
439 writebytes("", 1, 1, of);
|
|
440
|
|
441 // write the offset
|
|
442 buf[0] = (re -> offset >> 8) & 0xff;
|
|
443 buf[1] = re -> offset & 0xff;
|
|
444 writebytes(buf, 2, 1, of);
|
|
445 }
|
374
|
446 */
|
339
|
447 // flag end of incomplete references list
|
|
448 writebytes("", 1, 1, of);
|
|
449
|
|
450 // now blast out the code
|
|
451
|
|
452 // length
|
|
453 buf[0] = s -> oblen >> 8 & 0xff;
|
|
454 buf[1] = s -> oblen & 0xff;
|
|
455 writebytes(buf, 2, 1, of);
|
|
456
|
374
|
457 if (!(s -> flags & section_flag_bss))
|
339
|
458 {
|
|
459 writebytes(s -> obytes, s -> oblen, 1, of);
|
|
460 }
|
|
461 }
|
|
462
|
|
463 // flag no more sections
|
|
464 // the "" is NOT an error
|
|
465 writebytes("", 1, 1, of);
|
|
466 }
|