📄 coff-objfmt.c
字号:
/* * COFF (DJGPP) object format * * Copyright (C) 2002 Peter Johnson * * 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: coff-objfmt.c 1168 2004-10-31 01:07:52Z peter $");#define YASM_LIB_INTERNAL#define YASM_BC_INTERNAL#define YASM_EXPR_INTERNAL#include <libyasm.h>#define REGULAR_OUTBUF_SIZE 1024/* Defining this to 0 sets all section VMA's to 0 rather than as the same as * the LMA. According to the DJGPP COFF Spec, this should be set to 1 * (VMA=LMA), and indeed DJGPP's GCC output shows VMA=LMA. However, NASM * outputs VMA=0 (as if this was 0), and GNU objdump output looks a lot nicer * with VMA=0. Who's right? This is #defined as changing this setting affects * several places in the code. */#define COFF_SET_VMA (!objfmt_coff->win32)#define COFF_MACHINE_I386 0x014C#define COFF_MACHINE_AMD64 0x8664#define COFF_F_LNNO 0x0004 /* line number info NOT present */#define COFF_F_LSYMS 0x0008 /* local symbols NOT present */#define COFF_F_AR32WR 0x0100 /* 32-bit little endian file */typedef struct coff_reloc { yasm_reloc reloc; enum { COFF_RELOC_ABSOLUTE = 0, /* absolute, no reloc needed */ /* I386 relocations */ COFF_RELOC_I386_ADDR16 = 0x1, /* 16-bit absolute reference */ COFF_RELOC_I386_REL16 = 0x2, /* 16-bit PC-relative reference */ COFF_RELOC_I386_ADDR32 = 0x6, /* 32-bit absolute reference */ COFF_RELOC_I386_ADDR32NB = 0x7, /* 32-bit absolute ref w/o base */ COFF_RELOC_I386_SEG12 = 0x9, /* 16-bit absolute segment ref */ COFF_RELOC_I386_SECTION = 0xA, /* section index */ COFF_RELOC_I386_SECREL = 0xB, /* offset from start of segment */ COFF_RELOC_I386_TOKEN = 0xC, /* CLR metadata token */ COFF_RELOC_I386_SECREL7 = 0xD, /* 7-bit offset from base of sect */ COFF_RELOC_I386_REL32 = 0x14, /* 32-bit PC-relative reference */ /* AMD64 relocations */ COFF_RELOC_AMD64_ADDR64 = 0x1, /* 64-bit address (VA) */ COFF_RELOC_AMD64_ADDR32 = 0x2, /* 32-bit address (VA) */ COFF_RELOC_AMD64_ADDR32NB = 0x3, /* 32-bit address w/o base (RVA) */ COFF_RELOC_AMD64_REL32 = 0x4, /* 32-bit relative (0 byte dist) */ COFF_RELOC_AMD64_REL32_1 = 0x5, /* 32-bit relative (1 byte dist) */ COFF_RELOC_AMD64_REL32_2 = 0x6, /* 32-bit relative (2 byte dist) */ COFF_RELOC_AMD64_REL32_3 = 0x7, /* 32-bit relative (3 byte dist) */ COFF_RELOC_AMD64_REL32_4 = 0x8, /* 32-bit relative (4 byte dist) */ COFF_RELOC_AMD64_REL32_5 = 0x9, /* 32-bit relative (5 byte dist) */ COFF_RELOC_AMD64_SECTION = 0xA, /* section index */ COFF_RELOC_AMD64_SECREL = 0xB, /* 32-bit offset from base of sect */ COFF_RELOC_AMD64_SECREL7 = 0xC, /* 7-bit offset from base of sect */ COFF_RELOC_AMD64_TOKEN = 0xD /* CLR metadata token */ } type; /* type of relocation */} coff_reloc;#define COFF_STYP_TEXT 0x00000020UL#define COFF_STYP_DATA 0x00000040UL#define COFF_STYP_BSS 0x00000080UL#define COFF_STYP_INFO 0x00000200UL#define COFF_STYP_STD_MASK 0x000003FFUL#define COFF_STYP_ALIGN_MASK 0x00F00000UL#define COFF_STYP_ALIGN_SHIFT 20#define COFF_STYP_DISCARD 0x02000000UL#define COFF_STYP_NOCACHE 0x04000000UL#define COFF_STYP_NOPAGE 0x08000000UL#define COFF_STYP_SHARED 0x10000000UL#define COFF_STYP_EXECUTE 0x20000000UL#define COFF_STYP_READ 0x40000000UL#define COFF_STYP_WRITE 0x80000000UL#define COFF_STYP_WIN32_MASK 0xFE000000ULtypedef struct coff_section_data { /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ unsigned int scnum; /* section number (1=first section) */ unsigned long flags; /* section flags (see COFF_STYP_* above) */ unsigned long addr; /* starting memory address (first section -> 0) */ unsigned long scnptr; /* file ptr to raw data */ unsigned long size; /* size of raw data (section data) in bytes */ unsigned long relptr; /* file ptr to relocation */ unsigned long nreloc; /* number of relocation entries >64k -> error */} coff_section_data;typedef enum coff_symrec_sclass { COFF_SCL_EFCN = 0xff, /* physical end of function */ COFF_SCL_NULL = 0, COFF_SCL_AUTO = 1, /* automatic variable */ COFF_SCL_EXT = 2, /* external symbol */ COFF_SCL_STAT = 3, /* static */ COFF_SCL_REG = 4, /* register variable */ COFF_SCL_EXTDEF = 5, /* external definition */ COFF_SCL_LABEL = 6, /* label */ COFF_SCL_ULABEL = 7, /* undefined label */ COFF_SCL_MOS = 8, /* member of structure */ COFF_SCL_ARG = 9, /* function argument */ COFF_SCL_STRTAG = 10, /* structure tag */ COFF_SCL_MOU = 11, /* member of union */ COFF_SCL_UNTAG = 12, /* union tag */ COFF_SCL_TPDEF = 13, /* type definition */ COFF_SCL_USTATIC = 14, /* undefined static */ COFF_SCL_ENTAG = 15, /* enumeration tag */ COFF_SCL_MOE = 16, /* member of enumeration */ COFF_SCL_REGPARM = 17, /* register parameter */ COFF_SCL_FIELD = 18, /* bit field */ COFF_SCL_AUTOARG = 19, /* auto argument */ COFF_SCL_LASTENT = 20, /* dummy entry (end of block) */ COFF_SCL_BLOCK = 100, /* ".bb" or ".eb" */ COFF_SCL_FCN = 101, /* ".bf" or ".ef" */ COFF_SCL_EOS = 102, /* end of structure */ COFF_SCL_FILE = 103, /* file name */ COFF_SCL_LINE = 104, /* line # reformatted as symbol table entry */ COFF_SCL_ALIAS = 105, /* duplicate tag */ COFF_SCL_HIDDEN = 106 /* ext symbol in dmert public lib */} coff_symrec_sclass;typedef struct coff_symrec_data { unsigned long index; /* assigned COFF symbol table index */ coff_symrec_sclass sclass; /* storage class */ /*@owned@*/ /*@null@*/ yasm_expr *size; /* size if COMMON declaration */} coff_symrec_data;typedef union coff_symtab_auxent { /* no data needed for section symbol auxent, all info avail from sym */ /*@owned@*/ char *fname; /* filename aux entry */} coff_symtab_auxent;typedef enum coff_symtab_auxtype { COFF_SYMTAB_AUX_NONE = 0, COFF_SYMTAB_AUX_SECT, COFF_SYMTAB_AUX_FILE} coff_symtab_auxtype;typedef struct coff_symtab_entry { STAILQ_ENTRY(coff_symtab_entry) link; /*@dependent@*/ yasm_symrec *sym; int numaux; /* number of auxiliary entries */ coff_symtab_auxtype auxtype; /* type of aux entries */ coff_symtab_auxent aux[1]; /* actually may be any size (including 0) */} coff_symtab_entry;typedef STAILQ_HEAD(coff_symtab_head, coff_symtab_entry) coff_symtab_head;typedef struct yasm_objfmt_coff { yasm_objfmt_base objfmt; /* base structure*/ unsigned int parse_scnum; /* sect numbering in parser */ coff_symtab_head coff_symtab; /* symbol table of indexed syms */ int win32; /* nonzero for win32 output */ unsigned int machine; /* COFF machine to use */ yasm_object *object; yasm_symtab *symtab; /*@dependent@*/ yasm_arch *arch;} yasm_objfmt_coff;typedef struct coff_objfmt_output_info { yasm_objfmt_coff *objfmt_coff; /*@dependent@*/ FILE *f; /*@only@*/ unsigned char *buf; yasm_section *sect; /*@dependent@*/ coff_section_data *csd; unsigned long addr; /* start of next section */} coff_objfmt_output_info;static void coff_section_data_destroy(/*@only@*/ void *d);static void coff_section_data_print(void *data, FILE *f, int indent_level);static const yasm_assoc_data_callback coff_section_data_cb = { coff_section_data_destroy, coff_section_data_print};static void coff_symrec_data_destroy(/*@only@*/ void *d);static void coff_symrec_data_print(void *data, FILE *f, int indent_level);static const yasm_assoc_data_callback coff_symrec_data_cb = { coff_symrec_data_destroy, coff_symrec_data_print};yasm_objfmt_module yasm_coff_LTX_objfmt;yasm_objfmt_module yasm_win32_LTX_objfmt;static /*@dependent@*/ coff_symtab_entry *coff_objfmt_symtab_append(yasm_objfmt_coff *objfmt_coff, yasm_symrec *sym, coff_symrec_sclass sclass, /*@only@*/ /*@null@*/ yasm_expr *size, int numaux, coff_symtab_auxtype auxtype){ /*@null@*/ /*@dependent@*/ coff_symrec_data *sym_data_prev; coff_symrec_data *sym_data; coff_symtab_entry *entry; if (STAILQ_EMPTY(&objfmt_coff->coff_symtab)) yasm_internal_error(N_("empty COFF symbol table")); entry = STAILQ_LAST(&objfmt_coff->coff_symtab, coff_symtab_entry, link); sym_data_prev = yasm_symrec_get_data(entry->sym, &coff_symrec_data_cb); assert(sym_data_prev != NULL); sym_data = yasm_xmalloc(sizeof(coff_symrec_data)); sym_data->index = sym_data_prev->index + entry->numaux + 1; sym_data->sclass = sclass; sym_data->size = size; yasm_symrec_add_data(sym, &coff_symrec_data_cb, sym_data); entry = yasm_xmalloc(sizeof(coff_symtab_entry) + (numaux-1)*sizeof(coff_symtab_auxent)); entry->sym = sym; entry->numaux = numaux; entry->auxtype = auxtype; STAILQ_INSERT_TAIL(&objfmt_coff->coff_symtab, entry, link); return entry;}static intcoff_objfmt_append_local_sym(yasm_symrec *sym, /*@unused@*/ /*@null@*/ void *d){ /*@null@*/ yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)d; assert(objfmt_coff != NULL); if (!yasm_symrec_get_data(sym, &coff_symrec_data_cb)) coff_objfmt_symtab_append(objfmt_coff, sym, COFF_SCL_STAT, NULL, 0, COFF_SYMTAB_AUX_NONE); return 1;}static yasm_objfmt_coff *coff_common_create(const char *in_filename, yasm_object *object, yasm_arch *a){ yasm_objfmt_coff *objfmt_coff = yasm_xmalloc(sizeof(yasm_objfmt_coff)); yasm_symrec *filesym; coff_symrec_data *data; coff_symtab_entry *entry; objfmt_coff->object = object; objfmt_coff->symtab = yasm_object_get_symtab(object); objfmt_coff->arch = a; /* Only support x86 arch */ if (yasm__strcasecmp(yasm_arch_keyword(a), "x86") != 0) { yasm_xfree(objfmt_coff); return NULL; } /* Support x86 and amd64 machines of x86 arch */ if (yasm__strcasecmp(yasm_arch_get_machine(a), "x86") == 0) { objfmt_coff->machine = COFF_MACHINE_I386; } else if (yasm__strcasecmp(yasm_arch_get_machine(a), "amd64") == 0) { objfmt_coff->machine = COFF_MACHINE_AMD64; } else { yasm_xfree(objfmt_coff); return NULL; } objfmt_coff->parse_scnum = 1; /* section numbering starts at 1 */ STAILQ_INIT(&objfmt_coff->coff_symtab); data = yasm_xmalloc(sizeof(coff_symrec_data)); data->index = 0; data->sclass = COFF_SCL_FILE; data->size = NULL; /* FIXME: misuse of NULL bytecode here; it works, but only barely. */ filesym = yasm_symtab_define_label(objfmt_coff->symtab, ".file", NULL, 0, 0); yasm_symrec_add_data(filesym, &coff_symrec_data_cb, data); entry = yasm_xmalloc(sizeof(coff_symtab_entry)); entry->sym = filesym; entry->numaux = 1; entry->auxtype = COFF_SYMTAB_AUX_FILE; entry->aux[0].fname = yasm__xstrdup(in_filename); STAILQ_INSERT_TAIL(&objfmt_coff->coff_symtab, entry, link); return objfmt_coff;}static yasm_objfmt *coff_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a){ yasm_objfmt_coff *objfmt_coff = coff_common_create(in_filename, object, a); if (objfmt_coff) { objfmt_coff->objfmt.module = &yasm_coff_LTX_objfmt; objfmt_coff->win32 = 0; } return (yasm_objfmt *)objfmt_coff;}static yasm_objfmt *win32_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a){ yasm_objfmt_coff *objfmt_coff = coff_common_create(in_filename, object, a); if (objfmt_coff) { objfmt_coff->objfmt.module = &yasm_win32_LTX_objfmt; objfmt_coff->win32 = 1; } return (yasm_objfmt *)objfmt_coff;}static intcoff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d){ /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; /*@dependent@*/ /*@null@*/ coff_section_data *csd; /*@null@*/ yasm_bytecode *last; /* Don't output absolute sections */ if (yasm_section_is_absolute(sect)) return 0; assert(info != NULL); csd = yasm_section_get_data(sect, &coff_section_data_cb); assert(csd != NULL); csd->addr = info->addr; last = yasm_section_bcs_last(sect); if (last) info->addr += last->offset + last->len; return 0;}static intcoff_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@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; yasm_objfmt_coff *objfmt_coff; /*@dependent@*/ /*@null@*/ yasm_intnum *intn; /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; /*@dependent@*/ /*@null@*/ yasm_symrec *sym; /*@dependent@*/ yasm_section *label_sect; /*@dependent@*/ /*@null@*/ yasm_bytecode *label_precbc; assert(info != NULL); objfmt_coff = info->objfmt_coff; *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(objfmt_coff->arch, flt, buf, destsize, valsize, (unsigned int)shift, warn, bc->line); } /* Handle integer expressions, with relocation if necessary */ sym = yasm_expr_extract_symrec(ep, 1, yasm_common_calc_bc_dist); if (sym) { unsigned long addr; coff_reloc *reloc; yasm_sym_vis vis; if (valsize != 32) { yasm__error(bc->line, N_("coff: invalid relocation size")); return 1; } reloc = yasm_xmalloc(sizeof(coff_reloc)); addr = bc->offset + offset; if (COFF_SET_VMA) addr += info->addr; reloc->reloc.addr = yasm_intnum_create_uint(addr); reloc->reloc.sym = sym; vis = yasm_symrec_get_visibility(sym); if (vis & YASM_SYM_COMMON) { /* In standard COFF, COMMON symbols have their length added in */ if (!objfmt_coff->win32) { /*@dependent@*/ /*@null@*/ coff_symrec_data *csymd; csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb); assert(csymd != NULL); *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep), yasm_expr_expr(yasm_expr_copy(csymd->size)), csymd->size->line); *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist); } } else if (!(vis & YASM_SYM_EXTERN)) { /* Local symbols need relocation to their section's start */ if (yasm_symrec_get_label(sym, &label_precbc)) { /*@null@*/ coff_section_data *label_csd; label_sect = yasm_bc_get_section(label_precbc); label_csd = yasm_section_get_data(label_sect, &coff_section_data_cb); assert(label_csd != NULL); reloc->reloc.sym = label_csd->sym; if (COFF_SET_VMA) *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep), yasm_expr_int(yasm_intnum_create_uint(label_csd->addr)), (*ep)->line); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -