📄 bin-objfmt.c
字号:
/* * Flat-format binary 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: bin-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 1024static void bin_section_data_destroy(/*@only@*/ void *d);static void bin_section_data_print(void *data, FILE *f, int indent_level);static const yasm_assoc_data_callback bin_section_data_callback = { bin_section_data_destroy, bin_section_data_print};typedef struct yasm_objfmt_bin { yasm_objfmt_base objfmt; /* base structure */ yasm_object *object; yasm_symtab *symtab; /*@dependent@*/ yasm_arch *arch;} yasm_objfmt_bin;yasm_objfmt_module yasm_bin_LTX_objfmt;static yasm_objfmt *bin_objfmt_create(/*@unused@*/ const char *in_filename, yasm_object *object, yasm_arch *a){ yasm_objfmt_bin *objfmt_bin = yasm_xmalloc(sizeof(yasm_objfmt_bin)); objfmt_bin->objfmt.module = &yasm_bin_LTX_objfmt; objfmt_bin->object = object; objfmt_bin->symtab = yasm_object_get_symtab(object); objfmt_bin->arch = a; return (yasm_objfmt *)objfmt_bin;}/* Aligns sect to either its specified alignment (in its objfmt-specific data) * or def_align if no alignment was specified. Uses prevsect and base to both * determine the new starting address (returned) and the total length of * prevsect after sect has been aligned. */static unsigned longbin_objfmt_align_section(yasm_section *sect, yasm_section *prevsect, unsigned long base, unsigned long def_align, /*@out@*/ unsigned long *prevsectlen, /*@out@*/ unsigned long *padamt){ /*@dependent@*/ /*@null@*/ yasm_bytecode *last; unsigned long start; /*@dependent@*/ /*@null@*/ unsigned long *alignptr; unsigned long align; /* Figure out the size of .text by looking at the last bytecode's offset * plus its length. Add the start and size together to get the new start. */ last = yasm_section_bcs_last(prevsect); if (last) *prevsectlen = last->offset + last->len; else *prevsectlen = 0; start = base + *prevsectlen; /* Round new start up to alignment of .data section, and adjust textlen to * indicate padded size. Because aignment is always a power of two, we * can use some bit trickery to do this easily. */ alignptr = yasm_section_get_data(sect, &bin_section_data_callback); if (alignptr) align = *alignptr; else align = def_align; /* No alignment: use default */ if (start & (align-1)) start = (start & ~(align-1)) + align; *padamt = start - (base + *prevsectlen); return start;}typedef struct bin_objfmt_output_info { yasm_objfmt_bin *objfmt_bin; /*@dependent@*/ FILE *f; /*@only@*/ unsigned char *buf; /*@observer@*/ const yasm_section *sect; unsigned long start;} bin_objfmt_output_info;static /*@only@*/ yasm_expr *bin_objfmt_expr_xform(/*@returned@*/ /*@only@*/ yasm_expr *e, /*@unused@*/ /*@null@*/ void *d){ int i; /*@dependent@*/ yasm_section *sect; /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; /*@null@*/ yasm_intnum *dist; for (i=0; i<e->numterms; i++) { /* Transform symrecs that reference sections into * start expr + intnum(dist). */ if (e->terms[i].type == YASM_EXPR_SYM && yasm_symrec_get_label(e->terms[i].data.sym, &precbc) && (sect = yasm_bc_get_section(precbc)) && (dist = yasm_common_calc_bc_dist(yasm_section_bcs_first(sect), precbc))) { const yasm_expr *start = yasm_section_get_start(sect); e->terms[i].type = YASM_EXPR_EXPR; e->terms[i].data.expn = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(yasm_expr_copy(start)), yasm_expr_int(dist), e->line); } } return e;}static intbin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, size_t valsize, int shift, /*@unused@*/ unsigned long offset, yasm_bytecode *bc, int rel, int warn, /*@null@*/ void *d){ /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; /*@dependent@*/ /*@null@*/ yasm_intnum *intn; /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; assert(info != NULL); /* For binary output, this is trivial: any expression that doesn't simplify * to an integer is an error (references something external). * Other object formats need to generate their relocation list from here! */ *ep = yasm_expr__level_tree(*ep, 1, 1, NULL, bin_objfmt_expr_xform, NULL, NULL); /* 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_bin->arch, flt, buf, destsize, valsize, (unsigned int)shift, warn, bc->line); } /* Handle integer expressions */ intn = yasm_expr_get_intnum(ep, NULL); if (intn) { if (rel) { int retval = yasm_arch_intnum_fixup_rel(info->objfmt_bin->arch, intn, valsize, bc, bc->line); if (retval) return retval; } return yasm_arch_intnum_tobytes(info->objfmt_bin->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; } /* Couldn't output, assume it contains an external reference. */ yasm__error(bc->line, N_("binary object format does not support external references")); return 1;}static intbin_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d){ /*@null@*/ bin_objfmt_output_info *info = (bin_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, bin_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; } /* 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(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 voidbin_objfmt_output(yasm_objfmt *objfmt, FILE *f, const char *obj_filename, /*@unused@*/ int all_syms, /*@unused@*/ yasm_dbgfmt *df){ yasm_objfmt_bin *objfmt_bin = (yasm_objfmt_bin *)objfmt; /*@observer@*/ /*@null@*/ yasm_section *text, *data, *bss, *prevsect; /*@null@*/ yasm_expr *startexpr; /*@dependent@*/ /*@null@*/ const yasm_intnum *startnum; unsigned long start = 0, textstart = 0, datastart = 0; unsigned long textlen = 0, textpad = 0, datalen = 0, datapad = 0; unsigned long *prevsectlenptr, *prevsectpadptr; unsigned long i; bin_objfmt_output_info info; info.objfmt_bin = objfmt_bin; info.f = f; info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); text = yasm_object_find_general(objfmt_bin->object, ".text"); data = yasm_object_find_general(objfmt_bin->object, ".data"); bss = yasm_object_find_general(objfmt_bin->object, ".bss"); if (!text) yasm_internal_error(N_("No `.text' section in bin objfmt output")); /* First determine the actual starting offsets for .data and .bss. * As the order in the file is .text -> .data -> .bss (not present), * use the last bytecode in .text (and the .text section start) to * determine the starting offset in .data, and likewise for .bss. * Also compensate properly for alignment. */ /* Find out the start of .text */ startexpr = yasm_expr_copy(yasm_section_get_start(text));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -