Mercurial > hg-old > index.cgi
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 } |