📄 elf-objfmt.c
字号:
/* * 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 + -