⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 outaout.c

📁 开源的nasm编译器源码,研究编译器原理很有帮且
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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 + -