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

📄 elf-objfmt.c

📁 支持AMD64的汇编编译器源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * ELF object format * *  Copyright (C) 2003  Michael Urman * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include <util.h>/*@unused@*/ RCSID("$Id: elf-objfmt.c 1168 2004-10-31 01:07:52Z peter $");/* Notes * * elf-objfmt uses the "linking" view of an ELF file: * ELF header, an optional program header table, several sections, * and a section header table * * The ELF header tells us some overall program information, *   where to find the PHT (if it exists) with phnum and phentsize,  *   and where to find the SHT with shnum and shentsize * * The PHT doesn't seem to be generated by NASM for elftest.asm * * The SHT * * Each Section is spatially disjoint, and has exactly one SHT entry. */#define YASM_LIB_INTERNAL#define YASM_BC_INTERNAL#define YASM_EXPR_INTERNAL#include <libyasm.h>#include "elf.h"typedef struct yasm_objfmt_elf {    yasm_objfmt_base objfmt;		/* base structure */    unsigned int parse_scnum;		/* sect numbering in parser */    elf_symtab_head* elf_symtab;	/* symbol table of indexed syms */    elf_strtab_head* shstrtab;		/* section name strtab */    elf_strtab_head* strtab;		/* strtab entries */    yasm_object *object;    yasm_symtab *symtab;    /*@dependent@*/ yasm_arch *arch;        yasm_symrec *dotdotsym;		/* ..sym symbol */} yasm_objfmt_elf;typedef struct {    yasm_objfmt_elf *objfmt_elf;    FILE *f;    elf_secthead *shead;    yasm_section *sect;    yasm_object *object;    unsigned long sindex;} elf_objfmt_output_info;typedef struct {    yasm_objfmt_elf *objfmt_elf;    int local_names;} append_local_sym_info;yasm_objfmt_module yasm_elf_LTX_objfmt;static elf_symtab_entry *elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym,			 elf_section_index sectidx, elf_symbol_binding bind,			 elf_symbol_type type, yasm_expr *size,			 elf_address value){    elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->strtab,						   yasm_symrec_get_name(sym));    elf_symtab_entry *entry = elf_symtab_entry_create(name, sym);    elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);    elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value);    yasm_symrec_add_data(sym, &elf_symrec_data, entry);    return entry;}static intelf_objfmt_append_local_sym(yasm_symrec *sym, /*@null@*/ void *d){    append_local_sym_info *info = (append_local_sym_info *)d;    elf_symtab_entry *entry;    elf_address value=0;    yasm_section *sect=NULL;    yasm_bytecode *precbc=NULL;    assert(info != NULL);    if (!yasm_symrec_get_data(sym, &elf_symrec_data)) {	int is_sect = 0;	if (!yasm_symrec_get_label(sym, &precbc))	    return 1;	sect = yasm_bc_get_section(precbc);	if (!yasm_section_is_absolute(sect) &&	    strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0)	    is_sect = 1;	/* neither sections nor locals (except when debugging) need names */	entry = elf_symtab_insert_local_sym(info->objfmt_elf->elf_symtab,		    info->local_names && !is_sect ?		    info->objfmt_elf->strtab : NULL, sym);	elf_symtab_set_nonzero(entry, sect, 0, STB_LOCAL,			       is_sect ? STT_SECTION : STT_NOTYPE, NULL, 0);	yasm_symrec_add_data(sym, &elf_symrec_data, entry);	if (is_sect)	    return 1;    }    else {	if (!yasm_symrec_get_label(sym, &precbc))	    return 1;	sect = yasm_bc_get_section(precbc);    }    entry = yasm_symrec_get_data(sym, &elf_symrec_data);    if (precbc)	value = precbc->offset + precbc->len;    elf_symtab_set_nonzero(entry, sect, 0, 0, 0, NULL, value);    return 1;}static yasm_objfmt *elf_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a){    yasm_objfmt_elf *objfmt_elf = yasm_xmalloc(sizeof(yasm_objfmt_elf));    yasm_symrec *filesym;    elf_symtab_entry *entry;    objfmt_elf->objfmt.module = &yasm_elf_LTX_objfmt;    objfmt_elf->object = object;    objfmt_elf->symtab = yasm_object_get_symtab(object);    objfmt_elf->arch = a;    if (!elf_set_arch(a, objfmt_elf->symtab)) {	yasm_xfree(objfmt_elf);	return NULL;    }    objfmt_elf->parse_scnum = 4;    /* section numbering starts at 0;				       4 predefined sections. */    objfmt_elf->shstrtab = elf_strtab_create();    objfmt_elf->strtab = elf_strtab_create();    objfmt_elf->elf_symtab = elf_symtab_create();    /* FIXME: misuse of NULL bytecode here; it works, but only barely. */    filesym = yasm_symtab_define_label(objfmt_elf->symtab, ".file", NULL, 0,				       0);    entry = elf_symtab_entry_create(	elf_strtab_append_str(objfmt_elf->strtab, in_filename), filesym);    yasm_symrec_add_data(filesym, &elf_symrec_data, entry);    elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL, 0);    elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);    /* FIXME: misuse of NULL bytecode */    objfmt_elf->dotdotsym = yasm_symtab_define_label(objfmt_elf->symtab,						     "..sym", NULL, 1, 0);    return (yasm_objfmt *)objfmt_elf;}static longelf_objfmt_output_align(FILE *f, unsigned int align){    long pos;    unsigned long delta;    if ((align & (align-1)) != 0)	yasm_internal_error("requested alignment not a power of two");    pos = ftell(f);    if (pos == -1) {	yasm__error(0, N_("could not get file position on output file"));	return -1;    }    delta = align - (pos & (align-1));     if (delta != align) {	pos += delta;	if (fseek(f, pos, SEEK_SET) < 0) {	    yasm__error(0, N_("could not set file position on output file"));	    return -1;	}    }    return pos;}static intelf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,			unsigned char *buf, size_t destsize, size_t valsize,			int warn, void *d){    elf_reloc_entry *reloc;    elf_objfmt_output_info *info = d;    yasm_intnum *zero;    int retval;    reloc = elf_reloc_entry_create(sym, NULL,	yasm_intnum_create_uint(bc->offset), 0, valsize);    if (reloc == NULL) {	yasm__error(bc->line, N_("elf: invalid relocation size"));	return 1;    }    /* allocate .rel[a] sections on a need-basis */    if (elf_secthead_append_reloc(info->sect, info->shead, reloc))	info->objfmt_elf->parse_scnum++;    zero = yasm_intnum_create_uint(0);    elf_handle_reloc_addend(zero, reloc);    retval = yasm_arch_intnum_tobytes(info->objfmt_elf->arch, zero, buf,				      destsize, valsize, 0, bc, warn,				      bc->line);    yasm_intnum_destroy(zero);    return retval;}static intelf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,			size_t valsize, int shift, unsigned long offset,			yasm_bytecode *bc, int rel, int warn,			/*@null@*/ void *d){    /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;    /*@dependent@*/ /*@null@*/ yasm_intnum *intn;    /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;    /*@dependent@*/ /*@null@*/ yasm_symrec *sym;    /*@null@*/ elf_reloc_entry *reloc = NULL;    /*@null@*/ yasm_expr *wrt_expr;    /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = NULL;    if (info == NULL)	yasm_internal_error("null info struct");    *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);    /* Handle floating point expressions */    flt = yasm_expr_get_floatnum(ep);    if (flt) {	if (shift < 0)	    yasm_internal_error(N_("attempting to negative shift a float"));	return yasm_arch_floatnum_tobytes(info->objfmt_elf->arch, flt, buf,					  destsize, valsize,					  (unsigned int)shift, warn, bc->line);    }    /* Check for a WRT relocation */    wrt_expr = yasm_expr_extract_wrt(ep);    if (wrt_expr) {	wrt = yasm_expr_extract_symrec(&wrt_expr, 0,				       yasm_common_calc_bc_dist);	yasm_expr_destroy(wrt_expr);	if (!wrt) {	    yasm__error(bc->line, N_("WRT expression too complex"));	    return 1;	}    }    /* Handle integer expressions, with relocation if necessary */    sym = yasm_expr_extract_symrec(ep,				   !(wrt == info->objfmt_elf->dotdotsym ||				     (wrt && elf_is_wrt_sym_relative(wrt))),				   yasm_common_calc_bc_dist);    if (sym) {	yasm_sym_vis vis;	vis = yasm_symrec_get_visibility(sym);	if (wrt == info->objfmt_elf->dotdotsym)	    wrt = NULL;	else if (wrt && elf_is_wrt_sym_relative(wrt))	    ;	else if (!(vis & (YASM_SYM_COMMON|YASM_SYM_EXTERN)))	{	    yasm_bytecode *label_precbc;	    /* Local symbols need relocation to their section's start */	    if (yasm_symrec_get_label(sym, &label_precbc)) {		yasm_section *label_sect = yasm_bc_get_section(label_precbc);		/*@null@*/ elf_secthead *sym_shead;		sym_shead =		    yasm_section_get_data(label_sect, &elf_section_data);		assert(sym_shead != NULL);		sym = elf_secthead_get_sym(sym_shead);	    }	}	if (rel) {	    /* Need to reference to start of section, so add $$ in. */	    *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),		yasm_expr_sym(yasm_symtab_define_label2("$$",		    yasm_section_bcs_first(info->sect), 0, (*ep)->line)),		(*ep)->line);	    /* HELP: and this seems to have the desired effect. */	    *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),		yasm_expr_int(yasm_intnum_create_uint(bc->offset + offset)),		(*ep)->line);	    *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);	}	reloc = elf_reloc_entry_create(sym, wrt,	    yasm_intnum_create_uint(bc->offset + offset), rel, valsize);	if (reloc == NULL) {	    yasm__error(bc->line, N_("elf: invalid relocation (WRT or size)"));	    return 1;	}	/* allocate .rel[a] sections on a need-basis */	if (elf_secthead_append_reloc(info->sect, info->shead, reloc))	    info->objfmt_elf->parse_scnum++;    }    intn = yasm_expr_get_intnum(ep, NULL);    if (intn) {	if (rel) {	    int retval = yasm_arch_intnum_fixup_rel(info->objfmt_elf->arch,						    intn, valsize, bc,						    bc->line);	    if (retval)		return retval;	}	if (reloc)	    elf_handle_reloc_addend(intn, reloc);	return yasm_arch_intnum_tobytes(info->objfmt_elf->arch, intn, buf,					destsize, valsize, shift, bc, warn,					bc->line);    }    /* Check for complex float expressions */    if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {	yasm__error(bc->line, N_("floating point expression too complex"));	return 1;    }    yasm__error(bc->line, N_("elf: relocation too complex"));    return 1;}static intelf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d){    /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;    unsigned char buf[256];    /*@null@*/ /*@only@*/ unsigned char *bigbuf;    unsigned long size = 256;    unsigned long multiple;    unsigned long i;    int gap;    if (info == NULL)	yasm_internal_error("null info struct");    bigbuf = yasm_bc_tobytes(bc, buf, &size, &multiple, &gap, info,			     elf_objfmt_output_expr, elf_objfmt_output_reloc);    /* Don't bother doing anything else if size ended up being 0. */    if (size == 0) {	if (bigbuf)	    yasm_xfree(bigbuf);	return 0;    }    else {	yasm_intnum *bcsize = yasm_intnum_create_uint(size);	yasm_intnum *mult = yasm_intnum_create_uint(multiple);	yasm_intnum_calc(bcsize, YASM_EXPR_MUL, mult, 0);	elf_secthead_add_size(info->shead, bcsize);	yasm_intnum_destroy(bcsize);	yasm_intnum_destroy(mult);    }    /* Warn that gaps are converted to 0 and write out the 0's. */    if (gap) {	unsigned long left;	yasm__warning(YASM_WARN_GENERAL, bc->line,	    N_("uninitialized space declared in code/data section: zeroing"));	/* Write out in chunks */	memset(buf, 0, 256);	left = multiple*size;	while (left > 256) {	    fwrite(buf, 256, 1, info->f);	    left -= 256;	}	fwrite(buf, left, 1, info->f);    } else {	/* Output multiple copies of buf (or bigbuf if non-NULL) to file */	for (i=0; i<multiple; i++)	    fwrite(bigbuf ? bigbuf : buf, (size_t)size, 1, info->f);    }    /* If bigbuf was allocated, free it */    if (bigbuf)	yasm_xfree(bigbuf);    return 0;}static elf_secthead *elf_objfmt_create_dbg_secthead(yasm_section *sect,			       elf_objfmt_output_info *info){    elf_secthead *shead;    elf_section_type type=SHT_PROGBITS;    yasm_intnum *align=NULL;    elf_size entsize=0;    const char *sectname = yasm_section_get_name(sect);    elf_strtab_entry *name = elf_strtab_append_str(info->objfmt_elf->shstrtab,						   sectname);    if (yasm__strcasecmp(sectname, ".stab")==0) {	align = yasm_intnum_create_uint(4);	entsize = 12;    } else if (yasm__strcasecmp(sectname, ".stabstr")==0) {	type = SHT_STRTAB;	align = yasm_intnum_create_uint(1);    }    else	yasm_internal_error(N_("Unrecognized section without data"));    shead = elf_secthead_create(name, type, 0, info->objfmt_elf->parse_scnum++,				0, 0);    elf_secthead_set_align(shead, align);    elf_secthead_set_entsize(shead, entsize);    yasm_section_add_data(sect, &elf_section_data, shead);    return shead;}static intelf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d){    /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;    /*@dependent@*/ /*@null@*/ elf_secthead *shead;    long pos;    char *relname;    const char *sectname;    /* Don't output absolute sections into the section table */    if (yasm_section_is_absolute(sect))	return 0;    if (info == NULL)	yasm_internal_error("null info struct");    shead = yasm_section_get_data(sect, &elf_section_data);    if (shead == NULL)	shead = elf_objfmt_create_dbg_secthead(sect, info);    /* don't output header-only sections */    if ((elf_secthead_get_type(shead) & SHT_NOBITS) == SHT_NOBITS)    {	yasm_bytecode *last = yasm_section_bcs_last(sect);	if (last) {	    yasm_intnum *sectsize;	    sectsize = yasm_intnum_create_uint(last->offset + last->len);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -