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