home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / nasm097s.zip / OUTAOUT.C < prev    next >
C/C++ Source or Header  |  1997-11-06  |  26KB  |  897 lines

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