diff options
author | somov <somov@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
commit | a5950576e397b1909261050b8c7da16db58f10b1 (patch) | |
tree | 7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c | |
parent | 81eddc8c0b55990194e112b02d127b87d54164a9 (diff) | |
download | ydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz |
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c')
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c | 1684 |
1 files changed, 842 insertions, 842 deletions
diff --git a/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c b/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c index 9ad0e60afa..b2ac442511 100644 --- a/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c +++ b/contrib/tools/yasm/modules/objfmts/xdf/xdf-objfmt.c @@ -1,842 +1,842 @@ -/* - * Extended Dynamic Object format - * - * Copyright (C) 2004-2007 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> - -#include <libyasm.h> - - -#define REGULAR_OUTBUF_SIZE 1024 - -#define XDF_MAGIC 0x87654322 - -#define XDF_SYM_EXTERN 1 -#define XDF_SYM_GLOBAL 2 -#define XDF_SYM_EQU 4 - -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 */ - yasm_intnum *vaddr; /* starting virtual address */ - long scnum; /* section number (0=first section) */ - 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 */ -} xdf_section_data; - -typedef struct xdf_symrec_data { - unsigned long index; /* assigned XDF symbol table index */ -} xdf_symrec_data; - -typedef struct yasm_objfmt_xdf { - yasm_objfmt_base objfmt; /* base structure */ - - long parse_scnum; /* sect numbering in parser */ -} yasm_objfmt_xdf; - -typedef struct xdf_objfmt_output_info { - yasm_object *object; - yasm_objfmt_xdf *objfmt_xdf; - yasm_errwarns *errwarns; - /*@dependent@*/ FILE *f; - /*@only@*/ unsigned char *buf; - yasm_section *sect; - /*@dependent@*/ xdf_section_data *xsd; - - unsigned long indx; /* current symbol index */ - int all_syms; /* outputting all symbols? */ - unsigned long strtab_offset; /* current string table offset */ -} 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 yasm_objfmt * -xdf_objfmt_create(yasm_object *object) -{ - yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf)); - - /* Only support x86 arch */ - if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) { - yasm_xfree(objfmt_xdf); - return NULL; - } - - /* Support x86 and amd64 machines of x86 arch */ - if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") && - yasm__strcasecmp(yasm_arch_get_machine(object->arch), "amd64")) { - yasm_xfree(objfmt_xdf); - return NULL; - } - - objfmt_xdf->parse_scnum = 0; /* section numbering starts at 0 */ - - objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt; - - return (yasm_objfmt *)objfmt_xdf; -} - -static int -xdf_objfmt_output_value(yasm_value *value, unsigned char *buf, - unsigned int destsize, unsigned long offset, - yasm_bytecode *bc, int warn, /*@null@*/ void *d) -{ - /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; - /*@dependent@*/ /*@null@*/ yasm_intnum *intn; - unsigned long intn_minus; - int retval; - unsigned int valsize = value->size; - - assert(info != NULL); - - if (value->abs) - value->abs = yasm_expr_simplify(value->abs, 1); - - /* Try to output constant and PC-relative section-local first. - * Note this does NOT output any value with a SEG, WRT, external, - * cross-section, or non-PC-relative reference (those are handled below). - */ - switch (yasm_value_output_basic(value, buf, destsize, bc, warn, - info->object->arch)) { - case -1: - return 1; - case 0: - break; - default: - return 0; - } - - if (value->section_rel) { - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("xdf: relocation too complex")); - return 1; - } - - intn_minus = 0; - if (value->rel) { - xdf_reloc *reloc; - - reloc = yasm_xmalloc(sizeof(xdf_reloc)); - reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); - reloc->reloc.sym = value->rel; - reloc->base = NULL; - reloc->size = valsize/8; - reloc->shift = value->rshift; - - if (value->seg_of) - reloc->type = XDF_RELOC_SEG; - else if (value->wrt) { - reloc->base = value->wrt; - reloc->type = XDF_RELOC_WRT; - } else if (value->curpos_rel) { - reloc->type = XDF_RELOC_RIP; - /* Adjust to start of section, so subtract out the bytecode - * offset. - */ - intn_minus = bc->offset; - } else - reloc->type = XDF_RELOC_REL; - info->xsd->nreloc++; - yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); - } - - if (intn_minus > 0) { - intn = yasm_intnum_create_uint(intn_minus); - yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); - } else - intn = yasm_intnum_create_uint(0); - - if (value->abs) { - yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); - if (!intn2) { - yasm_error_set(YASM_ERROR_TOO_COMPLEX, - N_("xdf: relocation too complex")); - yasm_intnum_destroy(intn); - return 1; - } - yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); - } - - retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, - valsize, 0, bc, warn); - yasm_intnum_destroy(intn); - return retval; -} - -static int -xdf_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; - int gap; - - assert(info != NULL); - - bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, - xdf_objfmt_output_value, 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 += size; - - /* Warn that gaps are converted to 0 and write out the 0's. */ - if (gap) { - unsigned long left; - yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, - N_("uninitialized space: zeroing")); - /* Write out in chunks */ - memset(info->buf, 0, REGULAR_OUTBUF_SIZE); - left = 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 buf (or bigbuf if non-NULL) to file */ - 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 int -xdf_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; - - assert(info != NULL); - xsd = yasm_section_get_data(sect, &xdf_section_data_cb); - assert(xsd != NULL); - - 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 = yasm_bc_next_offset(yasm_section_bcs_last(sect)); - } 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->errwarns, info, - xdf_objfmt_output_bytecode); - - /* Sanity check final section size */ - if (xsd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect))) - 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); - 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 int -xdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) -{ - /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; - /*@dependent@*/ /*@null@*/ xdf_section_data *xsd; - /*@null@*/ xdf_symrec_data *xsymd; - unsigned char *localbuf; - - assert(info != NULL); - xsd = yasm_section_get_data(sect, &xdf_section_data_cb); - assert(xsd != NULL); - - localbuf = info->buf; - xsymd = yasm_symrec_get_data(xsd->sym, &xdf_symrec_data_cb); - assert(xsymd != NULL); - - YASM_WRITE_32_L(localbuf, xsymd->index); /* section name symbol */ - if (xsd->addr) { - yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); - localbuf += 8; /* physical address */ - } else { - YASM_WRITE_32_L(localbuf, 0); - YASM_WRITE_32_L(localbuf, 0); - } - if (xsd->vaddr) { - yasm_intnum_get_sized(xsd->vaddr, localbuf, 8, 64, 0, 0, 0); - localbuf += 8; /* virtual address */ - } else if (xsd->addr) { - yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); - localbuf += 8; /* VA=PA */ - } else { - YASM_WRITE_32_L(localbuf, 0); - YASM_WRITE_32_L(localbuf, 0); - } - YASM_WRITE_16_L(localbuf, yasm_section_get_align(sect)); /* alignment */ - YASM_WRITE_16_L(localbuf, xsd->flags); /* flags */ - YASM_WRITE_32_L(localbuf, xsd->scnptr); /* file ptr to data */ - YASM_WRITE_32_L(localbuf, xsd->size); /* section size */ - YASM_WRITE_32_L(localbuf, xsd->relptr); /* file ptr to relocs */ - YASM_WRITE_32_L(localbuf, xsd->nreloc); /* num of relocation entries */ - fwrite(info->buf, 40, 1, info->f); - - return 0; -} - -static int -xdf_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d) -{ - /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; - yasm_sym_vis vis = yasm_symrec_get_visibility(sym); - assert(info != NULL); - if (vis & YASM_SYM_COMMON) { - yasm_error_set(YASM_ERROR_GENERAL, - N_("XDF object format does not support common variables")); - yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); - return 0; - } - if (info->all_syms || - (vis != YASM_SYM_LOCAL && !(vis & YASM_SYM_DLOCAL))) { - /* Save index in symrec data */ - xdf_symrec_data *sym_data = yasm_xmalloc(sizeof(xdf_symrec_data)); - sym_data->index = info->indx; - yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data); - - info->indx++; - } - return 0; -} - -static int -xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) -{ - /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; - yasm_sym_vis vis = yasm_symrec_get_visibility(sym); - - assert(info != NULL); - - if (info->all_syms || vis != YASM_SYM_LOCAL) { - /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); - const yasm_expr *equ_val; - const yasm_intnum *intn; - size_t len = strlen(name); - unsigned long value = 0; - long scnum = -3; /* -3 = debugging symbol */ - /*@dependent@*/ /*@null@*/ yasm_section *sect; - /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; - unsigned long flags = 0; - unsigned char *localbuf; - - if (vis & YASM_SYM_GLOBAL) - flags = XDF_SYM_GLOBAL; - - /* Look at symrec for value/scnum/etc. */ - if (yasm_symrec_get_label(sym, &precbc)) { - if (precbc) - sect = yasm_bc_get_section(precbc); - else - sect = NULL; - /* it's a label: get value and offset. - * If there is not a section, leave as debugging symbol. - */ - if (sect) { - /*@dependent@*/ /*@null@*/ xdf_section_data *csectd; - csectd = yasm_section_get_data(sect, &xdf_section_data_cb); - if (csectd) - scnum = csectd->scnum; - else - yasm_internal_error(N_("didn't understand section")); - if (precbc) - value += yasm_bc_next_offset(precbc); - } - } else if ((equ_val = yasm_symrec_get_equ(sym))) { - yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); - intn = yasm_expr_get_intnum(&equ_val_copy, 1); - if (!intn) { - if (vis & YASM_SYM_GLOBAL) { - yasm_error_set(YASM_ERROR_NOT_CONSTANT, - N_("global EQU value not an integer expression")); - yasm_errwarn_propagate(info->errwarns, equ_val->line); - } - } else - value = yasm_intnum_get_uint(intn); - yasm_expr_destroy(equ_val_copy); - - flags |= XDF_SYM_EQU; - scnum = -2; /* -2 = absolute symbol */ - } else { - if (vis & YASM_SYM_EXTERN) { - flags = XDF_SYM_EXTERN; - scnum = -1; - } - } - - localbuf = info->buf; - YASM_WRITE_32_L(localbuf, scnum); /* section number */ - YASM_WRITE_32_L(localbuf, value); /* value */ - YASM_WRITE_32_L(localbuf, info->strtab_offset); - info->strtab_offset += (unsigned long)(len+1); - YASM_WRITE_32_L(localbuf, flags); /* flags */ - fwrite(info->buf, 16, 1, info->f); - yasm_xfree(name); - } - return 0; -} - -static int -xdf_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d) -{ - /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; - yasm_sym_vis vis = yasm_symrec_get_visibility(sym); - - assert(info != NULL); - - if (info->all_syms || vis != YASM_SYM_LOCAL) { - /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); - size_t len = strlen(name); - fwrite(name, len+1, 1, info->f); - yasm_xfree(name); - } - return 0; -} - -static void -xdf_objfmt_output(yasm_object *object, FILE *f, int all_syms, - yasm_errwarns *errwarns) -{ - yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; - xdf_objfmt_output_info info; - unsigned char *localbuf; - unsigned long symtab_count = 0; - - info.object = object; - info.objfmt_xdf = objfmt_xdf; - info.errwarns = errwarns; - info.f = f; - info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); - - /* Allocate space for headers by seeking forward */ - if (fseek(f, (long)(16+40*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) { - yasm__fatal(N_("could not seek on output file")); - /*@notreached@*/ - return; - } - - /* Get number of symbols */ - info.indx = 0; - info.all_syms = 1; /* force all syms into symbol table */ - yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_count_sym); - symtab_count = info.indx; - - /* Get file offset of start of string table */ - info.strtab_offset = 16+40*(objfmt_xdf->parse_scnum)+16*symtab_count; - - /* Output symbol table */ - yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_sym); - - /* Output string table */ - yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_str); - - /* Section data/relocs */ - if (yasm_object_sections_traverse(object, &info, - xdf_objfmt_output_section)) - return; - - /* Write headers */ - if (fseek(f, 0, SEEK_SET) < 0) { - yasm__fatal(N_("could not seek on output file")); - /*@notreached@*/ - return; - } - - localbuf = info.buf; - YASM_WRITE_32_L(localbuf, XDF_MAGIC); /* magic number */ - YASM_WRITE_32_L(localbuf, objfmt_xdf->parse_scnum); /* number of sects */ - YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */ - /* size of sect headers + symbol table + strings */ - YASM_WRITE_32_L(localbuf, info.strtab_offset-16); - fwrite(info.buf, 16, 1, f); - - yasm_object_sections_traverse(object, &info, xdf_objfmt_output_secthead); - - yasm_xfree(info.buf); -} - -static void -xdf_objfmt_destroy(yasm_objfmt *objfmt) -{ - yasm_xfree(objfmt); -} - -static void -xdf_objfmt_init_new_section(yasm_section *sect, unsigned long line) -{ - yasm_object *object = yasm_section_get_object(sect); - const char *sectname = yasm_section_get_name(sect); - yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; - xdf_section_data *data; - yasm_symrec *sym; - - data = yasm_xmalloc(sizeof(xdf_section_data)); - data->scnum = objfmt_xdf->parse_scnum++; - data->flags = 0; - data->addr = NULL; - data->vaddr = NULL; - data->scnptr = 0; - data->size = 0; - data->relptr = 0; - data->nreloc = 0; - yasm_section_add_data(sect, &xdf_section_data_cb, data); - - sym = yasm_symtab_define_label(object->symtab, sectname, - yasm_section_bcs_first(sect), 1, line); - data->sym = sym; -} - -static yasm_section * -xdf_objfmt_add_default_section(yasm_object *object) -{ - yasm_section *retval; - int isnew; - - retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); - if (isnew) - yasm_section_set_default(retval, 1); - return retval; -} - -static int -xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d, - uintptr_t bits) -{ - yasm_object *object = (yasm_object *)obj; - unsigned long *flags = (unsigned long *)d; - *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64); - switch (bits) { - case 16: *flags |= XDF_SECT_USE_16; break; - case 32: *flags |= XDF_SECT_USE_32; break; - case 64: *flags |= XDF_SECT_USE_64; break; - }; - yasm_arch_set_var(object->arch, "mode_bits", bits); - return 0; -} - -static /*@observer@*/ /*@null@*/ yasm_section * -xdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, - /*@unused@*/ /*@null@*/ - yasm_valparamhead *objext_valparams, - unsigned long line) -{ - yasm_valparam *vp; - yasm_section *retval; - int isnew; - int flags_override = 0; - const char *sectname; - int resonly = 0; - xdf_section_data *xsd; - unsigned long align = 0; - - struct xdf_section_switch_data { - /*@only@*/ /*@null@*/ yasm_intnum *absaddr; - /*@only@*/ /*@null@*/ yasm_intnum *vaddr; - /*@only@*/ /*@null@*/ yasm_intnum *align_intn; - unsigned long flags; - } data; - - static const yasm_dir_help help[] = { - { "use16", 0, xdf_helper_use, - offsetof(struct xdf_section_switch_data, flags), 16 }, - { "use32", 0, xdf_helper_use, - offsetof(struct xdf_section_switch_data, flags), 32 }, - { "use64", 0, xdf_helper_use, - offsetof(struct xdf_section_switch_data, flags), 64 }, - { "bss", 0, yasm_dir_helper_flag_or, - offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS }, - { "flat", 0, yasm_dir_helper_flag_or, - offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT }, - { "absolute", 1, yasm_dir_helper_intn, - offsetof(struct xdf_section_switch_data, absaddr), 0 }, - { "virtual", 1, yasm_dir_helper_intn, - offsetof(struct xdf_section_switch_data, vaddr), 0 }, - { "align", 1, yasm_dir_helper_intn, - offsetof(struct xdf_section_switch_data, align_intn), 0 } - }; - - data.absaddr = NULL; - data.vaddr = NULL; - data.align_intn = NULL; - data.flags = 0; - - vp = yasm_vps_first(valparams); - sectname = yasm_vp_string(vp); - if (!sectname) - return NULL; - vp = yasm_vps_next(vp); - - flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), - &data, yasm_dir_helper_valparam_warn); - if (flags_override < 0) - return NULL; /* error occurred */ - - if (data.absaddr) - data.flags |= XDF_SECT_ABSOLUTE; - if (data.align_intn) { - align = yasm_intnum_get_uint(data.align_intn); - yasm_intnum_destroy(data.align_intn); - - /* Alignments must be a power of two. */ - if (!is_exp2(align)) { - yasm_error_set(YASM_ERROR_VALUE, - N_("argument to `%s' is not a power of two"), - "align"); - if (data.vaddr) - yasm_intnum_destroy(data.vaddr); - if (data.absaddr) - yasm_intnum_destroy(data.absaddr); - return NULL; - } - - /* Check to see if alignment is supported size */ - if (align > 4096) { - yasm_error_set(YASM_ERROR_VALUE, - N_("XDF does not support alignments > 4096")); - if (data.vaddr) - yasm_intnum_destroy(data.vaddr); - if (data.absaddr) - yasm_intnum_destroy(data.absaddr); - return NULL; - } - } - - retval = yasm_object_get_general(object, sectname, align, 1, resonly, - &isnew, line); - - xsd = yasm_section_get_data(retval, &xdf_section_data_cb); - - if (isnew || yasm_section_is_default(retval)) { - yasm_section_set_default(retval, 0); - xsd->flags = data.flags; - if (data.absaddr) { - if (xsd->addr) - yasm_intnum_destroy(xsd->addr); - xsd->addr = data.absaddr; - } - if (data.vaddr) { - if (xsd->vaddr) - yasm_intnum_destroy(xsd->vaddr); - xsd->vaddr = data.vaddr; - } - yasm_section_set_align(retval, align, line); - } else if (flags_override) - yasm_warn_set(YASM_WARN_GENERAL, - N_("section flags ignored on section redeclaration")); - return retval; -} - -static /*@observer@*/ /*@null@*/ yasm_symrec * -xdf_objfmt_get_special_sym(yasm_object *object, const char *name, - const char *parser) -{ - return NULL; -} - -static void -xdf_section_data_destroy(void *data) -{ - xdf_section_data *xsd = (xdf_section_data *)data; - if (xsd->addr) - yasm_intnum_destroy(xsd->addr); - if (xsd->vaddr) - yasm_intnum_destroy(xsd->vaddr); - yasm_xfree(data); -} - -static void -xdf_section_data_print(void *data, FILE *f, int indent_level) -{ - xdf_section_data *xsd = (xdf_section_data *)data; - - fprintf(f, "%*ssym=\n", indent_level, ""); - yasm_symrec_print(xsd->sym, f, indent_level+1); - fprintf(f, "%*sscnum=%ld\n", indent_level, "", xsd->scnum); - fprintf(f, "%*sflags=0x%x\n", indent_level, "", xsd->flags); - fprintf(f, "%*saddr=", indent_level, ""); - yasm_intnum_print(xsd->addr, f); - fprintf(f, "%*svaddr=", indent_level, ""); - yasm_intnum_print(xsd->vaddr, f); - fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", xsd->scnptr); - fprintf(f, "%*ssize=%ld\n", indent_level, "", xsd->size); - fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", xsd->relptr); - fprintf(f, "%*snreloc=%ld\n", indent_level, "", xsd->nreloc); -} - -static void -xdf_symrec_data_destroy(void *data) -{ - yasm_xfree(data); -} - -static void -xdf_symrec_data_print(void *data, FILE *f, int indent_level) -{ - xdf_symrec_data *xsd = (xdf_symrec_data *)data; - - fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", xsd->index); -} - -/* Define valid debug formats to use with this object format */ -static const char *xdf_objfmt_dbgfmt_keywords[] = { - "null", - NULL -}; - -/* Define objfmt structure -- see objfmt.h for details */ -yasm_objfmt_module yasm_xdf_LTX_objfmt = { - "Extended Dynamic Object", - "xdf", - "xdf", - 32, - 0, - xdf_objfmt_dbgfmt_keywords, - "null", - NULL, /* no directives */ - NULL, /* no standard macros */ - xdf_objfmt_create, - xdf_objfmt_output, - xdf_objfmt_destroy, - xdf_objfmt_add_default_section, - xdf_objfmt_init_new_section, - xdf_objfmt_section_switch, - xdf_objfmt_get_special_sym -}; +/* + * Extended Dynamic Object format + * + * Copyright (C) 2004-2007 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> + +#include <libyasm.h> + + +#define REGULAR_OUTBUF_SIZE 1024 + +#define XDF_MAGIC 0x87654322 + +#define XDF_SYM_EXTERN 1 +#define XDF_SYM_GLOBAL 2 +#define XDF_SYM_EQU 4 + +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 */ + yasm_intnum *vaddr; /* starting virtual address */ + long scnum; /* section number (0=first section) */ + 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 */ +} xdf_section_data; + +typedef struct xdf_symrec_data { + unsigned long index; /* assigned XDF symbol table index */ +} xdf_symrec_data; + +typedef struct yasm_objfmt_xdf { + yasm_objfmt_base objfmt; /* base structure */ + + long parse_scnum; /* sect numbering in parser */ +} yasm_objfmt_xdf; + +typedef struct xdf_objfmt_output_info { + yasm_object *object; + yasm_objfmt_xdf *objfmt_xdf; + yasm_errwarns *errwarns; + /*@dependent@*/ FILE *f; + /*@only@*/ unsigned char *buf; + yasm_section *sect; + /*@dependent@*/ xdf_section_data *xsd; + + unsigned long indx; /* current symbol index */ + int all_syms; /* outputting all symbols? */ + unsigned long strtab_offset; /* current string table offset */ +} 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 yasm_objfmt * +xdf_objfmt_create(yasm_object *object) +{ + yasm_objfmt_xdf *objfmt_xdf = yasm_xmalloc(sizeof(yasm_objfmt_xdf)); + + /* Only support x86 arch */ + if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) { + yasm_xfree(objfmt_xdf); + return NULL; + } + + /* Support x86 and amd64 machines of x86 arch */ + if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") && + yasm__strcasecmp(yasm_arch_get_machine(object->arch), "amd64")) { + yasm_xfree(objfmt_xdf); + return NULL; + } + + objfmt_xdf->parse_scnum = 0; /* section numbering starts at 0 */ + + objfmt_xdf->objfmt.module = &yasm_xdf_LTX_objfmt; + + return (yasm_objfmt *)objfmt_xdf; +} + +static int +xdf_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_minus; + int retval; + unsigned int valsize = value->size; + + assert(info != NULL); + + if (value->abs) + value->abs = yasm_expr_simplify(value->abs, 1); + + /* Try to output constant and PC-relative section-local first. + * Note this does NOT output any value with a SEG, WRT, external, + * cross-section, or non-PC-relative reference (those are handled below). + */ + switch (yasm_value_output_basic(value, buf, destsize, bc, warn, + info->object->arch)) { + case -1: + return 1; + case 0: + break; + default: + return 0; + } + + if (value->section_rel) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("xdf: relocation too complex")); + return 1; + } + + intn_minus = 0; + if (value->rel) { + xdf_reloc *reloc; + + reloc = yasm_xmalloc(sizeof(xdf_reloc)); + reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset); + reloc->reloc.sym = value->rel; + reloc->base = NULL; + reloc->size = valsize/8; + reloc->shift = value->rshift; + + if (value->seg_of) + reloc->type = XDF_RELOC_SEG; + else if (value->wrt) { + reloc->base = value->wrt; + reloc->type = XDF_RELOC_WRT; + } else if (value->curpos_rel) { + reloc->type = XDF_RELOC_RIP; + /* Adjust to start of section, so subtract out the bytecode + * offset. + */ + intn_minus = bc->offset; + } else + reloc->type = XDF_RELOC_REL; + info->xsd->nreloc++; + yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); + } + + if (intn_minus > 0) { + intn = yasm_intnum_create_uint(intn_minus); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + } else + intn = yasm_intnum_create_uint(0); + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("xdf: relocation too complex")); + yasm_intnum_destroy(intn); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(intn); + return retval; +} + +static int +xdf_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; + int gap; + + assert(info != NULL); + + bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info, + xdf_objfmt_output_value, 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 += size; + + /* Warn that gaps are converted to 0 and write out the 0's. */ + if (gap) { + unsigned long left; + yasm_warn_set(YASM_WARN_UNINIT_CONTENTS, + N_("uninitialized space: zeroing")); + /* Write out in chunks */ + memset(info->buf, 0, REGULAR_OUTBUF_SIZE); + left = 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 buf (or bigbuf if non-NULL) to file */ + 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 int +xdf_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; + + assert(info != NULL); + xsd = yasm_section_get_data(sect, &xdf_section_data_cb); + assert(xsd != NULL); + + 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 = yasm_bc_next_offset(yasm_section_bcs_last(sect)); + } 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->errwarns, info, + xdf_objfmt_output_bytecode); + + /* Sanity check final section size */ + if (xsd->size != yasm_bc_next_offset(yasm_section_bcs_last(sect))) + 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); + 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 int +xdf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ xdf_section_data *xsd; + /*@null@*/ xdf_symrec_data *xsymd; + unsigned char *localbuf; + + assert(info != NULL); + xsd = yasm_section_get_data(sect, &xdf_section_data_cb); + assert(xsd != NULL); + + localbuf = info->buf; + xsymd = yasm_symrec_get_data(xsd->sym, &xdf_symrec_data_cb); + assert(xsymd != NULL); + + YASM_WRITE_32_L(localbuf, xsymd->index); /* section name symbol */ + if (xsd->addr) { + yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); + localbuf += 8; /* physical address */ + } else { + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + } + if (xsd->vaddr) { + yasm_intnum_get_sized(xsd->vaddr, localbuf, 8, 64, 0, 0, 0); + localbuf += 8; /* virtual address */ + } else if (xsd->addr) { + yasm_intnum_get_sized(xsd->addr, localbuf, 8, 64, 0, 0, 0); + localbuf += 8; /* VA=PA */ + } else { + YASM_WRITE_32_L(localbuf, 0); + YASM_WRITE_32_L(localbuf, 0); + } + YASM_WRITE_16_L(localbuf, yasm_section_get_align(sect)); /* alignment */ + YASM_WRITE_16_L(localbuf, xsd->flags); /* flags */ + YASM_WRITE_32_L(localbuf, xsd->scnptr); /* file ptr to data */ + YASM_WRITE_32_L(localbuf, xsd->size); /* section size */ + YASM_WRITE_32_L(localbuf, xsd->relptr); /* file ptr to relocs */ + YASM_WRITE_32_L(localbuf, xsd->nreloc); /* num of relocation entries */ + fwrite(info->buf, 40, 1, info->f); + + return 0; +} + +static int +xdf_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + assert(info != NULL); + if (vis & YASM_SYM_COMMON) { + yasm_error_set(YASM_ERROR_GENERAL, + N_("XDF object format does not support common variables")); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + return 0; + } + if (info->all_syms || + (vis != YASM_SYM_LOCAL && !(vis & YASM_SYM_DLOCAL))) { + /* Save index in symrec data */ + xdf_symrec_data *sym_data = yasm_xmalloc(sizeof(xdf_symrec_data)); + sym_data->index = info->indx; + yasm_symrec_add_data(sym, &xdf_symrec_data_cb, sym_data); + + info->indx++; + } + return 0; +} + +static int +xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + + assert(info != NULL); + + if (info->all_syms || vis != YASM_SYM_LOCAL) { + /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); + const yasm_expr *equ_val; + const yasm_intnum *intn; + size_t len = strlen(name); + unsigned long value = 0; + long scnum = -3; /* -3 = debugging symbol */ + /*@dependent@*/ /*@null@*/ yasm_section *sect; + /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; + unsigned long flags = 0; + unsigned char *localbuf; + + if (vis & YASM_SYM_GLOBAL) + flags = XDF_SYM_GLOBAL; + + /* Look at symrec for value/scnum/etc. */ + if (yasm_symrec_get_label(sym, &precbc)) { + if (precbc) + sect = yasm_bc_get_section(precbc); + else + sect = NULL; + /* it's a label: get value and offset. + * If there is not a section, leave as debugging symbol. + */ + if (sect) { + /*@dependent@*/ /*@null@*/ xdf_section_data *csectd; + csectd = yasm_section_get_data(sect, &xdf_section_data_cb); + if (csectd) + scnum = csectd->scnum; + else + yasm_internal_error(N_("didn't understand section")); + if (precbc) + value += yasm_bc_next_offset(precbc); + } + } else if ((equ_val = yasm_symrec_get_equ(sym))) { + yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); + intn = yasm_expr_get_intnum(&equ_val_copy, 1); + if (!intn) { + if (vis & YASM_SYM_GLOBAL) { + yasm_error_set(YASM_ERROR_NOT_CONSTANT, + N_("global EQU value not an integer expression")); + yasm_errwarn_propagate(info->errwarns, equ_val->line); + } + } else + value = yasm_intnum_get_uint(intn); + yasm_expr_destroy(equ_val_copy); + + flags |= XDF_SYM_EQU; + scnum = -2; /* -2 = absolute symbol */ + } else { + if (vis & YASM_SYM_EXTERN) { + flags = XDF_SYM_EXTERN; + scnum = -1; + } + } + + localbuf = info->buf; + YASM_WRITE_32_L(localbuf, scnum); /* section number */ + YASM_WRITE_32_L(localbuf, value); /* value */ + YASM_WRITE_32_L(localbuf, info->strtab_offset); + info->strtab_offset += (unsigned long)(len+1); + YASM_WRITE_32_L(localbuf, flags); /* flags */ + fwrite(info->buf, 16, 1, info->f); + yasm_xfree(name); + } + return 0; +} + +static int +xdf_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d) +{ + /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + + assert(info != NULL); + + if (info->all_syms || vis != YASM_SYM_LOCAL) { + /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); + size_t len = strlen(name); + fwrite(name, len+1, 1, info->f); + yasm_xfree(name); + } + return 0; +} + +static void +xdf_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; + xdf_objfmt_output_info info; + unsigned char *localbuf; + unsigned long symtab_count = 0; + + info.object = object; + info.objfmt_xdf = objfmt_xdf; + info.errwarns = errwarns; + info.f = f; + info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE); + + /* Allocate space for headers by seeking forward */ + if (fseek(f, (long)(16+40*(objfmt_xdf->parse_scnum)), SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + /* Get number of symbols */ + info.indx = 0; + info.all_syms = 1; /* force all syms into symbol table */ + yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_count_sym); + symtab_count = info.indx; + + /* Get file offset of start of string table */ + info.strtab_offset = 16+40*(objfmt_xdf->parse_scnum)+16*symtab_count; + + /* Output symbol table */ + yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_sym); + + /* Output string table */ + yasm_symtab_traverse(object->symtab, &info, xdf_objfmt_output_str); + + /* Section data/relocs */ + if (yasm_object_sections_traverse(object, &info, + xdf_objfmt_output_section)) + return; + + /* Write headers */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm__fatal(N_("could not seek on output file")); + /*@notreached@*/ + return; + } + + localbuf = info.buf; + YASM_WRITE_32_L(localbuf, XDF_MAGIC); /* magic number */ + YASM_WRITE_32_L(localbuf, objfmt_xdf->parse_scnum); /* number of sects */ + YASM_WRITE_32_L(localbuf, symtab_count); /* number of symtabs */ + /* size of sect headers + symbol table + strings */ + YASM_WRITE_32_L(localbuf, info.strtab_offset-16); + fwrite(info.buf, 16, 1, f); + + yasm_object_sections_traverse(object, &info, xdf_objfmt_output_secthead); + + yasm_xfree(info.buf); +} + +static void +xdf_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_xfree(objfmt); +} + +static void +xdf_objfmt_init_new_section(yasm_section *sect, unsigned long line) +{ + yasm_object *object = yasm_section_get_object(sect); + const char *sectname = yasm_section_get_name(sect); + yasm_objfmt_xdf *objfmt_xdf = (yasm_objfmt_xdf *)object->objfmt; + xdf_section_data *data; + yasm_symrec *sym; + + data = yasm_xmalloc(sizeof(xdf_section_data)); + data->scnum = objfmt_xdf->parse_scnum++; + data->flags = 0; + data->addr = NULL; + data->vaddr = NULL; + data->scnptr = 0; + data->size = 0; + data->relptr = 0; + data->nreloc = 0; + yasm_section_add_data(sect, &xdf_section_data_cb, data); + + sym = yasm_symtab_define_label(object->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + data->sym = sym; +} + +static yasm_section * +xdf_objfmt_add_default_section(yasm_object *object) +{ + yasm_section *retval; + int isnew; + + retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0); + if (isnew) + yasm_section_set_default(retval, 1); + return retval; +} + +static int +xdf_helper_use(void *obj, yasm_valparam *vp, unsigned long line, void *d, + uintptr_t bits) +{ + yasm_object *object = (yasm_object *)obj; + unsigned long *flags = (unsigned long *)d; + *flags &= ~(XDF_SECT_USE_16|XDF_SECT_USE_32|XDF_SECT_USE_64); + switch (bits) { + case 16: *flags |= XDF_SECT_USE_16; break; + case 32: *flags |= XDF_SECT_USE_32; break; + case 64: *flags |= XDF_SECT_USE_64; break; + }; + yasm_arch_set_var(object->arch, "mode_bits", bits); + return 0; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +xdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@unused@*/ /*@null@*/ + yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_valparam *vp; + yasm_section *retval; + int isnew; + int flags_override = 0; + const char *sectname; + int resonly = 0; + xdf_section_data *xsd; + unsigned long align = 0; + + struct xdf_section_switch_data { + /*@only@*/ /*@null@*/ yasm_intnum *absaddr; + /*@only@*/ /*@null@*/ yasm_intnum *vaddr; + /*@only@*/ /*@null@*/ yasm_intnum *align_intn; + unsigned long flags; + } data; + + static const yasm_dir_help help[] = { + { "use16", 0, xdf_helper_use, + offsetof(struct xdf_section_switch_data, flags), 16 }, + { "use32", 0, xdf_helper_use, + offsetof(struct xdf_section_switch_data, flags), 32 }, + { "use64", 0, xdf_helper_use, + offsetof(struct xdf_section_switch_data, flags), 64 }, + { "bss", 0, yasm_dir_helper_flag_or, + offsetof(struct xdf_section_switch_data, flags), XDF_SECT_BSS }, + { "flat", 0, yasm_dir_helper_flag_or, + offsetof(struct xdf_section_switch_data, flags), XDF_SECT_FLAT }, + { "absolute", 1, yasm_dir_helper_intn, + offsetof(struct xdf_section_switch_data, absaddr), 0 }, + { "virtual", 1, yasm_dir_helper_intn, + offsetof(struct xdf_section_switch_data, vaddr), 0 }, + { "align", 1, yasm_dir_helper_intn, + offsetof(struct xdf_section_switch_data, align_intn), 0 } + }; + + data.absaddr = NULL; + data.vaddr = NULL; + data.align_intn = NULL; + data.flags = 0; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help), + &data, yasm_dir_helper_valparam_warn); + if (flags_override < 0) + return NULL; /* error occurred */ + + if (data.absaddr) + data.flags |= XDF_SECT_ABSOLUTE; + if (data.align_intn) { + align = yasm_intnum_get_uint(data.align_intn); + yasm_intnum_destroy(data.align_intn); + + /* Alignments must be a power of two. */ + if (!is_exp2(align)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("argument to `%s' is not a power of two"), + "align"); + if (data.vaddr) + yasm_intnum_destroy(data.vaddr); + if (data.absaddr) + yasm_intnum_destroy(data.absaddr); + return NULL; + } + + /* Check to see if alignment is supported size */ + if (align > 4096) { + yasm_error_set(YASM_ERROR_VALUE, + N_("XDF does not support alignments > 4096")); + if (data.vaddr) + yasm_intnum_destroy(data.vaddr); + if (data.absaddr) + yasm_intnum_destroy(data.absaddr); + return NULL; + } + } + + retval = yasm_object_get_general(object, sectname, align, 1, resonly, + &isnew, line); + + xsd = yasm_section_get_data(retval, &xdf_section_data_cb); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + xsd->flags = data.flags; + if (data.absaddr) { + if (xsd->addr) + yasm_intnum_destroy(xsd->addr); + xsd->addr = data.absaddr; + } + if (data.vaddr) { + if (xsd->vaddr) + yasm_intnum_destroy(xsd->vaddr); + xsd->vaddr = data.vaddr; + } + yasm_section_set_align(retval, align, line); + } else if (flags_override) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +xdf_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + return NULL; +} + +static void +xdf_section_data_destroy(void *data) +{ + xdf_section_data *xsd = (xdf_section_data *)data; + if (xsd->addr) + yasm_intnum_destroy(xsd->addr); + if (xsd->vaddr) + yasm_intnum_destroy(xsd->vaddr); + yasm_xfree(data); +} + +static void +xdf_section_data_print(void *data, FILE *f, int indent_level) +{ + xdf_section_data *xsd = (xdf_section_data *)data; + + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(xsd->sym, f, indent_level+1); + fprintf(f, "%*sscnum=%ld\n", indent_level, "", xsd->scnum); + fprintf(f, "%*sflags=0x%x\n", indent_level, "", xsd->flags); + fprintf(f, "%*saddr=", indent_level, ""); + yasm_intnum_print(xsd->addr, f); + fprintf(f, "%*svaddr=", indent_level, ""); + yasm_intnum_print(xsd->vaddr, f); + fprintf(f, "%*sscnptr=0x%lx\n", indent_level, "", xsd->scnptr); + fprintf(f, "%*ssize=%ld\n", indent_level, "", xsd->size); + fprintf(f, "%*srelptr=0x%lx\n", indent_level, "", xsd->relptr); + fprintf(f, "%*snreloc=%ld\n", indent_level, "", xsd->nreloc); +} + +static void +xdf_symrec_data_destroy(void *data) +{ + yasm_xfree(data); +} + +static void +xdf_symrec_data_print(void *data, FILE *f, int indent_level) +{ + xdf_symrec_data *xsd = (xdf_symrec_data *)data; + + fprintf(f, "%*ssymtab index=%lu\n", indent_level, "", xsd->index); +} + +/* Define valid debug formats to use with this object format */ +static const char *xdf_objfmt_dbgfmt_keywords[] = { + "null", + NULL +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_xdf_LTX_objfmt = { + "Extended Dynamic Object", + "xdf", + "xdf", + 32, + 0, + xdf_objfmt_dbgfmt_keywords, + "null", + NULL, /* no directives */ + NULL, /* no standard macros */ + xdf_objfmt_create, + xdf_objfmt_output, + xdf_objfmt_destroy, + xdf_objfmt_add_default_section, + xdf_objfmt_init_new_section, + xdf_objfmt_section_switch, + xdf_objfmt_get_special_sym +}; |