comparison lwasm/output.c @ 374:d99322ef6f21

Stage 1: actually do output
author lost@starbug
date Sat, 24 Apr 2010 14:15:18 -0600
parents old-trunk/lwasm/old/output.c@eb230fa7d28e
children 3498b2d88376
comparison
equal deleted inserted replaced
373:8f9d72cfb897 374:d99322ef6f21
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 <config.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include <lw_alloc.h>
30 #include <lw_expr.h>
31
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
43 void do_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 -> output_file, "wb");
54 if (!of)
55 {
56 fprintf(stderr, "Cannot open '%s' for output", as -> output_file);
57 perror("");
58 return;
59 }
60
61 switch (as -> output_format)
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);
86 unlink(as -> output_file);
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 {
104 line_t *cl;
105
106 for (cl = as -> line_head; cl; cl = cl -> next)
107 {
108 if (cl -> outputl <= 0)
109 continue;
110
111 fseek(of, lw_expr_intval(cl -> addr), SEEK_SET);
112 writebytes(cl -> output, cl -> outputl, 1, of);
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 {
123 line_t *cl;
124
125 for (cl = as -> line_head; cl; cl = cl -> next)
126 {
127 if (cl -> len > 0 && cl -> outputl == 0)
128 {
129 int i;
130 for (i = 0; i < cl -> len; i++)
131 writebytes("\0", 1, 1, of);
132 continue;
133 }
134 else if (cl -> outputl > 0)
135 writebytes(cl -> output, cl -> outputl, 1, of);
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 {
146 line_t *cl;
147
148 for (cl = as -> line_head; cl; cl = cl -> next)
149 {
150 if (cl -> inmod == 0)
151 continue;
152 if (cl -> len > 0 && cl -> outputl == 0)
153 {
154 int i;
155 for (i = 0; i < cl -> len; i++)
156 writebytes("\0", 1, 1, of);
157 continue;
158 }
159 else if (cl -> outputl > 0)
160 writebytes(cl -> output, cl -> outputl, 1, of);
161 }
162 }
163
164 void write_code_decb(asmstate_t *as, FILE *of)
165 {
166 long preambloc;
167 line_t *cl;
168 int blocklen = -1;
169 int nextcalc = -1;
170 unsigned char outbuf[5];
171 int caddr;
172
173 for (cl = as -> line_head; cl; cl = cl -> next)
174 {
175 if (cl -> outputl < 0)
176 continue;
177 caddr = lw_expr_intval(cl -> addr);
178 if (caddr != nextcalc && cl -> outputl > 0)
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;
191 nextcalc = caddr;
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 }
200 nextcalc += cl -> outputl;
201 writebytes(cl -> output, cl -> outputl, 1, of);
202 blocklen += cl -> outputl;
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 {
226 s -> obytes = lw_realloc(s -> obytes, s -> obsize + 128);
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 {
235 line_t *l;
236 sectiontab_t *s;
237 reloctab_t *re;
238 struct symtabe *se;
239
240 int i;
241 unsigned char buf[16];
242
243 // output the magic number and file header
244 // the 8 is NOT an error
245 writebytes("LWOBJ16", 8, 1, of);
246
247 // run through the entire system and build the byte streams for each
248 // section; at the same time, generate a list of "local" symbols to
249 // output for each section
250 // NOTE: for "local" symbols, we will append \x01 and the ascii string
251 // of the context identifier (so sym in context 1 would be "sym\x011"
252 // we can do this because the linker can handle symbols with any
253 // character other than NUL.
254 // also we will generate a list of incomplete references for each
255 // section along with the actual definition that will be output
256
257 // once all this information is generated, we will output each section
258 // to the file
259
260 // NOTE: we build everything in memory then output it because the
261 // assembler accepts multiple instances of the same section but the
262 // linker expects only one instance of each section in the object file
263 // so we need to collect all the various pieces of a section together
264 // (also, the assembler treated multiple instances of the same section
265 // as continuations of previous sections so we would need to collect
266 // them together anyway.
267
268 for (l = as -> line_head; l; l = l -> next)
269 {
270 if (l -> csect)
271 {
272 // we're in a section - need to output some bytes
273 if (l -> outputl > 0)
274 for (i = 0; i < l -> outputl; i++)
275 write_code_obj_sbadd(l -> csect, l -> output[i]);
276 else if (l -> outputl == 0)
277 for (i = 0; i < l -> len; i++)
278 write_code_obj_sbadd(l -> csect, 0);
279 }
280 }
281
282 // run through the sections
283 for (s = as -> sections; s; s = s -> next)
284 {
285 // write the name
286 writebytes(s -> name, strlen(s -> name) + 1, 1, of);
287
288 // write the flags
289 if (s -> flags & section_flag_bss)
290 writebytes("\x01", 1, 1, of);
291
292 // indicate end of flags - the "" is NOT an error
293 writebytes("", 1, 1, of);
294
295 // now the local symbols
296 for (se = as -> symtab.head; se; se = se -> next)
297 {
298 // ignore symbols not in this section
299 if (se -> section != s)
300 continue;
301
302 if (se -> flags & symbol_flag_set)
303 continue;
304
305 // don't output non-constant symbols
306 if (!lw_expr_istype(se -> value, lw_expr_type_int))
307 continue;
308
309 writebytes(se -> symbol, strlen(se -> symbol), 1, of);
310 if (se -> context >= 0)
311 {
312 writebytes("\x01", 1, 1, of);
313 sprintf(buf, "%d", se -> context);
314 writebytes(buf, strlen(buf), 1, of);
315 }
316 // the "" is NOT an error
317 writebytes("", 1, 1, of);
318
319 // write the address
320 buf[0] = (lw_expr_intval(se -> value) >> 8) & 0xff;
321 buf[1] = lw_expr_intval(se -> value) & 0xff;
322 writebytes(buf, 2, 1, of);
323 }
324 // flag end of local symbol table - "" is NOT an error
325 writebytes("", 1, 1, of);
326
327 // now the exports -- FIXME
328 /* for (ex = as -> exportlist; ex; ex = ex -> next)
329 {
330 int eval;
331 ex -> se -> section != s)
332 continue;
333 if (!lwasm_expr_exportable(ex -> se -> value))
334 continue;
335 eval = lwasm_expr_exportval(ex -> se -> value);
336 writebytes(ex -> symbol, strlen(ex -> symbol) + 1, 1, of);
337 buf[0] = (eval >> 8) & 0xff;
338 buf[1] = eval & 0xff;
339 writebytes(buf, 2, 1, of);
340 }
341 */
342 // flag end of exported symbols - "" is NOT an error
343 writebytes("", 1, 1, of);
344
345 // FIXME - relocation table
346 /* for (re = s -> rl; re; re = re -> next)
347 {
348 if (re -> expr == NULL)
349 {
350 // this is an error but we'll simply ignore it
351 // and not output this expression
352 continue;
353 }
354
355 // work through each term in the expression and output
356 // the proper equivalent to the object file
357 if (re -> relocsize == 1)
358 {
359 // flag an 8 bit relocation (low 8 bits will be used)
360 buf[0] = 0xFF;
361 buf[1] = 0x01;
362 writebytes(buf, 2, 1, of);
363 }
364 for (sn = re -> expr -> head; sn; sn = sn -> next)
365 {
366 switch (sn -> term -> term_type)
367 {
368 case LWASM_TERM_OPER:
369 buf[0] = 0x04;
370 buf[1] = sn -> term -> value;
371 writebytes(buf, 2, 1, of);
372 break;
373
374 case LWASM_TERM_INT:
375 buf[0] = 0x01;
376 buf[1] = (sn -> term -> value >> 8) & 0xff;
377 buf[2] = sn -> term -> value & 0xff;
378 writebytes(buf, 3, 1, of);
379 break;
380
381 case LWASM_TERM_SECBASE:
382 writebytes("\x05", 1, 1, of);
383 break;
384
385 case LWASM_TERM_SYM:
386 // now for the ugly part - resolve a symbol reference
387 // and determine whether it's internal, external, or
388 // a section base
389 se = lwasm_find_symbol(as, sn -> term -> symbol, re -> context);
390 if (!se)
391 se = lwasm_find_symbol(as, sn -> term -> symbol, -1);
392 if (!se || se -> flags & SYMBOL_EXTERN)
393 {
394 // not found - assume external reference
395 // found but flagged external - handle it
396 writebytes("\x02", 1, 1, of);
397 writebytes(se -> sym, strlen(se -> sym) + 1, 1, of);
398 break;
399 }
400 // a local symbol reference here
401 writebytes("\x03", 1, 1, of);
402 writebytes(se -> sym, strlen(se -> sym), 1, of);
403 if (se -> context >= 0)
404 {
405 writebytes("\x01", 1, 1, of);
406 sprintf(buf, "%d", se -> context);
407 writebytes(buf, strlen(buf), 1, of);
408 }
409 writebytes("", 1, 1, of);
410 break;
411
412 default:
413 // unrecognized term type - replace with integer 0
414 buf[0] = 0x01;
415 buf[1] = 0x00;
416 buf[2] = 0x00;
417 writebytes(buf, 3, 1, of);
418 break;
419 }
420 }
421
422 // flag end of expressions
423 writebytes("", 1, 1, of);
424
425 // write the offset
426 buf[0] = (re -> offset >> 8) & 0xff;
427 buf[1] = re -> offset & 0xff;
428 writebytes(buf, 2, 1, of);
429 }
430 */
431 // flag end of incomplete references list
432 writebytes("", 1, 1, of);
433
434 // now blast out the code
435
436 // length
437 buf[0] = s -> oblen >> 8 & 0xff;
438 buf[1] = s -> oblen & 0xff;
439 writebytes(buf, 2, 1, of);
440
441 if (!(s -> flags & section_flag_bss))
442 {
443 writebytes(s -> obytes, s -> oblen, 1, of);
444 }
445 }
446
447 // flag no more sections
448 // the "" is NOT an error
449 writebytes("", 1, 1, of);
450 }