Hash even backend-specific directives, unify null functions
[platform/upstream/nasm.git] / output / outaout.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *     
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33
34 /* 
35  * outaout.c    output routines for the Netwide Assembler to produce
36  *              Linux a.out object files
37  */
38
39 #include "compiler.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <inttypes.h>
46
47 #include "nasm.h"
48 #include "nasmlib.h"
49 #include "saa.h"
50 #include "raa.h"
51 #include "stdscan.h"
52 #include "output/outform.h"
53 #include "output/outlib.h"
54
55 #if defined OF_AOUT || defined OF_AOUTB
56
57 #define RELTYPE_ABSOLUTE 0x00
58 #define RELTYPE_RELATIVE 0x01
59 #define RELTYPE_GOTPC    0x01   /* no explicit GOTPC in a.out */
60 #define RELTYPE_GOTOFF   0x10
61 #define RELTYPE_GOT      0x10   /* distinct from GOTOFF bcos sym not sect */
62 #define RELTYPE_PLT      0x21
63 #define RELTYPE_SYMFLAG  0x08
64
65 struct Reloc {
66     struct Reloc *next;
67     int32_t address;               /* relative to _start_ of section */
68     int32_t symbol;                /* symbol number or -ve section id */
69     int bytes;                  /* 2 or 4 */
70     int reltype;                /* see above */
71 };
72
73 struct Symbol {
74     int32_t strpos;                /* string table position of name */
75     int type;                   /* symbol type - see flags below */
76     int32_t value;                 /* address, or COMMON variable size */
77     int32_t size;                  /* size for data or function exports */
78     int32_t segment;               /* back-reference used by gsym_reloc */
79     struct Symbol *next;        /* list of globals in each section */
80     struct Symbol *nextfwd;     /* list of unresolved-size symbols */
81     char *name;                 /* for unresolved-size symbols */
82     int32_t symnum;                /* index into symbol table */
83 };
84
85 /*
86  * Section IDs - used in Reloc.symbol when negative, and in
87  * Symbol.type when positive.
88  */
89 #define SECT_ABS 2              /* absolute value */
90 #define SECT_TEXT 4             /* text section */
91 #define SECT_DATA 6             /* data section */
92 #define SECT_BSS 8              /* bss section */
93 #define SECT_MASK 0xE           /* mask out any of the above */
94
95 /*
96  * More flags used in Symbol.type.
97  */
98 #define SYM_GLOBAL 1            /* it's a global symbol */
99 #define SYM_DATA 0x100          /* used for shared libs */
100 #define SYM_FUNCTION 0x200      /* used for shared libs */
101 #define SYM_WITH_SIZE 0x4000    /* not output; internal only */
102
103 /*
104  * Bit more explanation of symbol types: SECT_xxx denotes a local
105  * symbol. SECT_xxx|SYM_GLOBAL denotes a global symbol, defined in
106  * this module. Just SYM_GLOBAL, with zero value, denotes an
107  * external symbol referenced in this module. And just SYM_GLOBAL,
108  * but with a non-zero value, declares a C `common' variable, of
109  * size `value'.
110  */
111
112 struct Section {
113     struct SAA *data;
114     uint32_t len, size, nrelocs;
115     int32_t index;
116     struct Reloc *head, **tail;
117     struct Symbol *gsyms, *asym;
118 };
119
120 static struct Section stext, sdata, sbss;
121
122 static struct SAA *syms;
123 static uint32_t nsyms;
124
125 static struct RAA *bsym;
126
127 static struct SAA *strs;
128 static uint32_t strslen;
129
130 static struct Symbol *fwds;
131
132 static FILE *aoutfp;
133 static efunc error;
134 static evalfunc evaluate;
135
136 static int bsd;
137 static int is_pic;
138
139 static void aout_write(void);
140 static void aout_write_relocs(struct Reloc *);
141 static void aout_write_syms(void);
142 static void aout_sect_write(struct Section *, const uint8_t *,
143                             uint32_t);
144 static void aout_pad_sections(void);
145 static void aout_fixup_relocs(struct Section *);
146
147 /*
148  * Special section numbers which are used to define special
149  * symbols, which can be used with WRT to provide PIC relocation
150  * types.
151  */
152 static int32_t aout_gotpc_sect, aout_gotoff_sect;
153 static int32_t aout_got_sect, aout_plt_sect;
154 static int32_t aout_sym_sect;
155
156 static void aoutg_init(FILE * fp, efunc errfunc, ldfunc ldef,
157                        evalfunc eval)
158 {
159     aoutfp = fp;
160     error = errfunc;
161     evaluate = eval;
162     (void)ldef;                 /* placate optimisers */
163     stext.data = saa_init(1L);
164     stext.head = NULL;
165     stext.tail = &stext.head;
166     sdata.data = saa_init(1L);
167     sdata.head = NULL;
168     sdata.tail = &sdata.head;
169     stext.len = stext.size = sdata.len = sdata.size = sbss.len = 0;
170     stext.nrelocs = sdata.nrelocs = 0;
171     stext.gsyms = sdata.gsyms = sbss.gsyms = NULL;
172     stext.index = seg_alloc();
173     sdata.index = seg_alloc();
174     sbss.index = seg_alloc();
175     stext.asym = sdata.asym = sbss.asym = NULL;
176     syms = saa_init((int32_t)sizeof(struct Symbol));
177     nsyms = 0;
178     bsym = raa_init();
179     strs = saa_init(1L);
180     strslen = 0;
181     fwds = NULL;
182 }
183
184 #ifdef OF_AOUT
185
186 static void aout_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval)
187 {
188     bsd = false;
189     aoutg_init(fp, errfunc, ldef, eval);
190
191     aout_gotpc_sect = aout_gotoff_sect = aout_got_sect =
192         aout_plt_sect = aout_sym_sect = NO_SEG;
193 }
194
195 #endif
196
197 #ifdef OF_AOUTB
198
199 extern struct ofmt of_aoutb;
200
201 static void aoutb_init(FILE * fp, efunc errfunc, ldfunc ldef,
202                        evalfunc eval)
203 {
204     bsd = true;
205     aoutg_init(fp, errfunc, ldef, eval);
206
207     is_pic = 0x00;              /* may become 0x40 */
208
209     aout_gotpc_sect = seg_alloc();
210     ldef("..gotpc", aout_gotpc_sect + 1, 0L, NULL, false, false, &of_aoutb,
211          error);
212     aout_gotoff_sect = seg_alloc();
213     ldef("..gotoff", aout_gotoff_sect + 1, 0L, NULL, false, false,
214          &of_aoutb, error);
215     aout_got_sect = seg_alloc();
216     ldef("..got", aout_got_sect + 1, 0L, NULL, false, false, &of_aoutb,
217          error);
218     aout_plt_sect = seg_alloc();
219     ldef("..plt", aout_plt_sect + 1, 0L, NULL, false, false, &of_aoutb,
220          error);
221     aout_sym_sect = seg_alloc();
222     ldef("..sym", aout_sym_sect + 1, 0L, NULL, false, false, &of_aoutb,
223          error);
224 }
225
226 #endif
227
228 static void aout_cleanup(int debuginfo)
229 {
230     struct Reloc *r;
231
232     (void)debuginfo;
233
234     aout_pad_sections();
235     aout_fixup_relocs(&stext);
236     aout_fixup_relocs(&sdata);
237     aout_write();
238     saa_free(stext.data);
239     while (stext.head) {
240         r = stext.head;
241         stext.head = stext.head->next;
242         nasm_free(r);
243     }
244     saa_free(sdata.data);
245     while (sdata.head) {
246         r = sdata.head;
247         sdata.head = sdata.head->next;
248         nasm_free(r);
249     }
250     saa_free(syms);
251     raa_free(bsym);
252     saa_free(strs);
253 }
254
255 static int32_t aout_section_names(char *name, int pass, int *bits)
256 {
257
258     (void)pass;
259
260     /*
261      * Default to 32 bits.
262      */
263     if (!name)
264         *bits = 32;
265
266     if (!name)
267         return stext.index;
268
269     if (!strcmp(name, ".text"))
270         return stext.index;
271     else if (!strcmp(name, ".data"))
272         return sdata.index;
273     else if (!strcmp(name, ".bss"))
274         return sbss.index;
275     else
276         return NO_SEG;
277 }
278
279 static void aout_deflabel(char *name, int32_t segment, int64_t offset,
280                           int is_global, char *special)
281 {
282     int pos = strslen + 4;
283     struct Symbol *sym;
284     int special_used = false;
285
286     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
287         /*
288          * This is a NASM special symbol. We never allow it into
289          * the a.out symbol table, even if it's a valid one. If it
290          * _isn't_ a valid one, we should barf immediately.
291          */
292         if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") &&
293             strcmp(name, "..got") && strcmp(name, "..plt") &&
294             strcmp(name, "..sym"))
295             error(ERR_NONFATAL, "unrecognised special symbol `%s'", name);
296         return;
297     }
298
299     if (is_global == 3) {
300         struct Symbol **s;
301         /*
302          * Fix up a forward-reference symbol size from the first
303          * pass.
304          */
305         for (s = &fwds; *s; s = &(*s)->nextfwd)
306             if (!strcmp((*s)->name, name)) {
307                 struct tokenval tokval;
308                 expr *e;
309                 char *p = special;
310
311                 while (*p && !nasm_isspace(*p))
312                     p++;
313                 while (*p && nasm_isspace(*p))
314                     p++;
315                 stdscan_reset();
316                 stdscan_bufptr = p;
317                 tokval.t_type = TOKEN_INVALID;
318                 e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
319                 if (e) {
320                     if (!is_simple(e))
321                         error(ERR_NONFATAL, "cannot use relocatable"
322                               " expression as symbol size");
323                     else
324                         (*s)->size = reloc_value(e);
325                 }
326
327                 /*
328                  * Remove it from the list of unresolved sizes.
329                  */
330                 nasm_free((*s)->name);
331                 *s = (*s)->nextfwd;
332                 return;
333             }
334         return;                 /* it wasn't an important one */
335     }
336
337     saa_wbytes(strs, name, (int32_t)(1 + strlen(name)));
338     strslen += 1 + strlen(name);
339
340     sym = saa_wstruct(syms);
341
342     sym->strpos = pos;
343     sym->type = is_global ? SYM_GLOBAL : 0;
344     sym->segment = segment;
345     if (segment == NO_SEG)
346         sym->type |= SECT_ABS;
347     else if (segment == stext.index) {
348         sym->type |= SECT_TEXT;
349         if (is_global) {
350             sym->next = stext.gsyms;
351             stext.gsyms = sym;
352         } else if (!stext.asym)
353             stext.asym = sym;
354     } else if (segment == sdata.index) {
355         sym->type |= SECT_DATA;
356         if (is_global) {
357             sym->next = sdata.gsyms;
358             sdata.gsyms = sym;
359         } else if (!sdata.asym)
360             sdata.asym = sym;
361     } else if (segment == sbss.index) {
362         sym->type |= SECT_BSS;
363         if (is_global) {
364             sym->next = sbss.gsyms;
365             sbss.gsyms = sym;
366         } else if (!sbss.asym)
367             sbss.asym = sym;
368     } else
369         sym->type = SYM_GLOBAL;
370     if (is_global == 2)
371         sym->value = offset;
372     else
373         sym->value = (sym->type == SYM_GLOBAL ? 0 : offset);
374
375     if (is_global && sym->type != SYM_GLOBAL) {
376         /*
377          * Global symbol exported _from_ this module. We must check
378          * the special text for type information.
379          */
380
381         if (special) {
382             int n = strcspn(special, " ");
383
384             if (!nasm_strnicmp(special, "function", n))
385                 sym->type |= SYM_FUNCTION;
386             else if (!nasm_strnicmp(special, "data", n) ||
387                      !nasm_strnicmp(special, "object", n))
388                 sym->type |= SYM_DATA;
389             else
390                 error(ERR_NONFATAL, "unrecognised symbol type `%.*s'",
391                       n, special);
392             if (special[n]) {
393                 struct tokenval tokval;
394                 expr *e;
395                 int fwd = false;
396                 char *saveme = stdscan_bufptr;  /* bugfix? fbk 8/10/00 */
397
398                 if (!bsd) {
399                     error(ERR_NONFATAL, "Linux a.out does not support"
400                           " symbol size information");
401                 } else {
402                     while (special[n] && nasm_isspace(special[n]))
403                         n++;
404                     /*
405                      * We have a size expression; attempt to
406                      * evaluate it.
407                      */
408                     sym->type |= SYM_WITH_SIZE;
409                     stdscan_reset();
410                     stdscan_bufptr = special + n;
411                     tokval.t_type = TOKEN_INVALID;
412                     e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error,
413                                  NULL);
414                     if (fwd) {
415                         sym->nextfwd = fwds;
416                         fwds = sym;
417                         sym->name = nasm_strdup(name);
418                     } else if (e) {
419                         if (!is_simple(e))
420                             error(ERR_NONFATAL, "cannot use relocatable"
421                                   " expression as symbol size");
422                         else
423                             sym->size = reloc_value(e);
424                     }
425                 }
426                 stdscan_bufptr = saveme;        /* bugfix? fbk 8/10/00 */
427             }
428             special_used = true;
429         }
430     }
431
432     /*
433      * define the references from external-symbol segment numbers
434      * to these symbol records.
435      */
436     if (segment != NO_SEG && segment != stext.index &&
437         segment != sdata.index && segment != sbss.index)
438         bsym = raa_write(bsym, segment, nsyms);
439     sym->symnum = nsyms;
440
441     nsyms++;
442     if (sym->type & SYM_WITH_SIZE)
443         nsyms++;                /* and another for the size */
444
445     if (special && !special_used)
446         error(ERR_NONFATAL, "no special symbol features supported here");
447 }
448
449 static void aout_add_reloc(struct Section *sect, int32_t segment,
450                            int reltype, int bytes)
451 {
452     struct Reloc *r;
453
454     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
455     sect->tail = &r->next;
456     r->next = NULL;
457
458     r->address = sect->len;
459     r->symbol = (segment == NO_SEG ? -SECT_ABS :
460                  segment == stext.index ? -SECT_TEXT :
461                  segment == sdata.index ? -SECT_DATA :
462                  segment == sbss.index ? -SECT_BSS :
463                  raa_read(bsym, segment));
464     r->reltype = reltype;
465     if (r->symbol >= 0)
466         r->reltype |= RELTYPE_SYMFLAG;
467     r->bytes = bytes;
468
469     sect->nrelocs++;
470 }
471
472 /*
473  * This routine deals with ..got and ..sym relocations: the more
474  * complicated kinds. In shared-library writing, some relocations
475  * with respect to global symbols must refer to the precise symbol
476  * rather than referring to an offset from the base of the section
477  * _containing_ the symbol. Such relocations call to this routine,
478  * which searches the symbol list for the symbol in question.
479  *
480  * RELTYPE_GOT references require the _exact_ symbol address to be
481  * used; RELTYPE_ABSOLUTE references can be at an offset from the
482  * symbol. The boolean argument `exact' tells us this.
483  *
484  * Return value is the adjusted value of `addr', having become an
485  * offset from the symbol rather than the section. Should always be
486  * zero when returning from an exact call.
487  *
488  * Limitation: if you define two symbols at the same place,
489  * confusion will occur.
490  *
491  * Inefficiency: we search, currently, using a linked list which
492  * isn't even necessarily sorted.
493  */
494 static int32_t aout_add_gsym_reloc(struct Section *sect,
495                                 int32_t segment, int32_t offset,
496                                 int type, int bytes, int exact)
497 {
498     struct Symbol *sym, *sm, *shead;
499     struct Reloc *r;
500
501     /*
502      * First look up the segment to find whether it's text, data,
503      * bss or an external symbol.
504      */
505     shead = NULL;
506     if (segment == stext.index)
507         shead = stext.gsyms;
508     else if (segment == sdata.index)
509         shead = sdata.gsyms;
510     else if (segment == sbss.index)
511         shead = sbss.gsyms;
512     if (!shead) {
513         if (exact && offset != 0)
514             error(ERR_NONFATAL, "unable to find a suitable global symbol"
515                   " for this reference");
516         else
517             aout_add_reloc(sect, segment, type, bytes);
518         return offset;
519     }
520
521     if (exact) {
522         /*
523          * Find a symbol pointing _exactly_ at this one.
524          */
525         for (sym = shead; sym; sym = sym->next)
526             if (sym->value == offset)
527                 break;
528     } else {
529         /*
530          * Find the nearest symbol below this one.
531          */
532         sym = NULL;
533         for (sm = shead; sm; sm = sm->next)
534             if (sm->value <= offset && (!sym || sm->value > sym->value))
535                 sym = sm;
536     }
537     if (!sym && exact) {
538         error(ERR_NONFATAL, "unable to find a suitable global symbol"
539               " for this reference");
540         return 0;
541     }
542
543     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
544     sect->tail = &r->next;
545     r->next = NULL;
546
547     r->address = sect->len;
548     r->symbol = sym->symnum;
549     r->reltype = type | RELTYPE_SYMFLAG;
550     r->bytes = bytes;
551
552     sect->nrelocs++;
553
554     return offset - sym->value;
555 }
556
557 /*
558  * This routine deals with ..gotoff relocations. These _must_ refer
559  * to a symbol, due to a perversity of *BSD's PIC implementation,
560  * and it must be a non-global one as well; so we store `asym', the
561  * first nonglobal symbol defined in each section, and always work
562  * from that. Relocation type is always RELTYPE_GOTOFF.
563  *
564  * Return value is the adjusted value of `addr', having become an
565  * offset from the `asym' symbol rather than the section.
566  */
567 static int32_t aout_add_gotoff_reloc(struct Section *sect, int32_t segment,
568                                   int32_t offset, int bytes)
569 {
570     struct Reloc *r;
571     struct Symbol *asym;
572
573     /*
574      * First look up the segment to find whether it's text, data,
575      * bss or an external symbol.
576      */
577     asym = NULL;
578     if (segment == stext.index)
579         asym = stext.asym;
580     else if (segment == sdata.index)
581         asym = sdata.asym;
582     else if (segment == sbss.index)
583         asym = sbss.asym;
584     if (!asym)
585         error(ERR_NONFATAL, "`..gotoff' relocations require a non-global"
586               " symbol in the section");
587
588     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
589     sect->tail = &r->next;
590     r->next = NULL;
591
592     r->address = sect->len;
593     r->symbol = asym->symnum;
594     r->reltype = RELTYPE_GOTOFF;
595     r->bytes = bytes;
596
597     sect->nrelocs++;
598
599     return offset - asym->value;
600 }
601
602 static void aout_out(int32_t segto, const void *data,
603                      enum out_type type, uint64_t size,
604                      int32_t segment, int32_t wrt)
605 {
606     struct Section *s;
607     int32_t addr;
608     uint8_t mydata[4], *p;
609
610     /*
611      * handle absolute-assembly (structure definitions)
612      */
613     if (segto == NO_SEG) {
614         if (type != OUT_RESERVE)
615             error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
616                   " space");
617         return;
618     }
619
620     if (segto == stext.index)
621         s = &stext;
622     else if (segto == sdata.index)
623         s = &sdata;
624     else if (segto == sbss.index)
625         s = NULL;
626     else {
627         error(ERR_WARNING, "attempt to assemble code in"
628               " segment %d: defaulting to `.text'", segto);
629         s = &stext;
630     }
631
632     if (!s && type != OUT_RESERVE) {
633         error(ERR_WARNING, "attempt to initialize memory in the"
634               " BSS section: ignored");
635         sbss.len += realsize(type, size);
636         return;
637     }
638
639     if (type == OUT_RESERVE) {
640         if (s) {
641             error(ERR_WARNING, "uninitialized space declared in"
642                   " %s section: zeroing",
643                   (segto == stext.index ? "code" : "data"));
644             aout_sect_write(s, NULL, size);
645         } else
646             sbss.len += size;
647     } else if (type == OUT_RAWDATA) {
648         if (segment != NO_SEG)
649             error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
650         aout_sect_write(s, data, size);
651     } else if (type == OUT_ADDRESS) {
652         addr = *(int64_t *)data;
653         if (segment != NO_SEG) {
654             if (segment % 2) {
655                 error(ERR_NONFATAL, "a.out format does not support"
656                       " segment base references");
657             } else {
658                 if (wrt == NO_SEG) {
659                     aout_add_reloc(s, segment, RELTYPE_ABSOLUTE,
660                                    size);
661                 } else if (!bsd) {
662                     error(ERR_NONFATAL,
663                           "Linux a.out format does not support"
664                           " any use of WRT");
665                     wrt = NO_SEG;       /* we can at least _try_ to continue */
666                 } else if (wrt == aout_gotpc_sect + 1) {
667                     is_pic = 0x40;
668                     aout_add_reloc(s, segment, RELTYPE_GOTPC, size);
669                 } else if (wrt == aout_gotoff_sect + 1) {
670                     is_pic = 0x40;
671                     addr = aout_add_gotoff_reloc(s, segment,
672                                                  addr, size);
673                 } else if (wrt == aout_got_sect + 1) {
674                     is_pic = 0x40;
675                     addr =
676                         aout_add_gsym_reloc(s, segment, addr, RELTYPE_GOT,
677                                             size, true);
678                 } else if (wrt == aout_sym_sect + 1) {
679                     addr = aout_add_gsym_reloc(s, segment, addr,
680                                                RELTYPE_ABSOLUTE, size,
681                                                false);
682                 } else if (wrt == aout_plt_sect + 1) {
683                     is_pic = 0x40;
684                     error(ERR_NONFATAL,
685                           "a.out format cannot produce non-PC-"
686                           "relative PLT references");
687                 } else {
688                     error(ERR_NONFATAL,
689                           "a.out format does not support this"
690                           " use of WRT");
691                     wrt = NO_SEG;       /* we can at least _try_ to continue */
692                 }
693             }
694         }
695         p = mydata;
696         if (size == 2)
697             WRITESHORT(p, addr);
698         else
699             WRITELONG(p, addr);
700         aout_sect_write(s, mydata, size);
701     } else if (type == OUT_REL2ADR) {
702         if (segment == segto)
703             error(ERR_PANIC, "intra-segment OUT_REL2ADR");
704         if (segment != NO_SEG && segment % 2) {
705             error(ERR_NONFATAL, "a.out format does not support"
706                   " segment base references");
707         } else {
708             if (wrt == NO_SEG) {
709                 aout_add_reloc(s, segment, RELTYPE_RELATIVE, 2);
710             } else if (!bsd) {
711                 error(ERR_NONFATAL, "Linux a.out format does not support"
712                       " any use of WRT");
713                 wrt = NO_SEG;   /* we can at least _try_ to continue */
714             } else if (wrt == aout_plt_sect + 1) {
715                 is_pic = 0x40;
716                 aout_add_reloc(s, segment, RELTYPE_PLT, 2);
717             } else if (wrt == aout_gotpc_sect + 1 ||
718                        wrt == aout_gotoff_sect + 1 ||
719                        wrt == aout_got_sect + 1) {
720                 error(ERR_NONFATAL, "a.out format cannot produce PC-"
721                       "relative GOT references");
722             } else {
723                 error(ERR_NONFATAL, "a.out format does not support this"
724                       " use of WRT");
725                 wrt = NO_SEG;   /* we can at least _try_ to continue */
726             }
727         }
728         p = mydata;
729         WRITESHORT(p, *(int64_t *)data - (size + s->len));
730         aout_sect_write(s, mydata, 2L);
731     } else if (type == OUT_REL4ADR) {
732         if (segment == segto)
733             error(ERR_PANIC, "intra-segment OUT_REL4ADR");
734         if (segment != NO_SEG && segment % 2) {
735             error(ERR_NONFATAL, "a.out format does not support"
736                   " segment base references");
737         } else {
738             if (wrt == NO_SEG) {
739                 aout_add_reloc(s, segment, RELTYPE_RELATIVE, 4);
740             } else if (!bsd) {
741                 error(ERR_NONFATAL, "Linux a.out format does not support"
742                       " any use of WRT");
743                 wrt = NO_SEG;   /* we can at least _try_ to continue */
744             } else if (wrt == aout_plt_sect + 1) {
745                 is_pic = 0x40;
746                 aout_add_reloc(s, segment, RELTYPE_PLT, 4);
747             } else if (wrt == aout_gotpc_sect + 1 ||
748                        wrt == aout_gotoff_sect + 1 ||
749                        wrt == aout_got_sect + 1) {
750                 error(ERR_NONFATAL, "a.out format cannot produce PC-"
751                       "relative GOT references");
752             } else {
753                 error(ERR_NONFATAL, "a.out format does not support this"
754                       " use of WRT");
755                 wrt = NO_SEG;   /* we can at least _try_ to continue */
756             }
757         }
758         p = mydata;
759         WRITELONG(p, *(int64_t *)data - (size + s->len));
760         aout_sect_write(s, mydata, 4L);
761     }
762 }
763
764 static void aout_pad_sections(void)
765 {
766     static uint8_t pad[] = { 0x90, 0x90, 0x90, 0x90 };
767     /*
768      * Pad each of the text and data sections with NOPs until their
769      * length is a multiple of four. (NOP == 0x90.) Also increase
770      * the length of the BSS section similarly.
771      */
772     aout_sect_write(&stext, pad, (-(int32_t)stext.len) & 3);
773     aout_sect_write(&sdata, pad, (-(int32_t)sdata.len) & 3);
774     sbss.len = (sbss.len + 3) & ~3;
775 }
776
777 /*
778  * a.out files have the curious property that all references to
779  * things in the data or bss sections are done by addresses which
780  * are actually relative to the start of the _text_ section, in the
781  * _file_. (No relation to what happens after linking. No idea why
782  * this should be so. It's very strange.) So we have to go through
783  * the relocation table, _after_ the final size of each section is
784  * known, and fix up the relocations pointed to.
785  */
786 static void aout_fixup_relocs(struct Section *sect)
787 {
788     struct Reloc *r;
789
790     saa_rewind(sect->data);
791     for (r = sect->head; r; r = r->next) {
792         uint8_t *p, *q, blk[4];
793         int32_t l;
794
795         saa_fread(sect->data, r->address, blk, (int32_t)r->bytes);
796         p = q = blk;
797         l = *p++;
798         if (r->bytes > 1) {
799             l += ((int32_t)*p++) << 8;
800             if (r->bytes == 4) {
801                 l += ((int32_t)*p++) << 16;
802                 l += ((int32_t)*p++) << 24;
803             }
804         }
805         if (r->symbol == -SECT_DATA)
806             l += stext.len;
807         else if (r->symbol == -SECT_BSS)
808             l += stext.len + sdata.len;
809         if (r->bytes == 4)
810             WRITELONG(q, l);
811         else if (r->bytes == 2)
812             WRITESHORT(q, l);
813         else
814             *q++ = l & 0xFF;
815         saa_fwrite(sect->data, r->address, blk, (int32_t)r->bytes);
816     }
817 }
818
819 static void aout_write(void)
820 {
821     /*
822      * Emit the a.out header.
823      */
824     /* OMAGIC, M_386 or MID_I386, no flags */
825     fwriteint32_t(bsd ? 0x07018600 | is_pic : 0x640107L, aoutfp);
826     fwriteint32_t(stext.len, aoutfp);
827     fwriteint32_t(sdata.len, aoutfp);
828     fwriteint32_t(sbss.len, aoutfp);
829     fwriteint32_t(nsyms * 12, aoutfp);     /* length of symbol table */
830     fwriteint32_t(0L, aoutfp);     /* object files have no entry point */
831     fwriteint32_t(stext.nrelocs * 8, aoutfp);      /* size of text relocs */
832     fwriteint32_t(sdata.nrelocs * 8, aoutfp);      /* size of data relocs */
833
834     /*
835      * Write out the code section and the data section.
836      */
837     saa_fpwrite(stext.data, aoutfp);
838     saa_fpwrite(sdata.data, aoutfp);
839
840     /*
841      * Write out the relocations.
842      */
843     aout_write_relocs(stext.head);
844     aout_write_relocs(sdata.head);
845
846     /*
847      * Write the symbol table.
848      */
849     aout_write_syms();
850
851     /*
852      * And the string table.
853      */
854     fwriteint32_t(strslen + 4, aoutfp);    /* length includes length count */
855     saa_fpwrite(strs, aoutfp);
856 }
857
858 static void aout_write_relocs(struct Reloc *r)
859 {
860     while (r) {
861         uint32_t word2;
862
863         fwriteint32_t(r->address, aoutfp);
864
865         if (r->symbol >= 0)
866             word2 = r->symbol;
867         else
868             word2 = -r->symbol;
869         word2 |= r->reltype << 24;
870         word2 |= (r->bytes == 1 ? 0 :
871                   r->bytes == 2 ? 0x2000000L : 0x4000000L);
872         fwriteint32_t(word2, aoutfp);
873
874         r = r->next;
875     }
876 }
877
878 static void aout_write_syms(void)
879 {
880     uint32_t i;
881
882     saa_rewind(syms);
883     for (i = 0; i < nsyms; i++) {
884         struct Symbol *sym = saa_rstruct(syms);
885         fwriteint32_t(sym->strpos, aoutfp);
886         fwriteint32_t((int32_t)sym->type & ~SYM_WITH_SIZE, aoutfp);
887         /*
888          * Fix up the symbol value now we know the final section
889          * sizes.
890          */
891         if ((sym->type & SECT_MASK) == SECT_DATA)
892             sym->value += stext.len;
893         if ((sym->type & SECT_MASK) == SECT_BSS)
894             sym->value += stext.len + sdata.len;
895         fwriteint32_t(sym->value, aoutfp);
896         /*
897          * Output a size record if necessary.
898          */
899         if (sym->type & SYM_WITH_SIZE) {
900             fwriteint32_t(sym->strpos, aoutfp);
901             fwriteint32_t(0x0DL, aoutfp);  /* special value: means size */
902             fwriteint32_t(sym->size, aoutfp);
903             i++;                /* use up another of `nsyms' */
904         }
905     }
906 }
907
908 static void aout_sect_write(struct Section *sect,
909                             const uint8_t *data, uint32_t len)
910 {
911     saa_wbytes(sect->data, data, len);
912     sect->len += len;
913 }
914
915 static int32_t aout_segbase(int32_t segment)
916 {
917     return segment;
918 }
919
920 static void aout_filename(char *inname, char *outname, efunc error)
921 {
922     standard_extension(inname, outname, ".o", error);
923 }
924
925 extern macros_t aout_stdmac[];
926
927 #endif                          /* OF_AOUT || OF_AOUTB */
928
929 #ifdef OF_AOUT
930
931 struct ofmt of_aout = {
932     "Linux a.out object files",
933     "aout",
934     0,
935     null_debug_arr,
936     &null_debug_form,
937     aout_stdmac,
938     aout_init,
939     null_setinfo,
940     aout_out,
941     aout_deflabel,
942     aout_section_names,
943     aout_segbase,
944     null_directive,
945     aout_filename,
946     aout_cleanup
947 };
948
949 #endif
950
951 #ifdef OF_AOUTB
952
953 struct ofmt of_aoutb = {
954     "NetBSD/FreeBSD a.out object files",
955     "aoutb",
956     0,
957     null_debug_arr,
958     &null_debug_form,
959     aout_stdmac,
960     aoutb_init,
961     null_setinfo,
962     aout_out,
963     aout_deflabel,
964     aout_section_names,
965     aout_segbase,
966     null_directive,
967     aout_filename,
968     aout_cleanup
969 };
970
971 #endif