?? xdf-objfmt.c
字號:
/* * Extended Dynamic Object format * * Copyright (C) 2004 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: xdf-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#define XDF_MAGIC 0x87654321#define XDF_SYM_EXTERN 1#define XDF_SYM_GLOBAL 2#define XDF_SYM_EQU 4typedef STAILQ_HEAD(xdf_reloc_head, xdf_reloc) xdf_reloc_head;typedef struct xdf_reloc { yasm_reloc reloc; /*@null@*/ yasm_symrec *base; /* base symbol (for WRT) */ enum { XDF_RELOC_REL = 1, /* relative to segment */ XDF_RELOC_WRT = 2, /* relative to symbol */ XDF_RELOC_RIP = 4, /* RIP-relative */ XDF_RELOC_SEG = 8 /* segment containing symbol */ } type; /* type of relocation */ enum { XDF_RELOC_8 = 1, XDF_RELOC_16 = 2, XDF_RELOC_32 = 4, XDF_RELOC_64 = 8 } size; /* size of relocation */ unsigned int shift; /* relocation shift (0,4,8,16,24,32) */} xdf_reloc;typedef struct xdf_section_data { /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */ yasm_intnum *addr; /* starting memory address */ long scnum; /* section number (0=first section) */ unsigned int align; /* section alignment (0-4096) */ enum { XDF_SECT_ABSOLUTE = 0x01, XDF_SECT_FLAT = 0x02, XDF_SECT_BSS = 0x04, XDF_SECT_EQU = 0x08, XDF_SECT_USE_16 = 0x10, XDF_SECT_USE_32 = 0x20, XDF_SECT_USE_64 = 0x40 } flags; /* section flags */ 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 */ /*@owned@*/ xdf_reloc_head relocs;} xdf_section_data;typedef struct xdf_symrec_data { unsigned long index; /* assigned XDF symbol table index */} xdf_symrec_data;typedef struct xdf_symtab_entry { STAILQ_ENTRY(xdf_symtab_entry) link; /*@dependent@*/ yasm_symrec *sym;} xdf_symtab_entry;typedef STAILQ_HEAD(xdf_symtab_head, xdf_symtab_entry) xdf_symtab_head;typedef struct yasm_objfmt_xdf { yasm_objfmt_base objfmt; /* base structure */ long parse_scnum; /* sect numbering in parser */ xdf_symtab_head xdf_symtab; /* symbol table of indexed syms */ yasm_object *object; yasm_symtab *symtab; /*@dependent@*/ yasm_arch *arch;} yasm_objfmt_xdf;typedef struct xdf_objfmt_output_info { yasm_objfmt_xdf *objfmt_xdf; /*@dependent@*/ FILE *f; /*@only@*/ unsigned char *buf; yasm_section *sect; /*@dependent@*/ xdf_section_data *xsd;} xdf_objfmt_output_info;static void xdf_section_data_destroy(/*@only@*/ void *d);static void xdf_section_data_print(void *data, FILE *f, int indent_level);static const yasm_assoc_data_callback xdf_section_data_cb = { xdf_section_data_destroy, xdf_section_data_print};static void xdf_symrec_data_destroy(/*@only@*/ void *d);static void xdf_symrec_data_print(void *data, FILE *f, int indent_level);static const yasm_assoc_data_callback xdf_symrec_data_cb = { xdf_symrec_data_destroy, xdf_symrec_data_print};yasm_objfmt_module yasm_xdf_LTX_objfmt;static /*@dependent@*/ xdf_symtab_entry *xdf_objfmt_symtab_append(yasm_objfmt_xdf *objfmt_xdf, yasm_symrec *sym){ /*@null@*/ /*@dependent@*/ xdf_symrec_data *sym_data_prev; xdf_symrec_data *sym_data; xdf_symtab_entry *entry; unsigned long indx; if (STAILQ_EMPTY(&objfmt_xdf->xdf_symtab)) indx = 0; else { entry = STAILQ_LAST(&objfmt_xdf->xdf_symtab, xdf_symtab_entry, link); sym_data_prev = yasm_symrec_get_data(entry->sym, &xdf_symrec_data_cb); assert(sym_data_prev != NULL); indx = sym_data_prev->index + 1; } sym_data = yasm_xmalloc(sizeof(xdf_symrec_data)); sym_data->index = indx; yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data); entry = yasm_xmalloc(sizeof(xdf_symtab_entry)); entry->sym = sym; STAILQ_INSERT_TAIL(&objfmt_xdf->xdf_symtab, entry, link); return entry;}static intxdf_objfmt_append_local_sym(yasm_symrec *sym, /*@unused@*/ /*@null@*/ void *d){ /*@null@*/ yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)d; assert(objfmt_xdf != NULL); if (!yasm_symrec_get_data(sym, &xdf_symrec_data_cb)) xdf_objfmt_symtab_append(objfmt_xdf, sym); return 1;}static yasm_objfmt *xdf_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a){ yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf)); objfmt_xdf->object = object; objfmt_xdf->symtab = yasm_object_get_symtab(object); objfmt_xdf->arch = a; /* Only support x86 arch */ if (yasm__strcasecmp(yasm_arch_keyword(a), "x86") != 0) { yasm_xfree(objfmt_xdf); return NULL; } /* Support x86 and amd64 machines of x86 arch */ if (yasm__strcasecmp(yasm_arch_get_machine(a), "x86") && yasm__strcasecmp(yasm_arch_get_machine(a), "amd64")) { yasm_xfree(objfmt_xdf); return NULL; } objfmt_xdf->parse_scnum = 0; /* section numbering starts at 0 */ STAILQ_INIT(&objfmt_xdf->xdf_symtab); objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt; return (yasm_objfmt *)objfmt_xdf;}static intxdf_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@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; yasm_objfmt_xdf *objfmt_xdf; /*@dependent@*/ /*@null@*/ yasm_intnum *intn; /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; /*@dependent@*/ /*@null@*/ yasm_symrec *sym; yasm_expr *shr_expr; yasm_expr *wrt_expr; unsigned int shr = 0; unsigned int seg = 0; assert(info != NULL); objfmt_xdf = info->objfmt_xdf; *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_xdf->arch, flt, buf, destsize, valsize, (unsigned int)shift, warn, bc->line); } /* Check for a right shift value */ shr_expr = yasm_expr_extract_shr(ep); if (shr_expr) { /*@dependent@*/ /*@null@*/ const yasm_intnum *shr_intn; shr_intn = yasm_expr_get_intnum(&shr_expr, NULL); if (!shr_intn) { yasm__error(bc->line, N_("shift expression too complex")); return 1; } shr = yasm_intnum_get_uint(shr_intn); } /* Check for a segment relocation */ if (yasm_expr_extract_seg(ep)) seg = 1; /* Check for a WRT relocation */ wrt_expr = yasm_expr_extract_wrt(ep); /* Handle integer expressions, with relocation if necessary */ sym = yasm_expr_extract_symrec(ep, 0, yasm_common_calc_bc_dist); if (sym) { xdf_reloc *reloc; reloc = yasm_xmalloc(sizeof(xdf_reloc)); reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); reloc->reloc.sym = sym; reloc->base = NULL; reloc->size = valsize/8; reloc->shift = shr; if (seg) reloc->type = XDF_RELOC_SEG; else if (wrt_expr) { reloc->base = yasm_expr_extract_symrec(&wrt_expr, 0, yasm_common_calc_bc_dist); if (!reloc->base) { yasm__error(bc->line, N_("WRT expression too complex")); return 1; } reloc->type = XDF_RELOC_WRT; } else if (rel) { reloc->type = XDF_RELOC_RIP; /* 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); *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist); } else reloc->type = XDF_RELOC_REL; info->xsd->nreloc++; yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); } intn = yasm_expr_get_intnum(ep, NULL); if (intn) { if (rel) { int retval = yasm_arch_intnum_fixup_rel(objfmt_xdf->arch, intn, valsize, bc, bc->line); if (retval) return retval; } return yasm_arch_intnum_tobytes(objfmt_xdf->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_("xdf: relocation too complex")); return 1;}static intxdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d){ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; /*@null@*/ /*@only@*/ unsigned char *bigbuf; unsigned long size = REGULAR_OUTBUF_SIZE; unsigned long multiple; unsigned long i; int gap; assert(info != NULL); bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info, xdf_objfmt_output_expr, NULL); /* Don't bother doing anything else if size ended up being 0. */ if (size == 0) { if (bigbuf) yasm_xfree(bigbuf); return 0; } info->xsd->size += multiple*size; /* 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: zeroing")); /* Write out in chunks */ memset(info->buf, 0, REGULAR_OUTBUF_SIZE); left = multiple*size; while (left > REGULAR_OUTBUF_SIZE) { fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f); left -= REGULAR_OUTBUF_SIZE; } fwrite(info->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 : info->buf, (size_t)size, 1, info->f); } /* If bigbuf was allocated, free it */ if (bigbuf) yasm_xfree(bigbuf); return 0;}static intxdf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d){ /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; /*@dependent@*/ /*@null@*/ xdf_section_data *xsd; long pos; xdf_reloc *reloc; yasm_bytecode *last; /* FIXME: Don't output absolute sections into the section table */ if (yasm_section_is_absolute(sect)) return 0; assert(info != NULL); xsd = yasm_section_get_data(sect, &xdf_section_data_cb); assert(xsd != NULL); last = yasm_section_bcs_last(sect); if (xsd->flags & XDF_SECT_BSS) { /* Don't output BSS sections. * TODO: Check for non-reserve bytecodes? */ pos = 0; /* position = 0 because it's not in the file */ xsd->size = last->offset + last->len; } else { pos = ftell(info->f); if (pos == -1) { yasm__fatal(N_("could not get file position on output file")); /*@notreached@*/ return 1; } info->sect = sect; info->xsd = xsd; yasm_section_bcs_traverse(sect, info, xdf_objfmt_output_bytecode); /* Sanity check final section size */ if (xsd->size != (last->offset + last->len)) yasm_internal_error( N_("xdf: section computed size did not match actual size")); } /* Empty? Go on to next section */ if (xsd->size == 0) return 0; xsd->scnptr = (unsigned long)pos; /* No relocations to output? Go on to next section */ if (xsd->nreloc == 0) return 0; pos = ftell(info->f); if (pos == -1) { yasm__fatal(N_("could not get file position on output file")); /*@notreached@*/ return 1; } xsd->relptr = (unsigned long)pos; reloc = (xdf_reloc *)yasm_section_relocs_first(sect); while (reloc) { unsigned char *localbuf = info->buf; /*@null@*/ xdf_symrec_data *xsymd; xsymd = yasm_symrec_get_data(reloc->reloc.sym, &xdf_symrec_data_cb); if (!xsymd) yasm_internal_error( N_("xdf: no symbol data for relocated symbol")); yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0, 0); localbuf += 4; /* address of relocation */ YASM_WRITE_32_L(localbuf, xsymd->index); /* relocated symbol */ if (reloc->base) { xsymd = yasm_symrec_get_data(reloc->base, &xdf_symrec_data_cb); if (!xsymd) yasm_internal_error( N_("xdf: no symbol data for relocated base symbol")); YASM_WRITE_32_L(localbuf, xsymd->index); /* base symbol */ } else { if (reloc->type == XDF_RELOC_WRT) yasm_internal_error( N_("xdf: no base symbol for WRT relocation")); YASM_WRITE_32_L(localbuf, 0); /* no base symbol */ } YASM_WRITE_8(localbuf, reloc->type); /* type of relocation */ YASM_WRITE_8(localbuf, reloc->size); /* size of relocation */ YASM_WRITE_8(localbuf, reloc->shift); /* relocation shift */ YASM_WRITE_8(localbuf, 0); /* flags */ fwrite(info->buf, 16, 1, info->f); reloc = (xdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc); } return 0;}static intxdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d){
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -