📄 outaout.c
字号:
/* outaout.c output routines for the Netwide Assembler to produce * Linux a.out object files * * The Netwide Assembler is copyright (C) 1996 Simon Tatham and * Julian Hall. All rights reserved. The software is * redistributable under the licence given in the file "Licence" * distributed in the NASM archive. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "nasm.h"#include "nasmlib.h"#include "outform.h"#if defined OF_AOUT || defined OF_AOUTB#define RELTYPE_ABSOLUTE 0x00#define RELTYPE_RELATIVE 0x01#define RELTYPE_GOTPC 0x01 /* no explicit GOTPC in a.out */#define RELTYPE_GOTOFF 0x10#define RELTYPE_GOT 0x10 /* distinct from GOTOFF bcos sym not sect */#define RELTYPE_PLT 0x21#define RELTYPE_SYMFLAG 0x08struct Reloc { struct Reloc *next; long address; /* relative to _start_ of section */ long symbol; /* symbol number or -ve section id */ int bytes; /* 2 or 4 */ int reltype; /* see above */};struct Symbol { long strpos; /* string table position of name */ int type; /* symbol type - see flags below */ long value; /* address, or COMMON variable size */ long size; /* size for data or function exports */ long segment; /* back-reference used by gsym_reloc */ struct Symbol *next; /* list of globals in each section */ struct Symbol *nextfwd; /* list of unresolved-size symbols */ char *name; /* for unresolved-size symbols */ long symnum; /* index into symbol table */};/* * Section IDs - used in Reloc.symbol when negative, and in * Symbol.type when positive. */#define SECT_ABS 2 /* absolute value */#define SECT_TEXT 4 /* text section */#define SECT_DATA 6 /* data section */#define SECT_BSS 8 /* bss section */#define SECT_MASK 0xE /* mask out any of the above *//* * More flags used in Symbol.type. */#define SYM_GLOBAL 1 /* it's a global symbol */#define SYM_DATA 0x100 /* used for shared libs */#define SYM_FUNCTION 0x200 /* used for shared libs */#define SYM_WITH_SIZE 0x4000 /* not output; internal only *//* * Bit more explanation of symbol types: SECT_xxx denotes a local * symbol. SECT_xxx|SYM_GLOBAL denotes a global symbol, defined in * this module. Just SYM_GLOBAL, with zero value, denotes an * external symbol referenced in this module. And just SYM_GLOBAL, * but with a non-zero value, declares a C `common' variable, of * size `value'. */struct Section { struct SAA *data; unsigned long len, size, nrelocs; long index; struct Reloc *head, **tail; struct Symbol *gsyms, *asym;};static struct Section stext, sdata, sbss;static struct SAA *syms;static unsigned long nsyms;static struct RAA *bsym;static struct SAA *strs;static unsigned long strslen;static struct Symbol *fwds;static FILE *aoutfp;static efunc error;static evalfunc evaluate;static int bsd;static int is_pic;static void aout_write(void);static void aout_write_relocs(struct Reloc *);static void aout_write_syms(void);static void aout_sect_write(struct Section *, const unsigned char *, unsigned long);static void aout_pad_sections(void);static void aout_fixup_relocs(struct Section *);/* * Special section numbers which are used to define special * symbols, which can be used with WRT to provide PIC relocation * types. */static long aout_gotpc_sect, aout_gotoff_sect;static long aout_got_sect, aout_plt_sect;static long aout_sym_sect;static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { aoutfp = fp; error = errfunc; evaluate = eval; (void) ldef; /* placate optimisers */ stext.data = saa_init(1L); stext.head = NULL; stext.tail = &stext.head; sdata.data = saa_init(1L); sdata.head = NULL; sdata.tail = &sdata.head; stext.len = stext.size = sdata.len = sdata.size = sbss.len = 0; stext.nrelocs = sdata.nrelocs = 0; stext.gsyms = sdata.gsyms = sbss.gsyms = NULL; stext.index = seg_alloc(); sdata.index = seg_alloc(); sbss.index = seg_alloc(); stext.asym = sdata.asym = sbss.asym = NULL; syms = saa_init((long)sizeof(struct Symbol)); nsyms = 0; bsym = raa_init(); strs = saa_init(1L); strslen = 0; fwds = NULL;}#ifdef OF_AOUTstatic void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { bsd = FALSE; aoutg_init (fp, errfunc, ldef, eval); aout_gotpc_sect = aout_gotoff_sect = aout_got_sect = aout_plt_sect = aout_sym_sect = NO_SEG;}#endif#ifdef OF_AOUTBextern struct ofmt of_aoutb;static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { bsd = TRUE; aoutg_init (fp, errfunc, ldef, eval); is_pic = 0x00; /* may become 0x40 */ aout_gotpc_sect = seg_alloc(); ldef("..gotpc", aout_gotpc_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error); aout_gotoff_sect = seg_alloc(); ldef("..gotoff", aout_gotoff_sect+1, 0L,NULL,FALSE,FALSE,&of_aoutb,error); aout_got_sect = seg_alloc(); ldef("..got", aout_got_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error); aout_plt_sect = seg_alloc(); ldef("..plt", aout_plt_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error); aout_sym_sect = seg_alloc(); ldef("..sym", aout_sym_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error);}#endifstatic void aout_cleanup(int debuginfo) { struct Reloc *r; (void) debuginfo; aout_pad_sections(); aout_fixup_relocs(&stext); aout_fixup_relocs(&sdata); aout_write(); fclose (aoutfp); saa_free (stext.data); while (stext.head) { r = stext.head; stext.head = stext.head->next; nasm_free (r); } saa_free (sdata.data); while (sdata.head) { r = sdata.head; sdata.head = sdata.head->next; nasm_free (r); } saa_free (syms); raa_free (bsym); saa_free (strs);}static long aout_section_names (char *name, int pass, int *bits) { /* * Default to 32 bits. */ if (!name) *bits = 32; if (!name) return stext.index; if (!strcmp(name, ".text")) return stext.index; else if (!strcmp(name, ".data")) return sdata.index; else if (!strcmp(name, ".bss")) return sbss.index; else return NO_SEG;}static void aout_deflabel (char *name, long segment, long offset, int is_global, char *special) { int pos = strslen+4; struct Symbol *sym; int special_used = FALSE; if (name[0] == '.' && name[1] == '.' && name[2] != '@') { /* * This is a NASM special symbol. We never allow it into * the a.out symbol table, even if it's a valid one. If it * _isn't_ a valid one, we should barf immediately. */ if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && strcmp(name, "..got") && strcmp(name, "..plt") && strcmp(name, "..sym")) error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); return; } if (is_global == 3) { struct Symbol **s; /* * Fix up a forward-reference symbol size from the first * pass. */ for (s = &fwds; *s; s = &(*s)->nextfwd) if (!strcmp((*s)->name, name)) { struct tokenval tokval; expr *e; char *p = special; while (*p && !isspace(*p)) p++; while (*p && isspace(*p)) p++; stdscan_reset(); stdscan_bufptr = p; tokval.t_type = TOKEN_INVALID; e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); if (e) { if (!is_simple(e)) error (ERR_NONFATAL, "cannot use relocatable" " expression as symbol size"); else (*s)->size = reloc_value(e); } /* * Remove it from the list of unresolved sizes. */ nasm_free ((*s)->name); *s = (*s)->nextfwd; return; } return; /* it wasn't an important one */ } saa_wbytes (strs, name, (long)(1+strlen(name))); strslen += 1+strlen(name); sym = saa_wstruct (syms); sym->strpos = pos; sym->type = is_global ? SYM_GLOBAL : 0; sym->segment = segment; if (segment == NO_SEG) sym->type |= SECT_ABS; else if (segment == stext.index) { sym->type |= SECT_TEXT; if (is_global) { sym->next = stext.gsyms; stext.gsyms = sym; } else if (!stext.asym) stext.asym = sym; } else if (segment == sdata.index) { sym->type |= SECT_DATA; if (is_global) { sym->next = sdata.gsyms; sdata.gsyms = sym; } else if (!sdata.asym) sdata.asym = sym; } else if (segment == sbss.index) { sym->type |= SECT_BSS; if (is_global) { sym->next = sbss.gsyms; sbss.gsyms = sym; } else if (!sbss.asym) sbss.asym = sym; } else sym->type = SYM_GLOBAL; if (is_global == 2) sym->value = offset; else sym->value = (sym->type == SYM_GLOBAL ? 0 : offset); if (is_global && sym->type != SYM_GLOBAL) { /* * Global symbol exported _from_ this module. We must check * the special text for type information. */ if (special) { int n = strcspn(special, " "); if (!nasm_strnicmp(special, "function", n)) sym->type |= SYM_FUNCTION; else if (!nasm_strnicmp(special, "data", n) || !nasm_strnicmp(special, "object", n)) sym->type |= SYM_DATA; else error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", n, special); if (special[n]) { struct tokenval tokval; expr *e; int fwd = FALSE; char *saveme=stdscan_bufptr; /* bugfix? fbk 8/10/00 */ if (!bsd) { error(ERR_NONFATAL, "Linux a.out does not support" " symbol size information"); } else { while (special[n] && isspace(special[n])) n++; /* * We have a size expression; attempt to * evaluate it. */ sym->type |= SYM_WITH_SIZE; stdscan_reset(); stdscan_bufptr = special+n; tokval.t_type = TOKEN_INVALID; e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, NULL); if (fwd) { sym->nextfwd = fwds; fwds = sym; sym->name = nasm_strdup(name); } else if (e) { if (!is_simple(e)) error (ERR_NONFATAL, "cannot use relocatable" " expression as symbol size"); else sym->size = reloc_value(e); } } stdscan_bufptr=saveme; /* bugfix? fbk 8/10/00 */ } special_used = TRUE; } } /* * define the references from external-symbol segment numbers * to these symbol records. */ if (segment != NO_SEG && segment != stext.index && segment != sdata.index && segment != sbss.index) bsym = raa_write (bsym, segment, nsyms); sym->symnum = nsyms; nsyms++; if (sym->type & SYM_WITH_SIZE) nsyms++; /* and another for the size */ if (special && !special_used) error(ERR_NONFATAL, "no special symbol features supported here");}static void aout_add_reloc (struct Section *sect, long segment, int reltype, int bytes) { struct Reloc *r; r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); sect->tail = &r->next; r->next = NULL; r->address = sect->len; r->symbol = (segment == NO_SEG ? -SECT_ABS : segment == stext.index ? -SECT_TEXT : segment == sdata.index ? -SECT_DATA : segment == sbss.index ? -SECT_BSS : raa_read(bsym, segment)); r->reltype = reltype; if (r->symbol >= 0) r->reltype |= RELTYPE_SYMFLAG; r->bytes = bytes; sect->nrelocs++;}/* * This routine deals with ..got and ..sym relocations: the more * complicated kinds. In shared-library writing, some relocations * with respect to global symbols must refer to the precise symbol * rather than referring to an offset from the base of the section * _containing_ the symbol. Such relocations call to this routine, * which searches the symbol list for the symbol in question. * * RELTYPE_GOT references require the _exact_ symbol address to be * used; RELTYPE_ABSOLUTE references can be at an offset from the * symbol. The boolean argument `exact' tells us this. * * Return value is the adjusted value of `addr', having become an * offset from the symbol rather than the section. Should always be * zero when returning from an exact call. * * Limitation: if you define two symbols at the same place, * confusion will occur. * * Inefficiency: we search, currently, using a linked list which * isn't even necessarily sorted. */static long aout_add_gsym_reloc (struct Section *sect, long segment, long offset, int type, int bytes, int exact) { struct Symbol *sym, *sm, *shead; struct Reloc *r; /* * First look up the segment to find whether it's text, data, * bss or an external symbol. */ shead = NULL; if (segment == stext.index) shead = stext.gsyms; else if (segment == sdata.index) shead = sdata.gsyms; else if (segment == sbss.index) shead = sbss.gsyms; if (!shead) { if (exact && offset != 0) error (ERR_NONFATAL, "unable to find a suitable global symbol" " for this reference"); else aout_add_reloc (sect, segment, type, bytes); return offset; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -