comparison old-trunk/lwasm/old/output.c @ 339:eb230fa7d28e

Prepare for migration to hg
author lost
date Fri, 19 Mar 2010 02:54:14 +0000
parents
children
comparison
equal deleted inserted replaced
338:e7885b3ee266 339:eb230fa7d28e
1 /*
2 output.c
3 Copyright © 2009 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 <ctype.h>
25 #include <errno.h>
26 #include <stdio.h>
27 //#include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #define __output_c_seen__
31 //#include "instab.h"
32 #include "lwasm.h"
33 #include "util.h"
34
35 void write_code_raw(asmstate_t *as, FILE *of);
36 void write_code_decb(asmstate_t *as, FILE *of);
37 void write_code_rawrel(asmstate_t *as, FILE *of);
38 void write_code_obj(asmstate_t *as, FILE *of);
39 void write_code_os9(asmstate_t *as, FILE *of);
40
41 // this prevents warnings about not using the return value of fwrite()
42 #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0)
43
44 void lwasm_output(asmstate_t *as)
45 {
46 FILE *of;
47
48 if (as -> errorcount > 0)
49 {
50 fprintf(stderr, "Not doing output due to assembly errors.\n");
51 return;
52 }
53
54 of = fopen(as -> outfile, "wb");
55 if (!of)
56 {
57 fprintf(stderr, "Cannot open '%s' for output", as -> outfile);
58 perror("");
59 return;
60 }
61
62 switch (as -> outformat)
63 {
64 case OUTPUT_RAW:
65 write_code_raw(as, of);
66 break;
67
68 case OUTPUT_DECB:
69 write_code_decb(as, of);
70 break;
71
72 case OUTPUT_RAWREL:
73 write_code_rawrel(as, of);
74 break;
75
76 case OUTPUT_OBJ:
77 write_code_obj(as, of);
78 break;
79
80 case OUTPUT_OS9:
81 write_code_os9(as, of);
82 break;
83
84 default:
85 fprintf(stderr, "BUG: unrecognized output format when generating output file\n");
86 fclose(of);
87 unlink(as -> outfile);
88 return;
89 }
90
91 fclose(of);
92 }
93
94 /*
95 rawrel output treats an ORG directive as an offset from the start of the
96 file. Undefined results will occur if an ORG directive moves the output
97 pointer backward. This particular implementation uses "fseek" to handle
98 ORG requests and to skip over RMBs.
99
100 This simple brain damanged method simply does an fseek before outputting
101 each instruction.
102 */
103 void write_code_rawrel(asmstate_t *as, FILE *of)
104 {
105 lwasm_line_t *cl;
106
107 for (cl = as -> lineshead; cl; cl = cl -> next)
108 {
109 if (cl -> codelen == 0)
110 continue;
111
112 fseek(of, cl -> codeaddr, SEEK_SET);
113 writebytes(cl -> bytes, cl -> codelen, 1, of);
114 }
115 }
116
117 /*
118 raw merely writes all the bytes directly to the file as is. ORG is just a
119 reference for the assembler to handle absolute references. Multiple ORG
120 statements will produce mostly useless results
121 */
122 void write_code_raw(asmstate_t *as, FILE *of)
123 {
124 lwasm_line_t *cl;
125
126 for (cl = as -> lineshead; cl; cl = cl -> next)
127 {
128 if (cl -> nocodelen)
129 {
130 int i;
131 for (i = 0; i < cl -> nocodelen; i++)
132 writebytes("\0", 1, 1, of);
133 continue;
134 }
135 writebytes(cl -> bytes, cl -> codelen, 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 lwasm_line_t *cl;
147
148 for (cl = as -> lineshead; cl; cl = cl -> next)
149 {
150 if (cl -> inmod == 0)
151 continue;
152 if (cl -> nocodelen)
153 {
154 int i;
155 for (i = 0; i < cl -> nocodelen; i++)
156 writebytes("\0", 1, 1, of);
157 continue;
158 }
159 writebytes(cl -> bytes, cl -> codelen, 1, of);
160 }
161 }
162
163 void write_code_decb(asmstate_t *as, FILE *of)
164 {
165 long preambloc;
166 lwasm_line_t *cl;
167 int blocklen = -1;
168 int nextcalc = -1;
169 unsigned char outbuf[5];
170
171 for (cl = as -> lineshead; cl; cl = cl -> next)
172 {
173 if (cl -> nocodelen)
174 continue;
175 if (cl -> codeaddr != nextcalc && cl -> codelen > 0)
176 {
177 // need preamble here
178 if (blocklen > 0)
179 {
180 // update previous preamble if needed
181 fseek(of, preambloc, SEEK_SET);
182 outbuf[0] = (blocklen >> 8) & 0xFF;
183 outbuf[1] = blocklen & 0xFF;
184 writebytes(outbuf, 2, 1, of);
185 fseek(of, 0, SEEK_END);
186 }
187 blocklen = 0;
188 nextcalc = cl -> codeaddr;
189 outbuf[0] = 0x00;
190 outbuf[1] = 0x00;
191 outbuf[2] = 0x00;
192 outbuf[3] = (nextcalc >> 8) & 0xFF;
193 outbuf[4] = nextcalc & 0xFF;
194 preambloc = ftell(of) + 1;
195 writebytes(outbuf, 5, 1, of);
196 }
197 nextcalc += cl -> codelen;
198 writebytes(cl -> bytes, cl -> codelen, 1, of);
199 blocklen += cl -> codelen;
200 }
201 if (blocklen > 0)
202 {
203 fseek(of, preambloc, SEEK_SET);
204 outbuf[0] = (blocklen >> 8) & 0xFF;
205 outbuf[1] = blocklen & 0xFF;
206 writebytes(outbuf, 2, 1, of);
207 fseek(of, 0, SEEK_END);
208 }
209
210 // now write postamble
211 outbuf[0] = 0xFF;
212 outbuf[1] = 0x00;
213 outbuf[2] = 0x00;
214 outbuf[3] = (as -> execaddr >> 8) & 0xFF;
215 outbuf[4] = (as -> execaddr) & 0xFF;
216 writebytes(outbuf, 5, 1, of);
217 }
218
219 void write_code_obj_sbadd(sectiontab_t *s, unsigned char b)
220 {
221 if (s -> oblen >= s -> obsize)
222 {
223 s -> obytes = lwasm_realloc(s -> obytes, s -> obsize + 128);
224 s -> obsize += 128;
225 }
226 s -> obytes[s -> oblen] = b;
227 s -> oblen += 1;
228 }
229
230 void write_code_obj(asmstate_t *as, FILE *of)
231 {
232 lwasm_line_t *l;
233 sectiontab_t *s;
234 lwasm_symbol_ent_t *se;
235 export_list_t *ex;
236 section_reloc_list_t *re;
237 lwasm_expr_stack_node_t *sn;
238
239 int i;
240 unsigned char buf[16];
241
242 // output the magic number and file header
243 // the 8 is NOT an error
244 writebytes("LWOBJ16", 8, 1, of);
245
246 // run through the entire system and build the byte streams for each
247 // section; at the same time, generate a list of "local" symbols to
248 // output for each section
249 // NOTE: for "local" symbols, we will append \x01 and the ascii string
250 // of the context identifier (so sym in context 1 would be "sym\x011"
251 // we can do this because the linker can handle symbols with any
252 // character other than NUL.
253 // also we will generate a list of incomplete references for each
254 // section along with the actual definition that will be output
255
256 // once all this information is generated, we will output each section
257 // to the file
258
259 // NOTE: we build everything in memory then output it because the
260 // assembler accepts multiple instances of the same section but the
261 // linker expects only one instance of each section in the object file
262 // so we need to collect all the various pieces of a section together
263 // (also, the assembler treated multiple instances of the same section
264 // as continuations of previous sections so we would need to collect
265 // them together anyway.
266
267 for (l = as -> lineshead; l; l = l -> next)
268 {
269 if (l -> sect)
270 {
271 // we're in a section - need to output some bytes
272 for (i = 0; i < l -> codelen; i++)
273 write_code_obj_sbadd(l -> sect, l -> bytes[i]);
274 for (i = 0; i < l -> nocodelen; i++)
275 write_code_obj_sbadd(l -> sect, 0);
276
277 // do we have a "relocation"? If so, add a reference to the
278 // relocation table
279 if (l -> relocoff >= 0)
280 {
281 // build the relocation reference for the linker
282 re = lwasm_alloc(sizeof(section_reloc_list_t));
283 re -> next = l -> sect -> rl;
284 l -> sect -> rl = re;
285
286 re -> offset = l -> codeaddr + l -> relocoff;
287 re -> expr = l -> exprs[0];
288 re -> context = l -> context;
289 re -> relocsize = 2;
290 if (l -> reloc8bit)
291 re -> relocsize = 1;
292 }
293 }
294 }
295
296 // run through the sections
297 for (s = as -> sections; s; s = s -> next)
298 {
299 // write the name
300 writebytes(s -> name, strlen(s -> name) + 1, 1, of);
301
302 // write the flags
303 if (s -> flags & SECTION_BSS)
304 writebytes("\x01", 1, 1, of);
305
306 // indicate end of flags - the "" is NOT an error
307 writebytes("", 1, 1, of);
308
309
310 // now the local symbols
311 for (se = as -> symhead; se; se = se -> next)
312 {
313 // ignore symbols not in this section
314 if (se -> sect != s)
315 continue;
316
317 if (se -> flags & SYMBOL_SET)
318 continue;
319
320 if (se -> flags & SYMBOL_EXTERN)
321 continue;
322
323 writebytes(se -> sym, strlen(se -> sym), 1, of);
324 if (se -> context >= 0)
325 {
326 writebytes("\x01", 1, 1, of);
327 sprintf(buf, "%d", se -> context);
328 writebytes(buf, strlen(buf), 1, of);
329 }
330 // the "" is NOT an error
331 writebytes("", 1, 1, of);
332
333 // write the address
334 buf[0] = (se -> value >> 8) & 0xff;
335 buf[1] = se -> value & 0xff;
336 writebytes(buf, 2, 1, of);
337 }
338 // flag end of local symbol table - "" is NOT an error
339 writebytes("", 1, 1, of);
340
341 // now the exports
342 for (ex = s -> exports; ex; ex = ex -> next)
343 {
344 writebytes(ex -> sym, strlen(ex -> sym) + 1, 1, of);
345 buf[0] = (ex -> offset >> 8) & 0xff;
346 buf[1] = ex -> offset & 0xff;
347 writebytes(buf, 2, 1, of);
348 }
349
350 // flag end of exported symbols - "" is NOT an error
351 writebytes("", 1, 1, of);
352
353 // now output the "incomplete references"
354 // this being the most complex bit
355 for (re = s -> rl; re; re = re -> next)
356 {
357 if (re -> expr == NULL)
358 {
359 // this is an error but we'll simply ignore it
360 // and not output this expression
361 continue;
362 }
363
364 // work through each term in the expression and output
365 // the proper equivalent to the object file
366 if (re -> relocsize == 1)
367 {
368 // flag an 8 bit relocation (low 8 bits will be used)
369 buf[0] = 0xFF;
370 buf[1] = 0x01;
371 writebytes(buf, 2, 1, of);
372 }
373 for (sn = re -> expr -> head; sn; sn = sn -> next)
374 {
375 switch (sn -> term -> term_type)
376 {
377 case LWASM_TERM_OPER:
378 buf[0] = 0x04;
379 buf[1] = sn -> term -> value;
380 writebytes(buf, 2, 1, of);
381 break;
382
383 case LWASM_TERM_INT:
384 buf[0] = 0x01;
385 buf[1] = (sn -> term -> value >> 8) & 0xff;
386 buf[2] = sn -> term -> value & 0xff;
387 writebytes(buf, 3, 1, of);
388 break;
389
390 case LWASM_TERM_SECBASE:
391 writebytes("\x05", 1, 1, of);
392 break;
393
394 case LWASM_TERM_SYM:
395 // now for the ugly part - resolve a symbol reference
396 // and determine whether it's internal, external, or
397 // a section base
398 se = lwasm_find_symbol(as, sn -> term -> symbol, re -> context);
399 if (!se)
400 se = lwasm_find_symbol(as, sn -> term -> symbol, -1);
401 if (!se || se -> flags & SYMBOL_EXTERN)
402 {
403 // not found - assume external reference
404 // found but flagged external - handle it
405 writebytes("\x02", 1, 1, of);
406 writebytes(se -> sym, strlen(se -> sym) + 1, 1, of);
407 break;
408 }
409 // a local symbol reference here
410 writebytes("\x03", 1, 1, of);
411 writebytes(se -> sym, strlen(se -> sym), 1, of);
412 if (se -> context >= 0)
413 {
414 writebytes("\x01", 1, 1, of);
415 sprintf(buf, "%d", se -> context);
416 writebytes(buf, strlen(buf), 1, of);
417 }
418 writebytes("", 1, 1, of);
419 break;
420
421 default:
422 // unrecognized term type - replace with integer 0
423 buf[0] = 0x01;
424 buf[1] = 0x00;
425 buf[2] = 0x00;
426 writebytes(buf, 3, 1, of);
427 break;
428 }
429 }
430
431 // flag end of expressions
432 writebytes("", 1, 1, of);
433
434 // write the offset
435 buf[0] = (re -> offset >> 8) & 0xff;
436 buf[1] = re -> offset & 0xff;
437 writebytes(buf, 2, 1, of);
438 }
439 // flag end of incomplete references list
440 writebytes("", 1, 1, of);
441
442 // now blast out the code
443
444 // length
445 buf[0] = s -> oblen >> 8 & 0xff;
446 buf[1] = s -> oblen & 0xff;
447 writebytes(buf, 2, 1, of);
448
449 if (!(s -> flags & SECTION_BSS))
450 {
451 writebytes(s -> obytes, s -> oblen, 1, of);
452 }
453 }
454
455 // flag no more sections
456 // the "" is NOT an error
457 writebytes("", 1, 1, of);
458 }