comparison lwasm/output.c @ 151:427e268e876b

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