outaout.c
上传用户:yuppie_zhu
上传日期:2007-01-08
资源大小:535k
文件大小:26k
源码类别:

编译器/解释器

开发平台:

C/C++

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