diff options
Diffstat (limited to 'modules/objfmts/elf/elf-objfmt.c')
-rw-r--r-- | modules/objfmts/elf/elf-objfmt.c | 1365 |
1 files changed, 1365 insertions, 0 deletions
diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c new file mode 100644 index 0000000..1cf725f --- /dev/null +++ b/modules/objfmts/elf/elf-objfmt.c @@ -0,0 +1,1365 @@ +/* + * ELF object format + * + * Copyright (C) 2003-2007 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> + +/* 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. + */ + +#include <libyasm.h> + +#include "elf.h" +#include "elf-machine.h" + +typedef struct yasm_objfmt_elf { + yasm_objfmt_base objfmt; /* base structure */ + + elf_symtab_head* elf_symtab; /* symbol table of indexed syms */ + elf_strtab_head* shstrtab; /* section name strtab */ + elf_strtab_head* strtab; /* strtab entries */ + + elf_strtab_entry *file_strtab_entry;/* .file symbol associated string */ + yasm_symrec *dotdotsym; /* ..sym symbol */ +} yasm_objfmt_elf; + +typedef struct { + yasm_objfmt_elf *objfmt_elf; + yasm_errwarns *errwarns; + FILE *f; + elf_secthead *shead; + yasm_section *sect; + yasm_object *object; + unsigned long sindex; + yasm_symrec *GOT_sym; +} elf_objfmt_output_info; + +typedef struct { + yasm_object *object; + yasm_objfmt_elf *objfmt_elf; + yasm_errwarns *errwarns; + int local_names; +} build_symtab_info; + +yasm_objfmt_module yasm_elf_LTX_objfmt; +yasm_objfmt_module yasm_elf32_LTX_objfmt; +yasm_objfmt_module yasm_elf64_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, elf_symbol_vis vis, + yasm_expr *size, elf_address *value, + yasm_object *object) +{ + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + + if (!entry) { + /*@only@*/ char *symname = yasm_symrec_get_global_name(sym, object); + elf_strtab_entry *name = + elf_strtab_append_str(objfmt_elf->strtab, symname); + yasm_xfree(symname); + entry = elf_symtab_entry_create(name, sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + /* Only append to table if not already appended */ + if (!elf_sym_in_table(entry)) + elf_symtab_append_entry(objfmt_elf->elf_symtab, entry); + + elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value); + elf_sym_set_visibility(entry, vis); + + return entry; +} + +static elf_symtab_entry * +build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object) +{ + yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + if (yasm_vp_string(vp)) + yasm_error_set(YASM_ERROR_TYPE, + N_("unrecognized symbol type `%s'"), + yasm_vp_string(vp)); + } + } + + return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, 0, + STV_DEFAULT, NULL, NULL, object); +} + +struct elf_build_global_data { + yasm_expr *size; + unsigned long type; /* elf_symbol_type */ + elf_symbol_vis vis; + unsigned int vis_overrides; +}; + +static int +elf_global_helper_valparam(void *obj, yasm_valparam *vp, unsigned long line, + void *d) + +{ + struct elf_build_global_data *data = (struct elf_build_global_data *)d; + const char *s; + + if (!vp->val && (s = yasm_vp_id(vp))) { + yasm_error_set(YASM_ERROR_TYPE, N_("unrecognized symbol type `%s'"), + s); + return -1; + } else if (!vp->val && vp->type == YASM_PARAM_EXPR && !data->size) { + data->size = yasm_expr_copy(vp->param.e); + return 0; + } else + return yasm_dir_helper_valparam_warn(obj, vp, line, d); +} + +static int +elf_global_helper_vis(void *obj, yasm_valparam *vp, unsigned long line, + void *d, uintptr_t vis) +{ + struct elf_build_global_data *data = (struct elf_build_global_data *)d; + data->vis = vis; + data->vis_overrides++; + return 0; +} + + +static elf_symtab_entry * +build_global(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object) +{ + yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + + struct elf_build_global_data data; + + static const yasm_dir_help help[] = { + { "function", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_build_global_data, type), STT_FUNC }, + { "data", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_build_global_data, type), STT_OBJECT }, + { "object", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_build_global_data, type), STT_OBJECT }, + { "internal", 0, elf_global_helper_vis, 0, STV_INTERNAL }, + { "hidden", 0, elf_global_helper_vis, 0, STV_HIDDEN }, + { "protected", 0, elf_global_helper_vis, 0, STV_PROTECTED }, + }; + + data.size = NULL; + data.type = 0; + data.vis = STV_DEFAULT; + data.vis_overrides = 0; + + if (objext_valparams) + yasm_dir_helper(sym, yasm_vps_first(objext_valparams), + yasm_symrec_get_decl_line(sym), help, NELEMS(help), + &data, elf_global_helper_valparam); + + if (data.vis_overrides > 1) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("More than one symbol visibility provided; using last")); + } + + return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, + data.type, data.vis, data.size, NULL, + object); +} + +static /*@null@*/ elf_symtab_entry * +build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object) +{ + yasm_expr **size = yasm_symrec_get_common_size(sym); + yasm_valparamhead *objext_valparams = + yasm_symrec_get_objext_valparams(sym); + unsigned long addralign = 0; + + if (objext_valparams) { + yasm_valparam *vp = yasm_vps_first(objext_valparams); + for (; vp; vp = yasm_vps_next(vp)) { + if (!vp->val) { + /*@only@*/ /*@null@*/ yasm_expr *align_expr; + /*@dependent@*/ /*@null@*/ const yasm_intnum *align_intn; + + if (!(align_expr = yasm_vp_expr(vp, object->symtab, + yasm_symrec_get_def_line(sym))) + || !(align_intn = yasm_expr_get_intnum(&align_expr, 0))) { + yasm_error_set(YASM_ERROR_VALUE, + N_("alignment constraint is not an integer")); + if (align_expr) + yasm_expr_destroy(align_expr); + return NULL; + } + addralign = yasm_intnum_get_uint(align_intn); + yasm_expr_destroy(align_expr); + + /* Alignments must be a power of two. */ + if (!is_exp2(addralign)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("alignment constraint is not a power of two")); + return NULL; + } + } else + yasm_warn_set(YASM_WARN_GENERAL, + N_("Unrecognized qualifier `%s'"), vp->val); + } + } + + return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_COMMON, STB_GLOBAL, + 0, STV_DEFAULT, *size, &addralign, object); +} + +static int +elf_objfmt_build_symtab(yasm_symrec *sym, /*@null@*/ void *d) +{ + build_symtab_info *info = (build_symtab_info *)d; + yasm_sym_vis vis = yasm_symrec_get_visibility(sym); + yasm_sym_status status = yasm_symrec_get_status(sym); + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + elf_address value=0; + yasm_section *sect=NULL; + yasm_bytecode *precbc=NULL; + + assert(info != NULL); + + if (vis & YASM_SYM_EXTERN) { + entry = build_extern(info->objfmt_elf, sym, info->object); + yasm_errwarn_propagate(info->errwarns, + yasm_symrec_get_decl_line(sym)); + return 0; + } + + if (vis & YASM_SYM_COMMON) { + entry = build_common(info->objfmt_elf, sym, info->object); + yasm_errwarn_propagate(info->errwarns, + yasm_symrec_get_decl_line(sym)); + /* If the COMMON variable was actually defined, fall through. */ + if (!(status & YASM_SYM_DEFINED)) + return 0; + } + + /* Ignore any undefined at this point. */ + if (!(status & YASM_SYM_DEFINED)) + return 0; + + if (!yasm_symrec_get_label(sym, &precbc)) { + if (!yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym)) + return 0; + precbc = NULL; + } + + if (precbc) + sect = yasm_bc_get_section(precbc); + + if (entry && elf_sym_in_table(entry)) + ; + else if (vis & YASM_SYM_GLOBAL) { + entry = build_global(info->objfmt_elf, sym, info->object); + yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym)); + } else { + int is_sect = 0; + + /* Locals (except when debugging) do not need to be + * in the symbol table, unless they're a section. + */ + if (sect && + strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0) + is_sect = 1; +#if 0 + /* FIXME: to enable this we must have handling in place for special + * symbols. + */ + if (!info->local_names && !is_sect) + return 0; +#else + if (yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym)) + return 0; +#endif + entry = yasm_symrec_get_data(sym, &elf_symrec_data); + if (!entry) { + /*@only@*/ char *symname = + yasm_symrec_get_global_name(sym, info->object); + elf_strtab_entry *name = !info->local_names || is_sect ? NULL : + elf_strtab_append_str(info->objfmt_elf->strtab, symname); + yasm_xfree(symname); + entry = elf_symtab_entry_create(name, sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + if (!elf_sym_in_table(entry)) + elf_symtab_insert_local_sym(info->objfmt_elf->elf_symtab, entry); + + elf_symtab_set_nonzero(entry, sect, 0, STB_LOCAL, + is_sect ? STT_SECTION : 0, NULL, 0); + + if (is_sect) + return 0; + } + + if (precbc) + value = yasm_bc_next_offset(precbc); + elf_symtab_set_nonzero(entry, sect, 0, 0, 0, NULL, &value); + + return 0; +} + +static yasm_objfmt * +elf_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module, + int bits_pref, + const elf_machine_handler **elf_march_out) +{ + yasm_objfmt_elf *objfmt_elf = yasm_xmalloc(sizeof(yasm_objfmt_elf)); + yasm_symrec *filesym; + elf_symtab_entry *entry; + const elf_machine_handler *elf_march; + + objfmt_elf->objfmt.module = module; + elf_march = elf_set_arch(object->arch, object->symtab, bits_pref); + if (!elf_march) { + yasm_xfree(objfmt_elf); + return NULL; + } + if (elf_march_out) + *elf_march_out = elf_march; + + 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(object->symtab, ".file", NULL, 0, 0); + /* Put in current input filename; we'll replace it in output() */ + objfmt_elf->file_strtab_entry = + elf_strtab_append_str(objfmt_elf->strtab, object->src_filename); + entry = elf_symtab_entry_create(objfmt_elf->file_strtab_entry, filesym); + yasm_symrec_add_data(filesym, &elf_symrec_data, entry); + elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL, + NULL); + elf_symtab_append_entry(objfmt_elf->elf_symtab, entry); + + /* FIXME: misuse of NULL bytecode */ + objfmt_elf->dotdotsym = + yasm_symtab_define_label(object->symtab, "..sym", NULL, 0, 0); + + return (yasm_objfmt *)objfmt_elf; +} + +static yasm_objfmt * +elf_objfmt_create(yasm_object *object) +{ + const elf_machine_handler *elf_march; + yasm_objfmt *objfmt; + yasm_objfmt_elf *objfmt_elf; + + objfmt = elf_objfmt_create_common(object, &yasm_elf_LTX_objfmt, 0, + &elf_march); + if (objfmt) { + objfmt_elf = (yasm_objfmt_elf *)objfmt; + /* Figure out which bitness of object format to use */ + if (elf_march->bits == 32) + objfmt_elf->objfmt.module = &yasm_elf32_LTX_objfmt; + else if (elf_march->bits == 64) + objfmt_elf->objfmt.module = &yasm_elf64_LTX_objfmt; + } + return objfmt; +} + +static yasm_objfmt * +elf32_objfmt_create(yasm_object *object) +{ + return elf_objfmt_create_common(object, &yasm_elf32_LTX_objfmt, 32, NULL); +} + +static yasm_objfmt * +elf64_objfmt_create(yasm_object *object) +{ + return elf_objfmt_create_common(object, &yasm_elf64_LTX_objfmt, 64, NULL); +} + +static long +elf_objfmt_output_align(FILE *f, unsigned int align) +{ + long pos; + unsigned long delta; + if (!is_exp2(align)) + yasm_internal_error("requested alignment not a power of two"); + + pos = ftell(f); + if (pos == -1) { + yasm_error_set(YASM_ERROR_IO, + 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_set(YASM_ERROR_IO, + N_("could not set file position on output file")); + return -1; + } + } + return pos; +} + +static int +elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc, + unsigned char *buf, unsigned int destsize, + unsigned int 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, 0); + if (reloc == NULL) { + yasm_error_set(YASM_ERROR_TYPE, N_("elf: invalid relocation size")); + return 1; + } + /* allocate .rel[a] sections on a need-basis */ + elf_secthead_append_reloc(info->sect, info->shead, reloc); + + zero = yasm_intnum_create_uint(0); + elf_handle_reloc_addend(zero, reloc, 0); + retval = yasm_arch_intnum_tobytes(info->object->arch, zero, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(zero); + return retval; +} + +static int +elf_objfmt_output_value(yasm_value *value, unsigned char *buf, + unsigned int destsize, unsigned long offset, + yasm_bytecode *bc, int warn, /*@null@*/ void *d) +{ + /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; + unsigned long intn_val; + /*@null@*/ elf_reloc_entry *reloc = NULL; + int retval; + unsigned int valsize = value->size; + + if (info == NULL) + yasm_internal_error("null info struct"); + + 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; + } + + /* Handle other expressions, with relocation if necessary */ + if (value->seg_of || value->section_rel || value->rshift > 0) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("elf: relocation too complex")); + return 1; + } + + intn_val = 0; + if (value->rel) { + yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel); + /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel; + /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt; + + if (wrt == info->objfmt_elf->dotdotsym) + wrt = NULL; + else if (wrt && elf_is_wrt_sym_relative(wrt)) + ; + else if (wrt && elf_is_wrt_pos_adjusted(wrt)) + intn_val = offset + bc->offset; + else if (vis == YASM_SYM_LOCAL) { + yasm_bytecode *sym_precbc; + /* Local symbols need relocation to their section's start, and + * add in the offset of the bytecode (within the target section) + * into the abs portion. + * + * This is only done if the symbol is relocated against the + * section instead of the symbol itself. + */ + if (yasm_symrec_get_label(sym, &sym_precbc)) { + /* Relocate to section start */ + yasm_section *sym_sect = yasm_bc_get_section(sym_precbc); + /*@null@*/ elf_secthead *sym_shead; + sym_shead = yasm_section_get_data(sym_sect, &elf_section_data); + assert(sym_shead != NULL); + sym = elf_secthead_get_sym(sym_shead); + + intn_val = yasm_bc_next_offset(sym_precbc); + } + } + + /* For PC-relative, need to add offset of expression within bc. */ + if (value->curpos_rel) + intn_val += offset; + + /* Check for _GLOBAL_OFFSET_TABLE_ symbol reference */ + reloc = elf_reloc_entry_create(sym, wrt, + yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel, + valsize, sym == info->GOT_sym); + if (reloc == NULL) { + yasm_error_set(YASM_ERROR_TYPE, + N_("elf: invalid relocation (WRT or size)")); + return 1; + } + /* allocate .rel[a] sections on a need-basis */ + elf_secthead_append_reloc(info->sect, info->shead, reloc); + } + + intn = yasm_intnum_create_uint(intn_val); + + if (value->abs) { + yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0); + if (!intn2) { + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("elf: relocation too complex")); + yasm_intnum_destroy(intn); + return 1; + } + yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2); + } + + if (reloc) + elf_handle_reloc_addend(intn, reloc, offset); + retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize, + valsize, 0, bc, warn); + yasm_intnum_destroy(intn); + return retval; +} + +static int +elf_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; + int gap; + + if (info == NULL) + yasm_internal_error("null info struct"); + + bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, info, + elf_objfmt_output_value, 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); + elf_secthead_add_size(info->shead, bcsize); + yasm_intnum_destroy(bcsize); + } + + /* 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 declared in code/data section: zeroing")); + /* Write out in chunks */ + memset(buf, 0, 256); + left = size; + while (left > 256) { + fwrite(buf, 256, 1, info->f); + left -= 256; + } + fwrite(buf, left, 1, info->f); + } else { + /* Output buf (or bigbuf if non-NULL) to file */ + fwrite(bigbuf ? bigbuf : buf, (size_t)size, 1, info->f); + } + + /* If bigbuf was allocated, free it */ + if (bigbuf) + yasm_xfree(bigbuf); + + return 0; +} + +static int +elf_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; + + if (info == NULL) + yasm_internal_error("null info struct"); + shead = yasm_section_get_data(sect, &elf_section_data); + if (shead == NULL) + yasm_internal_error("no associated data"); + + if (elf_secthead_get_align(shead) == 0) + elf_secthead_set_align(shead, yasm_section_get_align(sect)); + + /* 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(yasm_bc_next_offset(last)); + elf_secthead_add_size(shead, sectsize); + yasm_intnum_destroy(sectsize); + } + elf_secthead_set_index(shead, ++info->sindex); + return 0; + } + + if ((pos = ftell(info->f)) == -1) { + yasm_error_set(YASM_ERROR_IO, + N_("couldn't read position on output stream")); + yasm_errwarn_propagate(info->errwarns, 0); + } + pos = elf_secthead_set_file_offset(shead, pos); + if (fseek(info->f, pos, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream")); + yasm_errwarn_propagate(info->errwarns, 0); + } + + info->sect = sect; + info->shead = shead; + yasm_section_bcs_traverse(sect, info->errwarns, info, + elf_objfmt_output_bytecode); + + elf_secthead_set_index(shead, ++info->sindex); + + /* No relocations to output? Go on to next section */ + if (elf_secthead_write_relocs_to_file(info->f, sect, shead, + info->errwarns) == 0) + return 0; + elf_secthead_set_rel_index(shead, ++info->sindex); + + /* name the relocation section .rel[a].foo */ + sectname = yasm_section_get_name(sect); + relname = elf_secthead_name_reloc_section(sectname); + elf_secthead_set_rel_name(shead, + elf_strtab_append_str(info->objfmt_elf->shstrtab, relname)); + yasm_xfree(relname); + + return 0; +} + +static int +elf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d) +{ + /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d; + /*@dependent@*/ /*@null@*/ elf_secthead *shead; + + if (info == NULL) + yasm_internal_error("null info struct"); + shead = yasm_section_get_data(sect, &elf_section_data); + if (shead == NULL) + yasm_internal_error("no section header attached to section"); + + if(elf_secthead_write_to_file(info->f, shead, info->sindex+1)) + info->sindex++; + + /* output strtab headers here? */ + + /* relocation entries for .foo are stored in section .rel[a].foo */ + if(elf_secthead_write_rel_to_file(info->f, 3, sect, shead, + info->sindex+1)) + info->sindex++; + + return 0; +} + +static void +elf_objfmt_output(yasm_object *object, FILE *f, int all_syms, + yasm_errwarns *errwarns) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + elf_objfmt_output_info info; + build_symtab_info buildsym_info; + long pos; + unsigned long elf_shead_addr; + elf_secthead *esdn; + unsigned long elf_strtab_offset, elf_shstrtab_offset, elf_symtab_offset; + unsigned long elf_strtab_size, elf_shstrtab_size, elf_symtab_size; + elf_strtab_entry *elf_strtab_name, *elf_shstrtab_name, *elf_symtab_name; + unsigned long elf_symtab_nlocal; + + info.object = object; + info.objfmt_elf = objfmt_elf; + info.errwarns = errwarns; + info.f = f; + info.GOT_sym = yasm_symtab_get(object->symtab, "_GLOBAL_OFFSET_TABLE_"); + + /* Update filename strtab */ + elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry, + object->src_filename); + + /* Allocate space for Ehdr by seeking forward */ + if (fseek(f, (long)(elf_proghead_get_size()), SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file")); + yasm_errwarn_propagate(errwarns, 0); + return; + } + + /* add all (local) syms to symtab because relocation needs a symtab index + * if all_syms, register them by name. if not, use strtab entry 0 */ + buildsym_info.object = object; + buildsym_info.objfmt_elf = objfmt_elf; + buildsym_info.errwarns = errwarns; + buildsym_info.local_names = all_syms; + yasm_symtab_traverse(object->symtab, &buildsym_info, + elf_objfmt_build_symtab); + elf_symtab_nlocal = elf_symtab_assign_indices(objfmt_elf->elf_symtab); + + /* output known sections - includes reloc sections which aren't in yasm's + * list. Assign indices as we go. */ + info.sindex = 3; + if (yasm_object_sections_traverse(object, &info, + elf_objfmt_output_section)) + return; + + /* add final sections to the shstrtab */ + elf_strtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".strtab"); + elf_symtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".symtab"); + elf_shstrtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, + ".shstrtab"); + + /* output .shstrtab */ + if ((pos = elf_objfmt_output_align(f, 4)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_shstrtab_offset = (unsigned long) pos; + elf_shstrtab_size = elf_strtab_output_to_file(f, objfmt_elf->shstrtab); + + /* output .strtab */ + if ((pos = elf_objfmt_output_align(f, 4)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_strtab_offset = (unsigned long) pos; + elf_strtab_size = elf_strtab_output_to_file(f, objfmt_elf->strtab); + + /* output .symtab - last section so all others have indexes */ + if ((pos = elf_objfmt_output_align(f, 4)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_symtab_offset = (unsigned long) pos; + elf_symtab_size = elf_symtab_write_to_file(f, objfmt_elf->elf_symtab, + errwarns); + + /* output section header table */ + if ((pos = elf_objfmt_output_align(f, 16)) == -1) { + yasm_errwarn_propagate(errwarns, 0); + return; + } + elf_shead_addr = (unsigned long) pos; + + /* stabs debugging support */ + if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "stabs")==0) { + yasm_section *stabsect = yasm_object_find_general(object, ".stab"); + yasm_section *stabstrsect = + yasm_object_find_general(object, ".stabstr"); + if (stabsect && stabstrsect) { + elf_secthead *stab = + yasm_section_get_data(stabsect, &elf_section_data); + elf_secthead *stabstr = + yasm_section_get_data(stabstrsect, &elf_section_data); + if (stab && stabstr) { + elf_secthead_set_link(stab, elf_secthead_get_index(stabstr)); + } + else + yasm_internal_error(N_("missing .stab or .stabstr section/data")); + } + } + + /* output dummy section header - 0 */ + info.sindex = 0; + + esdn = elf_secthead_create(NULL, SHT_NULL, 0, 0, 0); + elf_secthead_set_index(esdn, 0); + elf_secthead_write_to_file(f, esdn, 0); + elf_secthead_destroy(esdn); + + esdn = elf_secthead_create(elf_shstrtab_name, SHT_STRTAB, 0, + elf_shstrtab_offset, elf_shstrtab_size); + elf_secthead_set_index(esdn, 1); + elf_secthead_write_to_file(f, esdn, 1); + elf_secthead_destroy(esdn); + + esdn = elf_secthead_create(elf_strtab_name, SHT_STRTAB, 0, + elf_strtab_offset, elf_strtab_size); + elf_secthead_set_index(esdn, 2); + elf_secthead_write_to_file(f, esdn, 2); + elf_secthead_destroy(esdn); + + esdn = elf_secthead_create(elf_symtab_name, SHT_SYMTAB, 0, + elf_symtab_offset, elf_symtab_size); + elf_secthead_set_index(esdn, 3); + elf_secthead_set_info(esdn, elf_symtab_nlocal); + elf_secthead_set_link(esdn, 2); /* for .strtab, which is index 2 */ + elf_secthead_write_to_file(f, esdn, 3); + elf_secthead_destroy(esdn); + + info.sindex = 3; + /* output remaining section headers */ + yasm_object_sections_traverse(object, &info, elf_objfmt_output_secthead); + + /* output Ehdr */ + if (fseek(f, 0, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file")); + yasm_errwarn_propagate(errwarns, 0); + return; + } + + elf_proghead_write_to_file(f, elf_shead_addr, info.sindex+1, 1); +} + +static void +elf_objfmt_destroy(yasm_objfmt *objfmt) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)objfmt; + elf_symtab_destroy(objfmt_elf->elf_symtab); + elf_strtab_destroy(objfmt_elf->shstrtab); + elf_strtab_destroy(objfmt_elf->strtab); + yasm_xfree(objfmt); +} + +static void +elf_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_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + elf_secthead *esd; + yasm_symrec *sym; + elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->shstrtab, + sectname); + + elf_section_type type=SHT_PROGBITS; + elf_size entsize=0; + + if (yasm__strcasecmp(sectname, ".stab")==0) { + entsize = 12; + } else if (yasm__strcasecmp(sectname, ".stabstr")==0) { + type = SHT_STRTAB; + } + + esd = elf_secthead_create(name, type, 0, 0, 0); + elf_secthead_set_entsize(esd, entsize); + yasm_section_add_data(sect, &elf_section_data, esd); + sym = yasm_symtab_define_label(object->symtab, sectname, + yasm_section_bcs_first(sect), 1, line); + + elf_secthead_set_sym(esd, sym); +} + +static yasm_section * +elf_objfmt_add_default_section(yasm_object *object) +{ + yasm_section *retval; + int isnew; + + retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0); + if (isnew) + { + elf_secthead *esd = yasm_section_get_data(retval, &elf_section_data); + elf_secthead_set_typeflags(esd, SHT_PROGBITS, + SHF_ALLOC + SHF_EXECINSTR); + yasm_section_set_default(retval, 1); + } + return retval; +} + +struct elf_section_switch_data { + /*@only@*/ /*@null@*/ yasm_intnum *align_intn; + unsigned long flags; + unsigned long type; + int gasflags; + int stdsect; +}; + +/* GAS-style flags */ +static int +elf_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d, + /*@unused@*/ uintptr_t arg) +{ + struct elf_section_switch_data *data = (struct elf_section_switch_data *)d; + const char *s = yasm_vp_string(vp); + size_t i; + + if (!s) { + yasm_error_set(YASM_ERROR_VALUE, + N_("non-string section attribute")); + return -1; + } + + if (data->stdsect && strlen(s) == 0) { + data->gasflags = 1; + return 0; + } + + data->flags = 0; + for (i=0; i<strlen(s); i++) { + switch (s[i]) { + case 'a': + data->flags |= SHF_ALLOC; + break; + case 'w': + data->flags |= SHF_WRITE; + break; + case 'x': + data->flags |= SHF_EXECINSTR; + break; + case 'M': + data->flags |= SHF_MERGE; + break; + case 'S': + data->flags |= SHF_STRINGS; + break; + case 'G': + data->flags |= SHF_GROUP; + break; + case 'T': + data->flags |= SHF_TLS; + break; + default: + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized section attribute: `%c'"), + s[i]); + } + } + + data->gasflags = 1; + return 0; +} + +static /*@observer@*/ /*@null@*/ yasm_section * +elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, + /*@null@*/ yasm_valparamhead *objext_valparams, + unsigned long line) +{ + yasm_valparam *vp; + yasm_section *retval; + int isnew; + unsigned long align = 4; + int flags_override = 0; + const char *sectname; + int resonly = 0; + + struct elf_section_switch_data data; + + static const yasm_dir_help help[] = { + { "alloc", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_ALLOC }, + { "exec", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR }, + { "write", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_WRITE }, + { "tls", 0, yasm_dir_helper_flag_or, + offsetof(struct elf_section_switch_data, flags), SHF_TLS }, + { "progbits", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_section_switch_data, type), SHT_PROGBITS }, + { "noalloc", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_ALLOC }, + { "noexec", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR }, + { "nowrite", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_WRITE }, + { "notls", 0, yasm_dir_helper_flag_and, + offsetof(struct elf_section_switch_data, flags), SHF_TLS }, + { "noprogbits", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_section_switch_data, type), SHT_NOBITS }, + { "nobits", 0, yasm_dir_helper_flag_set, + offsetof(struct elf_section_switch_data, type), SHT_NOBITS }, + { "gasflags", 1, elf_helper_gasflags, 0, 0 }, + { "align", 1, yasm_dir_helper_intn, + offsetof(struct elf_section_switch_data, align_intn), 0 } + }; + /*@only@*/ /*@null@*/ yasm_expr *merge_expr = NULL; + /*@dependent@*/ /*@null@*/ const yasm_intnum *merge_intn = NULL; + elf_secthead *esd; + + data.align_intn = NULL; + data.flags = SHF_ALLOC; + data.type = SHT_PROGBITS; + data.gasflags = 0; + data.stdsect = 1; + + vp = yasm_vps_first(valparams); + sectname = yasm_vp_string(vp); + if (!sectname) + return NULL; + vp = yasm_vps_next(vp); + + if (strcmp(sectname, ".bss") == 0) { + data.type = SHT_NOBITS; + data.flags = SHF_ALLOC + SHF_WRITE; + resonly = 1; + } else if (strcmp(sectname, ".data") == 0) { + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC + SHF_WRITE; + } else if (strcmp(sectname, ".tdata") == 0) { + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC + SHF_WRITE + SHF_TLS; + } else if (strcmp(sectname, ".rodata") == 0) { + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC; + } else if (strcmp(sectname, ".text") == 0) { + align = 16; + data.type = SHT_PROGBITS; + data.flags = SHF_ALLOC + SHF_EXECINSTR; + } else if (strcmp(sectname, ".comment") == 0) { + align = 0; + data.type = SHT_PROGBITS; + data.flags = 0; + } else { + /* Default to code */ + align = 1; + data.stdsect = 0; + } + + 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.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"); + return NULL; + } + } + + /* Handle merge entity size */ + if (data.flags & SHF_MERGE) { + if (objext_valparams && (vp = yasm_vps_first(objext_valparams)) + && !vp->val) { + if (!(merge_expr = yasm_vp_expr(vp, object->symtab, line)) || + !(merge_intn = yasm_expr_get_intnum(&merge_expr, 0))) + yasm_warn_set(YASM_WARN_GENERAL, + N_("invalid merge entity size")); + } else { + yasm_warn_set(YASM_WARN_GENERAL, + N_("entity size for SHF_MERGE not specified")); + data.flags &= ~SHF_MERGE; + } + } + + retval = yasm_object_get_general(object, sectname, align, + (data.flags & SHF_EXECINSTR) != 0, + resonly, &isnew, line); + + esd = yasm_section_get_data(retval, &elf_section_data); + + if (isnew || yasm_section_is_default(retval)) { + yasm_section_set_default(retval, 0); + elf_secthead_set_typeflags(esd, data.type, data.flags); + if (merge_intn) + elf_secthead_set_entsize(esd, yasm_intnum_get_uint(merge_intn)); + yasm_section_set_align(retval, align, line); + } else if (flags_override && !data.gasflags) + yasm_warn_set(YASM_WARN_GENERAL, + N_("section flags ignored on section redeclaration")); + if (merge_expr) + yasm_expr_destroy(merge_expr); + return retval; +} + +static /*@observer@*/ /*@null@*/ yasm_symrec * +elf_objfmt_get_special_sym(yasm_object *object, const char *name, + const char *parser) +{ + if (yasm__strcasecmp(name, "sym") == 0) { + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + return objfmt_elf->dotdotsym; + } + return elf_get_special_sym(name, parser); +} + +static void +dir_type(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + const char *symname = yasm_vp_id(vp); + /* Get symbol elf data */ + yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line); + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + /*@null@*/ const char *type; + + /* Create entry if necessary */ + if (!entry) { + entry = elf_symtab_entry_create( + elf_strtab_append_str(objfmt_elf->strtab, symname), sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + /* Pull new type from param */ + vp = yasm_vps_next(vp); + if (vp && !vp->val && (type = yasm_vp_id(vp))) { + if (yasm__strcasecmp(type, "function") == 0) + elf_sym_set_type(entry, STT_FUNC); + else if (yasm__strcasecmp(type, "object") == 0) + elf_sym_set_type(entry, STT_OBJECT); + else if (yasm__strcasecmp(type, "tls_object") == 0) + elf_sym_set_type(entry, STT_TLS); + else if (yasm__strcasecmp(type, "notype") == 0) + elf_sym_set_type(entry, STT_NOTYPE); + else + yasm_warn_set(YASM_WARN_GENERAL, + N_("unrecognized symbol type `%s'"), type); + } else + yasm_error_set(YASM_ERROR_SYNTAX, N_("no type specified")); +} + +static void +dir_size(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + const char *symname = yasm_vp_id(vp); + /* Get symbol elf data */ + yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line); + elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data); + /*@only@*/ /*@null@*/ yasm_expr *size; + + /* Create entry if necessary */ + if (!entry) { + entry = elf_symtab_entry_create( + elf_strtab_append_str(objfmt_elf->strtab, symname), sym); + yasm_symrec_add_data(sym, &elf_symrec_data, entry); + } + + /* Pull new size from param */ + vp = yasm_vps_next(vp); + if (vp && !vp->val && (size = yasm_vp_expr(vp, object->symtab, line))) + elf_sym_set_size(entry, size); + else + yasm_error_set(YASM_ERROR_SYNTAX, N_("no size specified")); +} + +static void +dir_weak(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt; + yasm_valparam *vp = yasm_vps_first(valparams); + const char *symname = yasm_vp_id(vp); + yasm_symrec *sym = yasm_symtab_declare(object->symtab, symname, + YASM_SYM_GLOBAL, line); + elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_WEAK, 0, + STV_DEFAULT, NULL, NULL, object); +} + +static void +dir_ident(yasm_object *object, yasm_valparamhead *valparams, + yasm_valparamhead *objext_valparams, unsigned long line) +{ + yasm_valparamhead sect_vps; + yasm_datavalhead dvs; + yasm_section *comment; + yasm_valparam *vp; + yasm_valparam *vp2; + + /* Accept, but do nothing with empty ident */ + if (!valparams) + return; + vp = yasm_vps_first(valparams); + if (!vp) + return; + + /* Put ident data into .comment section */ + yasm_vps_initialize(§_vps); + vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment")); + yasm_vps_append(§_vps, vp2); + comment = elf_objfmt_section_switch(object, §_vps, NULL, line); + yasm_vps_delete(§_vps); + + /* To match GAS output, if the comment section is empty, put an + * initial 0 byte in the section. + */ + if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) { + yasm_dvs_initialize(&dvs); + yasm_dvs_append(&dvs, yasm_dv_create_expr( + yasm_expr_create_ident( + yasm_expr_int(yasm_intnum_create_uint(0)), line))); + yasm_section_bcs_append(comment, + yasm_bc_create_data(&dvs, 1, 0, object->arch, line)); + } + + yasm_dvs_initialize(&dvs); + do { + const char *s = yasm_vp_string(vp); + if (!s) { + yasm_error_set(YASM_ERROR_VALUE, + N_(".comment requires string parameters")); + yasm_dvs_delete(&dvs); + return; + } + yasm_dvs_append(&dvs, + yasm_dv_create_string(yasm__xstrdup(s), strlen(s))); + } while ((vp = yasm_vps_next(vp))); + + yasm_section_bcs_append(comment, + yasm_bc_create_data(&dvs, 1, 1, object->arch, line)); +} + +/* Define valid debug formats to use with this object format */ +static const char *elf_objfmt_dbgfmt_keywords[] = { + "null", + "stabs", + "dwarf2", + NULL +}; + +static const yasm_directive elf_objfmt_directives[] = { + { ".type", "gas", dir_type, YASM_DIR_ID_REQUIRED }, + { ".size", "gas", dir_size, YASM_DIR_ID_REQUIRED }, + { ".weak", "gas", dir_weak, YASM_DIR_ID_REQUIRED }, + { ".ident", "gas", dir_ident, YASM_DIR_ANY }, + { "type", "nasm", dir_type, YASM_DIR_ID_REQUIRED }, + { "size", "nasm", dir_size, YASM_DIR_ID_REQUIRED }, + { "weak", "nasm", dir_weak, YASM_DIR_ID_REQUIRED }, + { "ident", "nasm", dir_ident, YASM_DIR_ANY }, + { NULL, NULL, NULL, 0 } +}; + +static const char *elf_nasm_stdmac[] = { + "%imacro type 1+.nolist", + "[type %1]", + "%endmacro", + "%imacro size 1+.nolist", + "[size %1]", + "%endmacro", + "%imacro weak 1+.nolist", + "[weak %1]", + "%endmacro", + NULL +}; + +static const yasm_stdmac elf_objfmt_stdmacs[] = { + { "nasm", "nasm", elf_nasm_stdmac }, + { NULL, NULL, NULL } +}; + +/* Define objfmt structure -- see objfmt.h for details */ +yasm_objfmt_module yasm_elf_LTX_objfmt = { + "ELF", + "elf", + "o", + 32, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elf_objfmt_create, + elf_objfmt_output, + elf_objfmt_destroy, + elf_objfmt_add_default_section, + elf_objfmt_init_new_section, + elf_objfmt_section_switch, + elf_objfmt_get_special_sym +}; + +yasm_objfmt_module yasm_elf32_LTX_objfmt = { + "ELF (32-bit)", + "elf32", + "o", + 32, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elf32_objfmt_create, + elf_objfmt_output, + elf_objfmt_destroy, + elf_objfmt_add_default_section, + elf_objfmt_init_new_section, + elf_objfmt_section_switch, + elf_objfmt_get_special_sym +}; + +yasm_objfmt_module yasm_elf64_LTX_objfmt = { + "ELF (64-bit)", + "elf64", + "o", + 64, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elf64_objfmt_create, + elf_objfmt_output, + elf_objfmt_destroy, + elf_objfmt_add_default_section, + elf_objfmt_init_new_section, + elf_objfmt_section_switch, + elf_objfmt_get_special_sym +}; |