NASM 0.94
[platform/upstream/nasm.git] / outaout.c
1 /* outaout.c    output routines for the Netwide Assembler to produce
2  *              Linux a.out object files
3  *
4  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
5  * Julian Hall. All rights reserved. The software is
6  * redistributable under the licence given in the file "Licence"
7  * distributed in the NASM archive.
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14
15 #include "nasm.h"
16 #include "nasmlib.h"
17 #include "outform.h"
18
19 #ifdef OF_AOUT
20
21 struct Reloc {
22     struct Reloc *next;
23     long address;                      /* relative to _start_ of section */
24     long symbol;                       /* symbol number or -ve section id */
25     int bytes;                         /* 2 or 4 */
26     int relative;                      /* TRUE or FALSE */
27 };
28
29 struct Symbol {
30     long strpos;                       /* string table position of name */
31     int type;                          /* symbol type - see flags below */
32     long value;                        /* address, or COMMON variable size */
33 };
34
35 /*
36  * Section IDs - used in Reloc.symbol when negative, and in
37  * Symbol.type when positive.
38  */
39 #define SECT_ABS 2                     /* absolute value */
40 #define SECT_TEXT 4                    /* text section */
41 #define SECT_DATA 6                    /* data section */
42 #define SECT_BSS 8                     /* bss section */
43 #define SECT_MASK 0xE                  /* mask out any of the above */
44
45 /*
46  * Another flag used in Symbol.type.
47  */
48 #define SYM_GLOBAL 1                   /* it's a global symbol */
49
50 /*
51  * Bit more explanation of symbol types: SECT_xxx denotes a local
52  * symbol. SECT_xxx|SYM_GLOBAL denotes a global symbol, defined in
53  * this module. Just SYM_GLOBAL, with zero value, denotes an
54  * external symbol referenced in this module. And just SYM_GLOBAL,
55  * but with a non-zero value, declares a C `common' variable, of
56  * size `value'.
57  */
58
59 struct Section {
60     struct SAA *data;
61     unsigned long len, size, nrelocs;
62     long index;
63     struct Reloc *head, **tail;
64 };
65
66 static struct Section stext, sdata;
67 static unsigned long bsslen;
68 static long bssindex;
69
70 static struct SAA *syms;
71 static unsigned long nsyms;
72
73 static struct RAA *bsym;
74
75 static struct SAA *strs;
76 static unsigned long strslen;
77
78 static FILE *aoutfp;
79 static efunc error;
80
81 static void aout_write(void);
82 static void aout_write_relocs(struct Reloc *);
83 static void aout_write_syms(void);
84 static void aout_sect_write(struct Section *, unsigned char *, unsigned long);
85 static void aout_pad_sections(void);
86 static void aout_fixup_relocs(struct Section *);
87
88 static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef) {
89     aoutfp = fp;
90     error = errfunc;
91     (void) ldef;                       /* placate optimisers */
92     stext.data = saa_init(1L); stext.head = NULL; stext.tail = &stext.head;
93     sdata.data = saa_init(1L); sdata.head = NULL; sdata.tail = &sdata.head;
94     stext.len = stext.size = sdata.len = sdata.size = bsslen = 0;
95     stext.nrelocs = sdata.nrelocs = 0;
96     stext.index = seg_alloc();
97     sdata.index = seg_alloc();
98     bssindex = seg_alloc();
99     syms = saa_init((long)sizeof(struct Symbol));
100     nsyms = 0;
101     bsym = raa_init();
102     strs = saa_init(1L);
103     strslen = 0;
104 }
105
106 static void aout_cleanup(void) {
107     struct Reloc *r;
108
109     aout_pad_sections();
110     aout_fixup_relocs(&stext);
111     aout_fixup_relocs(&sdata);
112     aout_write();
113     fclose (aoutfp);
114     saa_free (stext.data);
115     while (stext.head) {
116         r = stext.head;
117         stext.head = stext.head->next;
118         nasm_free (r);
119     }
120     saa_free (sdata.data);
121     while (sdata.head) {
122         r = sdata.head;
123         sdata.head = sdata.head->next;
124         nasm_free (r);
125     }
126     saa_free (syms);
127     raa_free (bsym);
128     saa_free (strs);
129 }
130
131 static long aout_section_names (char *name, int pass, int *bits) {
132     /*
133      * Default to 32 bits.
134      */
135     if (!name)
136         *bits = 32;
137
138     if (!name)
139         return stext.index;
140
141     if (!strcmp(name, ".text"))
142         return stext.index;
143     else if (!strcmp(name, ".data"))
144         return sdata.index;
145     else if (!strcmp(name, ".bss"))
146         return bssindex;
147     else
148         return NO_SEG;
149 }
150
151 static void aout_deflabel (char *name, long segment, long offset,
152                            int is_global) {
153     int pos = strslen+4;
154     struct Symbol *sym;
155
156     if (name[0] == '.' && name[1] == '.') {
157         return;
158     }
159
160     saa_wbytes (strs, name, (long)(1+strlen(name)));
161     strslen += 1+strlen(name);
162
163     sym = saa_wstruct (syms);
164
165     sym->strpos = pos;
166     sym->type = is_global ? SYM_GLOBAL : 0;
167     if (segment == NO_SEG)
168         sym->type |= SECT_ABS;
169     else if (segment == stext.index)
170         sym->type |= SECT_TEXT;
171     else if (segment == sdata.index)
172         sym->type |= SECT_DATA;
173     else if (segment == bssindex)
174         sym->type |= SECT_BSS;
175     else
176         sym->type = SYM_GLOBAL;
177     if (is_global == 2)
178         sym->value = offset;
179     else
180         sym->value = (sym->type == SYM_GLOBAL ? 0 : offset);
181
182     /*
183      * define the references from external-symbol segment numbers
184      * to these symbol records.
185      */
186     if (segment != NO_SEG && segment != stext.index &&
187         segment != sdata.index && segment != bssindex)
188         bsym = raa_write (bsym, segment, nsyms);
189
190     nsyms++;
191 }
192
193 static void aout_add_reloc (struct Section *sect, long segment,
194                             int relative, int bytes) {
195     struct Reloc *r;
196
197     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
198     sect->tail = &r->next;
199     r->next = NULL;
200
201     r->address = sect->len;
202     r->symbol = (segment == NO_SEG ? -SECT_ABS :
203                  segment == stext.index ? -SECT_TEXT :
204                  segment == sdata.index ? -SECT_DATA :
205                  segment == bssindex ? -SECT_BSS :
206                  raa_read(bsym, segment));
207     r->relative = relative;
208     r->bytes = bytes;
209
210     sect->nrelocs++;
211 }
212
213 static void aout_out (long segto, void *data, unsigned long type,
214                       long segment, long wrt) {
215     struct Section *s;
216     long realbytes = type & OUT_SIZMASK;
217     unsigned char mydata[4], *p;
218
219     if (wrt != NO_SEG) {
220         wrt = NO_SEG;                  /* continue to do _something_ */
221         error (ERR_NONFATAL, "WRT not supported by a.out output format");
222     }
223
224     type &= OUT_TYPMASK;
225
226     /*
227      * handle absolute-assembly (structure definitions)
228      */
229     if (segto == NO_SEG) {
230         if (type != OUT_RESERVE)
231             error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
232                    " space");
233         return;
234     }
235
236     if (segto == stext.index)
237         s = &stext;
238     else if (segto == sdata.index)
239         s = &sdata;
240     else if (segto == bssindex)
241         s = NULL;
242     else {
243         error(ERR_WARNING, "attempt to assemble code in"
244               " segment %d: defaulting to `.text'", segto);
245         s = &stext;
246     }
247
248     if (!s && type != OUT_RESERVE) {
249         error(ERR_WARNING, "attempt to initialise memory in the"
250               " BSS section: ignored");
251         if (type == OUT_REL2ADR)
252             realbytes = 2;
253         else if (type == OUT_REL4ADR)
254             realbytes = 4;
255         bsslen += realbytes;
256         return;
257     }
258
259     if (type == OUT_RESERVE) {
260         if (s) {
261             error(ERR_WARNING, "uninitialised space declared in"
262                   " %s section: zeroing",
263                   (segto == stext.index ? "code" : "data"));
264             aout_sect_write (s, NULL, realbytes);
265         } else
266             bsslen += realbytes;
267     } else if (type == OUT_RAWDATA) {
268         if (segment != NO_SEG)
269             error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
270         aout_sect_write (s, data, realbytes);
271     } else if (type == OUT_ADDRESS) {
272         if (segment != NO_SEG) {
273             if (segment % 2) {
274                 error(ERR_NONFATAL, "a.out format does not support"
275                       " segment base references");
276             } else
277                 aout_add_reloc (s, segment, FALSE, realbytes);
278         }
279         p = mydata;
280         if (realbytes == 2)
281             WRITESHORT (p, *(long *)data);
282         else
283             WRITELONG (p, *(long *)data);
284         aout_sect_write (s, mydata, realbytes);
285     } else if (type == OUT_REL2ADR) {
286         if (segment == segto)
287             error(ERR_PANIC, "intra-segment OUT_REL2ADR");
288         if (segment != NO_SEG && segment % 2) {
289             error(ERR_NONFATAL, "a.out format does not support"
290                   " segment base references");
291         } else
292             aout_add_reloc (s, segment, TRUE, 2);
293         p = mydata;
294         WRITESHORT (p, *(long*)data-(realbytes + s->len));
295         aout_sect_write (s, mydata, 2L);
296     } else if (type == OUT_REL4ADR) {
297         if (segment == segto)
298             error(ERR_PANIC, "intra-segment OUT_REL4ADR");
299         if (segment != NO_SEG && segment % 2) {
300             error(ERR_NONFATAL, "a.out format does not support"
301                   " segment base references");
302         } else
303             aout_add_reloc (s, segment, TRUE, 4);
304         p = mydata;
305         WRITELONG (p, *(long*)data-(realbytes + s->len));
306         aout_sect_write (s, mydata, 4L);
307     }
308 }
309
310 static void aout_pad_sections(void) {
311     static unsigned char pad[] = { 0x90, 0x90, 0x90, 0x90 };
312     /*
313      * Pad each of the text and data sections with NOPs until their
314      * length is a multiple of four. (NOP == 0x90.) Also increase
315      * the length of the BSS section similarly.
316      */
317     aout_sect_write (&stext, pad, (-stext.len) & 3);
318     aout_sect_write (&sdata, pad, (-sdata.len) & 3);
319     bsslen = (bsslen + 3) & ~3;
320 }
321
322 /*
323  * a.out files have the curious property that all references to
324  * things in the data or bss sections are done by addresses which
325  * are actually relative to the start of the _text_ section, in the
326  * _file_. (No relation to what happens after linking. No idea why
327  * this should be so. It's very strange.) So we have to go through
328  * the relocation table, _after_ the final size of each section is
329  * known, and fix up the relocations pointed to.
330  */
331 static void aout_fixup_relocs(struct Section *sect) {
332     struct Reloc *r;
333
334     saa_rewind (sect->data);
335     for (r = sect->head; r; r = r->next) {
336         unsigned char *p, *q, blk[4];
337         long l;
338
339         saa_fread (sect->data, r->address, blk, (long)r->bytes);
340         p = q = blk;
341         l = *p++;
342         l += ((long)*p++) << 8;
343         if (r->bytes == 4) {
344             l += ((long)*p++) << 16;
345             l += ((long)*p++) << 24;
346         }
347         if (r->symbol == -SECT_DATA)
348             l += stext.len;
349         else if (r->symbol == -SECT_BSS)
350             l += stext.len + sdata.len;
351         if (r->bytes == 4)
352             WRITELONG(q, l);
353         else
354             WRITESHORT(q, l);
355         saa_fwrite (sect->data, r->address, blk, (long)r->bytes);
356     }
357 }
358
359 static void aout_write(void) {
360     /*
361      * Emit the a.out header.
362      */
363     fwritelong (0x640107L, aoutfp);    /* OMAGIC, M_386, no flags */
364     fwritelong (stext.len, aoutfp);
365     fwritelong (sdata.len, aoutfp);
366     fwritelong (bsslen, aoutfp);
367     fwritelong (nsyms * 12, aoutfp);   /* length of symbol table */
368     fwritelong (0L, aoutfp);           /* object files have no entry point */
369     fwritelong (stext.nrelocs * 8, aoutfp);   /* size of text relocs */
370     fwritelong (sdata.nrelocs * 8, aoutfp);   /* size of data relocs */
371
372     /*
373      * Write out the code section and the data section.
374      */
375     saa_fpwrite (stext.data, aoutfp);
376     saa_fpwrite (sdata.data, aoutfp);
377
378     /*
379      * Write out the relocations.
380      */
381     aout_write_relocs (stext.head);
382     aout_write_relocs (sdata.head);
383
384     /*
385      * Write the symbol table.
386      */
387     aout_write_syms ();
388
389     /*
390      * And the string table.
391      */
392     fwritelong (strslen+4, aoutfp);    /* length includes length count */
393     saa_fpwrite (strs, aoutfp);
394 }
395
396 static void aout_write_relocs (struct Reloc *r) {
397     while (r) {
398         unsigned long word2;
399
400         fwritelong (r->address, aoutfp);
401
402         if (r->symbol >= 0)
403             word2 = r->symbol | 0x8000000L;
404         else
405             word2 = -r->symbol;
406         if (r->relative)
407             word2 |= 0x1000000L;
408         word2 |= (r->bytes == 2 ? 0x2000000L : 0x4000000L);
409         fwritelong (word2, aoutfp);
410
411         r = r->next;
412     }
413 }
414
415 static void aout_write_syms (void) {
416     int i;
417
418     saa_rewind (syms);
419     for (i=0; i<nsyms; i++) {
420         struct Symbol *sym = saa_rstruct(syms);
421         fwritelong (sym->strpos, aoutfp);
422         fwritelong ((long)sym->type, aoutfp);
423         /*
424          * Fix up the symbol value now we know the final section
425          * sizes.
426          */
427         if ((sym->type & SECT_MASK) == SECT_DATA)
428             sym->value += stext.len;
429         if ((sym->type & SECT_MASK) == SECT_BSS)
430             sym->value += stext.len + sdata.len;
431         fwritelong (sym->value, aoutfp);
432     }
433 }
434
435 static void aout_sect_write (struct Section *sect,
436                              unsigned char *data, unsigned long len) {
437     saa_wbytes (sect->data, data, len);
438     sect->len += len;
439 }
440
441 static long aout_segbase (long segment) {
442     return segment;
443 }
444
445 static int aout_directive (char *directive, char *value, int pass) {
446     return 0;
447 }
448
449 static void aout_filename (char *inname, char *outname, efunc error) {
450     standard_extension (inname, outname, ".o", error);
451 }
452
453 struct ofmt of_aout = {
454     "GNU a.out (i386) object files (e.g. Linux)",
455     "aout",
456     aout_init,
457     aout_out,
458     aout_deflabel,
459     aout_section_names,
460     aout_segbase,
461     aout_directive,
462     aout_filename,
463     aout_cleanup
464 };
465
466 #endif /* OF_AOUT */