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