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/elf | |
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/elf')
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/elf/elf-machine.h | 216 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c | 2782 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c | 512 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c | 502 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c | 484 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/elf/elf.c | 1920 | ||||
-rw-r--r-- | contrib/tools/yasm/modules/objfmts/elf/elf.h | 1064 |
7 files changed, 3740 insertions, 3740 deletions
diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h b/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h index ea6cb4ec94..346b4f6f34 100644 --- a/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-machine.h @@ -1,108 +1,108 @@ -/* - * ELF object machine specific format helpers - * - * Copyright (C) 2004-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. - */ - -#ifndef ELF_MACHINE_H_INCLUDED -#define ELF_MACHINE_H_INCLUDED - -#define YASM_WRITE_32I_L(p, i) do {\ - assert(yasm_intnum_check_size(i, 32, 0, 2)); \ - yasm_intnum_get_sized(i, p, 4, 32, 0, 0, 0); \ - p += 4; } while (0) - -#define YASM_WRITE_64I_L(p, i) do {\ - assert(yasm_intnum_check_size(i, 64, 0, 2)); \ - yasm_intnum_get_sized(i, p, 8, 64, 0, 0, 0); \ - p += 8; } while (0) - -#define YASM_WRITE_64C_L(p, hi, lo) do {\ - YASM_WRITE_32_L(p, lo); \ - YASM_WRITE_32_L(p, hi); } while (0) - -#define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i) - -typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt); -typedef void(*func_write_symtab_entry)(unsigned char *bufp, - elf_symtab_entry *entry, - yasm_intnum *value_intn, - yasm_intnum *size_intn); -typedef void(*func_write_secthead)(unsigned char *bufp, elf_secthead *shead); -typedef void(*func_write_secthead_rel)(unsigned char *bufp, - elf_secthead *shead, - elf_section_index symtab_idx, - elf_section_index sindex); - -typedef void(*func_handle_reloc_addend)(yasm_intnum *intn, - elf_reloc_entry *reloc, - unsigned long offset); -typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc); -typedef void(*func_write_reloc)(unsigned char *bufp, - elf_reloc_entry *reloc, - unsigned int r_type, - unsigned int r_sym); -typedef void (*func_write_proghead)(unsigned char **bufpp, - elf_offset secthead_addr, - unsigned long secthead_count, - elf_section_index shstrtab_index); - -enum { - ELF_SSYM_SYM_RELATIVE = 1 << 0, - ELF_SSYM_CURPOS_ADJUST = 1 << 1, - ELF_SSYM_THREAD_LOCAL = 1 << 2 -}; - -typedef struct { - const char *name; /* should be something like ..name */ - const int sym_rel; /* symbol or section-relative? */ - const unsigned int reloc; /* relocation type */ - const unsigned int size; /* legal data size */ -} elf_machine_ssym; - -struct elf_machine_handler { - const char *arch; - const char *machine; - const char *reloc_section_prefix; - const unsigned long symtab_entry_size; - const unsigned long symtab_entry_align; - const unsigned long reloc_entry_size; - const unsigned long secthead_size; - const unsigned long proghead_size; - func_accepts_reloc accepts_reloc; - func_write_symtab_entry write_symtab_entry; - func_write_secthead write_secthead; - func_write_secthead_rel write_secthead_rel; - func_handle_reloc_addend handle_reloc_addend; - func_map_reloc_info_to_type map_reloc_info_to_type; - func_write_reloc write_reloc; - func_write_proghead write_proghead; - - elf_machine_ssym *ssyms; /* array of "special" syms */ - const size_t num_ssyms; /* size of array */ - - const int bits; /* usually 32 or 64 */ -}; - -#endif /* ELF_MACHINE_H_INCLUDED */ +/* + * ELF object machine specific format helpers + * + * Copyright (C) 2004-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. + */ + +#ifndef ELF_MACHINE_H_INCLUDED +#define ELF_MACHINE_H_INCLUDED + +#define YASM_WRITE_32I_L(p, i) do {\ + assert(yasm_intnum_check_size(i, 32, 0, 2)); \ + yasm_intnum_get_sized(i, p, 4, 32, 0, 0, 0); \ + p += 4; } while (0) + +#define YASM_WRITE_64I_L(p, i) do {\ + assert(yasm_intnum_check_size(i, 64, 0, 2)); \ + yasm_intnum_get_sized(i, p, 8, 64, 0, 0, 0); \ + p += 8; } while (0) + +#define YASM_WRITE_64C_L(p, hi, lo) do {\ + YASM_WRITE_32_L(p, lo); \ + YASM_WRITE_32_L(p, hi); } while (0) + +#define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i) + +typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt); +typedef void(*func_write_symtab_entry)(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn); +typedef void(*func_write_secthead)(unsigned char *bufp, elf_secthead *shead); +typedef void(*func_write_secthead_rel)(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex); + +typedef void(*func_handle_reloc_addend)(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset); +typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc); +typedef void(*func_write_reloc)(unsigned char *bufp, + elf_reloc_entry *reloc, + unsigned int r_type, + unsigned int r_sym); +typedef void (*func_write_proghead)(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index); + +enum { + ELF_SSYM_SYM_RELATIVE = 1 << 0, + ELF_SSYM_CURPOS_ADJUST = 1 << 1, + ELF_SSYM_THREAD_LOCAL = 1 << 2 +}; + +typedef struct { + const char *name; /* should be something like ..name */ + const int sym_rel; /* symbol or section-relative? */ + const unsigned int reloc; /* relocation type */ + const unsigned int size; /* legal data size */ +} elf_machine_ssym; + +struct elf_machine_handler { + const char *arch; + const char *machine; + const char *reloc_section_prefix; + const unsigned long symtab_entry_size; + const unsigned long symtab_entry_align; + const unsigned long reloc_entry_size; + const unsigned long secthead_size; + const unsigned long proghead_size; + func_accepts_reloc accepts_reloc; + func_write_symtab_entry write_symtab_entry; + func_write_secthead write_secthead; + func_write_secthead_rel write_secthead_rel; + func_handle_reloc_addend handle_reloc_addend; + func_map_reloc_info_to_type map_reloc_info_to_type; + func_write_reloc write_reloc; + func_write_proghead write_proghead; + + elf_machine_ssym *ssyms; /* array of "special" syms */ + const size_t num_ssyms; /* size of array */ + + const int bits; /* usually 32 or 64 */ +}; + +#endif /* ELF_MACHINE_H_INCLUDED */ diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c b/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c index 6874a1689f..e447218ad5 100644 --- a/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-objfmt.c @@ -1,1403 +1,1403 @@ -/* - * 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; -yasm_objfmt_module yasm_elfx32_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); +/* + * 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; +yasm_objfmt_module yasm_elfx32_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); if (!object->deb_filename) { object->deb_filename = yasm_replace_path( module->replace_map, module->replace_map_size, object->src_filename, strlen(object->src_filename)); } - /* Put in current input filename; we'll replace it in output() */ - objfmt_elf->file_strtab_entry = + /* Put in current input filename; we'll replace it in output() */ + objfmt_elf->file_strtab_entry = elf_strtab_append_str(objfmt_elf->strtab, object->deb_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 (strcmp (elf_march->machine, "x32") == 0) - objfmt_elf->objfmt.module = &yasm_elfx32_LTX_objfmt; - else 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 yasm_objfmt * -elfx32_objfmt_create(yasm_object *object) -{ - return elf_objfmt_create_common(object, &yasm_elfx32_LTX_objfmt, 32, 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_"); - + 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 (strcmp (elf_march->machine, "x32") == 0) + objfmt_elf->objfmt.module = &yasm_elfx32_LTX_objfmt; + else 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 yasm_objfmt * +elfx32_objfmt_create(yasm_object *object) +{ + return elf_objfmt_create_common(object, &yasm_elfx32_LTX_objfmt, 32, 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_"); + if (!object->deb_filename) { object->deb_filename = yasm_replace_path( objfmt_elf->objfmt.module->replace_map, objfmt_elf->objfmt.module->replace_map_size, object->src_filename, strlen(object->src_filename)); } - /* Update filename strtab */ - elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry, + /* Update filename strtab */ + elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry, object->deb_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 -}; - -yasm_objfmt_module yasm_elfx32_LTX_objfmt = { - "ELF (x32)", - "elfx32", - "o", - 64, - 0, - elf_objfmt_dbgfmt_keywords, - "null", - elf_objfmt_directives, - elf_objfmt_stdmacs, - elfx32_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 -}; + + /* 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 +}; + +yasm_objfmt_module yasm_elfx32_LTX_objfmt = { + "ELF (x32)", + "elfx32", + "o", + 64, + 0, + elf_objfmt_dbgfmt_keywords, + "null", + elf_objfmt_directives, + elf_objfmt_stdmacs, + elfx32_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 +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c index 3ba376af03..5384b768ed 100644 --- a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-amd64.c @@ -1,256 +1,256 @@ -/* - * ELF object format helpers - x86:amd64 - * - * Copyright (C) 2004-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> - -#include <libyasm.h> -#define YASM_OBJFMT_ELF_INTERNAL -#include "elf.h" -#include "elf-machine.h" - -static elf_machine_ssym elf_x86_amd64_ssyms[] = { - {"pltoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLTOFF64, 64}, - {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32}, - {"gotplt", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPLT64, 64}, - {"gotoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTOFF64, 64}, - {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32}, - {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TLSGD, 32}, - {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TLSLD, 32}, - {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_GOTTPOFF, 32}, - {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TPOFF32, 32}, - {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_DTPOFF32, 32}, - {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32}, - {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_GOTPC32_TLSDESC, 32}, - {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TLSDESC_CALL, 32} -}; - -static int -elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt) -{ - if (wrt) { - const elf_machine_ssym *ssym = (elf_machine_ssym *) - yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); - if (!ssym || val != ssym->size) - return 0; - return 1; - } - return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0); -} - -static void -elf_x86_amd64_write_symtab_entry(unsigned char *bufp, - elf_symtab_entry *entry, - yasm_intnum *value_intn, - yasm_intnum *size_intn) -{ - YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); - YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type)); - YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis)); - if (entry->sect) { - elf_secthead *shead = - yasm_section_get_data(entry->sect, &elf_section_data); - if (!shead) - yasm_internal_error(N_("symbol references section without data")); - YASM_WRITE_16_L(bufp, shead->index); - } else { - YASM_WRITE_16_L(bufp, entry->index); - } - YASM_WRITE_64I_L(bufp, value_intn); - YASM_WRITE_64I_L(bufp, size_intn); -} - -static void -elf_x86_amd64_write_secthead(unsigned char *bufp, elf_secthead *shead) -{ - YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); - YASM_WRITE_32_L(bufp, shead->type); - YASM_WRITE_64Z_L(bufp, shead->flags); - YASM_WRITE_64Z_L(bufp, 0); /* vmem address */ - YASM_WRITE_64Z_L(bufp, shead->offset); - YASM_WRITE_64I_L(bufp, shead->size); - - YASM_WRITE_32_L(bufp, shead->link); - YASM_WRITE_32_L(bufp, shead->info); - - YASM_WRITE_64Z_L(bufp, shead->align); - YASM_WRITE_64Z_L(bufp, shead->entsize); -} - -static void -elf_x86_amd64_write_secthead_rel(unsigned char *bufp, - elf_secthead *shead, - elf_section_index symtab_idx, - elf_section_index sindex) -{ - yasm_intnum *nreloc; - yasm_intnum *relocsize; - - YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); - YASM_WRITE_32_L(bufp, SHT_RELA); - YASM_WRITE_64Z_L(bufp, 0); - YASM_WRITE_64Z_L(bufp, 0); - YASM_WRITE_64Z_L(bufp, shead->rel_offset); - - nreloc = yasm_intnum_create_uint(shead->nreloc); - relocsize = yasm_intnum_create_uint(RELOC64A_SIZE); - yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc); - YASM_WRITE_64I_L(bufp, relocsize); /* size */ - yasm_intnum_destroy(nreloc); - yasm_intnum_destroy(relocsize); - - YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ - YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ - YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN); /* align */ - YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE); /* entity size */ -} - -static void -elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn, - elf_reloc_entry *reloc, - unsigned long offset) -{ - /* .rela: copy value out as addend, replace original with 0 */ - reloc->addend = yasm_intnum_copy(intn); - yasm_intnum_zero(intn); -} - -static unsigned int -elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc) -{ - if (reloc->wrt) { - const elf_machine_ssym *ssym = (elf_machine_ssym *) - yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); - if (!ssym || reloc->valsize != ssym->size) - yasm_internal_error(N_("Unsupported WRT")); - - /* Force TLS type; this is required by the linker. */ - if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { - elf_symtab_entry *esym; - - esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); - if (esym) - esym->type = STT_TLS; - } - /* Map PC-relative GOT to appropriate relocation */ - if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32) - return (unsigned char) R_X86_64_GOTPCREL; - return (unsigned char) ssym->reloc; - } else if (reloc->is_GOT_sym && reloc->valsize == 32) { - return (unsigned char) R_X86_64_GOTPC32; - } else if (reloc->is_GOT_sym && reloc->valsize == 64) { - return (unsigned char) R_X86_64_GOTPC64; - } else if (reloc->rtype_rel) { - switch (reloc->valsize) { - case 8: return (unsigned char) R_X86_64_PC8; - case 16: return (unsigned char) R_X86_64_PC16; - case 32: return (unsigned char) R_X86_64_PC32; - case 64: return (unsigned char) R_X86_64_PC64; - default: yasm_internal_error(N_("Unsupported relocation size")); - } - } else { - switch (reloc->valsize) { - case 8: return (unsigned char) R_X86_64_8; - case 16: return (unsigned char) R_X86_64_16; - case 32: return (unsigned char) R_X86_64_32; - case 64: return (unsigned char) R_X86_64_64; - default: yasm_internal_error(N_("Unsupported relocation size")); - } - } - return 0; -} - -static void -elf_x86_amd64_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, - unsigned int r_type, unsigned int r_sym) -{ - YASM_WRITE_64I_L(bufp, reloc->reloc.addr); - /*YASM_WRITE_64_L(bufp, ELF64_R_INFO(r_sym, r_type));*/ - YASM_WRITE_64C_L(bufp, r_sym, r_type); - if (reloc->addend) - YASM_WRITE_64I_L(bufp, reloc->addend); - else { - YASM_WRITE_32_L(bufp, 0); - YASM_WRITE_32_L(bufp, 0); - } -} - -static void -elf_x86_amd64_write_proghead(unsigned char **bufpp, - elf_offset secthead_addr, - unsigned long secthead_count, - elf_section_index shstrtab_index) -{ - unsigned char *bufp = *bufpp; - unsigned char *buf = bufp-4; - YASM_WRITE_8(bufp, ELFCLASS64); /* elf class */ - YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ - YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ - YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */ - YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */ - while (bufp-buf < EI_NIDENT) /* e_ident padding */ - YASM_WRITE_8(bufp, 0); - - YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ - YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */ - YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ - YASM_WRITE_64Z_L(bufp, 0); /* e_entry */ - YASM_WRITE_64Z_L(bufp, 0); /* e_phoff */ - YASM_WRITE_64Z_L(bufp, secthead_addr); /* e_shoff secthead off */ - - YASM_WRITE_32_L(bufp, 0); /* e_flags */ - YASM_WRITE_16_L(bufp, EHDR64_SIZE); /* e_ehsize */ - YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ - YASM_WRITE_16_L(bufp, 0); /* e_phnum */ - YASM_WRITE_16_L(bufp, SHDR64_SIZE); /* e_shentsize */ - YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ - YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ - *bufpp = bufp; -} - -const elf_machine_handler -elf_machine_handler_x86_amd64 = { - "x86", "amd64", ".rela", - SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE, - elf_x86_amd64_accepts_reloc, - elf_x86_amd64_write_symtab_entry, - elf_x86_amd64_write_secthead, - elf_x86_amd64_write_secthead_rel, - elf_x86_amd64_handle_reloc_addend, - elf_x86_amd64_map_reloc_info_to_type, - elf_x86_amd64_write_reloc, - elf_x86_amd64_write_proghead, - elf_x86_amd64_ssyms, - sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]), - 64 -}; +/* + * ELF object format helpers - x86:amd64 + * + * Copyright (C) 2004-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> + +#include <libyasm.h> +#define YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static elf_machine_ssym elf_x86_amd64_ssyms[] = { + {"pltoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLTOFF64, 64}, + {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32}, + {"gotplt", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPLT64, 64}, + {"gotoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTOFF64, 64}, + {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32}, + {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSGD, 32}, + {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSLD, 32}, + {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTTPOFF, 32}, + {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TPOFF32, 32}, + {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_DTPOFF32, 32}, + {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32}, + {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTPC32_TLSDESC, 32}, + {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSDESC_CALL, 32} +}; + +static int +elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt) +{ + if (wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); + if (!ssym || val != ssym->size) + return 0; + return 1; + } + return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0); +} + +static void +elf_x86_amd64_write_symtab_entry(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn) +{ + YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); + YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type)); + YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis)); + if (entry->sect) { + elf_secthead *shead = + yasm_section_get_data(entry->sect, &elf_section_data); + if (!shead) + yasm_internal_error(N_("symbol references section without data")); + YASM_WRITE_16_L(bufp, shead->index); + } else { + YASM_WRITE_16_L(bufp, entry->index); + } + YASM_WRITE_64I_L(bufp, value_intn); + YASM_WRITE_64I_L(bufp, size_intn); +} + +static void +elf_x86_amd64_write_secthead(unsigned char *bufp, elf_secthead *shead) +{ + YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); + YASM_WRITE_32_L(bufp, shead->type); + YASM_WRITE_64Z_L(bufp, shead->flags); + YASM_WRITE_64Z_L(bufp, 0); /* vmem address */ + YASM_WRITE_64Z_L(bufp, shead->offset); + YASM_WRITE_64I_L(bufp, shead->size); + + YASM_WRITE_32_L(bufp, shead->link); + YASM_WRITE_32_L(bufp, shead->info); + + YASM_WRITE_64Z_L(bufp, shead->align); + YASM_WRITE_64Z_L(bufp, shead->entsize); +} + +static void +elf_x86_amd64_write_secthead_rel(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex) +{ + yasm_intnum *nreloc; + yasm_intnum *relocsize; + + YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); + YASM_WRITE_32_L(bufp, SHT_RELA); + YASM_WRITE_64Z_L(bufp, 0); + YASM_WRITE_64Z_L(bufp, 0); + YASM_WRITE_64Z_L(bufp, shead->rel_offset); + + nreloc = yasm_intnum_create_uint(shead->nreloc); + relocsize = yasm_intnum_create_uint(RELOC64A_SIZE); + yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc); + YASM_WRITE_64I_L(bufp, relocsize); /* size */ + yasm_intnum_destroy(nreloc); + yasm_intnum_destroy(relocsize); + + YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ + YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ + YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN); /* align */ + YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE); /* entity size */ +} + +static void +elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + /* .rela: copy value out as addend, replace original with 0 */ + reloc->addend = yasm_intnum_copy(intn); + yasm_intnum_zero(intn); +} + +static unsigned int +elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc) +{ + if (reloc->wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); + if (!ssym || reloc->valsize != ssym->size) + yasm_internal_error(N_("Unsupported WRT")); + + /* Force TLS type; this is required by the linker. */ + if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + esym->type = STT_TLS; + } + /* Map PC-relative GOT to appropriate relocation */ + if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32) + return (unsigned char) R_X86_64_GOTPCREL; + return (unsigned char) ssym->reloc; + } else if (reloc->is_GOT_sym && reloc->valsize == 32) { + return (unsigned char) R_X86_64_GOTPC32; + } else if (reloc->is_GOT_sym && reloc->valsize == 64) { + return (unsigned char) R_X86_64_GOTPC64; + } else if (reloc->rtype_rel) { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_PC8; + case 16: return (unsigned char) R_X86_64_PC16; + case 32: return (unsigned char) R_X86_64_PC32; + case 64: return (unsigned char) R_X86_64_PC64; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } else { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_8; + case 16: return (unsigned char) R_X86_64_16; + case 32: return (unsigned char) R_X86_64_32; + case 64: return (unsigned char) R_X86_64_64; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } + return 0; +} + +static void +elf_x86_amd64_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, + unsigned int r_type, unsigned int r_sym) +{ + YASM_WRITE_64I_L(bufp, reloc->reloc.addr); + /*YASM_WRITE_64_L(bufp, ELF64_R_INFO(r_sym, r_type));*/ + YASM_WRITE_64C_L(bufp, r_sym, r_type); + if (reloc->addend) + YASM_WRITE_64I_L(bufp, reloc->addend); + else { + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, 0); + } +} + +static void +elf_x86_amd64_write_proghead(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char *bufp = *bufpp; + unsigned char *buf = bufp-4; + YASM_WRITE_8(bufp, ELFCLASS64); /* elf class */ + YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ + YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */ + YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */ + while (bufp-buf < EI_NIDENT) /* e_ident padding */ + YASM_WRITE_8(bufp, 0); + + YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ + YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */ + YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_64Z_L(bufp, 0); /* e_entry */ + YASM_WRITE_64Z_L(bufp, 0); /* e_phoff */ + YASM_WRITE_64Z_L(bufp, secthead_addr); /* e_shoff secthead off */ + + YASM_WRITE_32_L(bufp, 0); /* e_flags */ + YASM_WRITE_16_L(bufp, EHDR64_SIZE); /* e_ehsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phnum */ + YASM_WRITE_16_L(bufp, SHDR64_SIZE); /* e_shentsize */ + YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ + YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ + *bufpp = bufp; +} + +const elf_machine_handler +elf_machine_handler_x86_amd64 = { + "x86", "amd64", ".rela", + SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE, + elf_x86_amd64_accepts_reloc, + elf_x86_amd64_write_symtab_entry, + elf_x86_amd64_write_secthead, + elf_x86_amd64_write_secthead_rel, + elf_x86_amd64_handle_reloc_addend, + elf_x86_amd64_map_reloc_info_to_type, + elf_x86_amd64_write_reloc, + elf_x86_amd64_write_proghead, + elf_x86_amd64_ssyms, + sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]), + 64 +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c index 40a25a12a7..aad2d10dac 100644 --- a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x32.c @@ -1,251 +1,251 @@ -/* - * ELF object format helpers - x86:x32 - * - * Copyright (C) 2012 Michael Urman and H.J. Lu - * - * 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 YASM_OBJFMT_ELF_INTERNAL -#include "elf.h" -#include "elf-machine.h" - -static elf_machine_ssym elf_x86_x32_ssyms[] = { - {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32}, - {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32}, - {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TLSGD, 32}, - {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TLSLD, 32}, - {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_GOTTPOFF, 32}, - {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TPOFF32, 32}, - {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_DTPOFF32, 32}, - {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32}, - {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_GOTPC32_TLSDESC, 32}, - {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_X86_64_TLSDESC_CALL, 32} -}; - -static int -elf_x86_x32_accepts_reloc(size_t val, yasm_symrec *wrt) -{ - if (wrt) { - const elf_machine_ssym *ssym = (elf_machine_ssym *) - yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); - if (!ssym || val != ssym->size) - return 0; - return 1; - } - return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); -} - -static void -elf_x86_x32_write_symtab_entry(unsigned char *bufp, - elf_symtab_entry *entry, - yasm_intnum *value_intn, - yasm_intnum *size_intn) -{ - YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); - YASM_WRITE_32I_L(bufp, value_intn); - YASM_WRITE_32I_L(bufp, size_intn); - - YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type)); - YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis)); - if (entry->sect) { - elf_secthead *shead = - yasm_section_get_data(entry->sect, &elf_section_data); - if (!shead) - yasm_internal_error(N_("symbol references section without data")); - YASM_WRITE_16_L(bufp, shead->index); - } else { - YASM_WRITE_16_L(bufp, entry->index); - } -} - -static void -elf_x86_x32_write_secthead(unsigned char *bufp, elf_secthead *shead) -{ - YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); - YASM_WRITE_32_L(bufp, shead->type); - YASM_WRITE_32_L(bufp, shead->flags); - YASM_WRITE_32_L(bufp, 0); /* vmem address */ - YASM_WRITE_32_L(bufp, shead->offset); - YASM_WRITE_32I_L(bufp, shead->size); - - YASM_WRITE_32_L(bufp, shead->link); - YASM_WRITE_32_L(bufp, shead->info); - - YASM_WRITE_32_L(bufp, shead->align); - YASM_WRITE_32_L(bufp, shead->entsize); -} - -static void -elf_x86_x32_write_secthead_rel(unsigned char *bufp, - elf_secthead *shead, - elf_section_index symtab_idx, - elf_section_index sindex) -{ - yasm_intnum *nreloc; - yasm_intnum *relocsize; - - YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); - YASM_WRITE_32_L(bufp, SHT_RELA); - YASM_WRITE_32_L(bufp, 0); - YASM_WRITE_32_L(bufp, 0); - YASM_WRITE_32_L(bufp, shead->rel_offset); - - nreloc = yasm_intnum_create_uint(shead->nreloc); - relocsize = yasm_intnum_create_uint(RELOC32A_SIZE); - yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc); - YASM_WRITE_32I_L(bufp, relocsize); /* size */ - yasm_intnum_destroy(nreloc); - yasm_intnum_destroy(relocsize); - - YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ - YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ - YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */ - YASM_WRITE_32_L(bufp, RELOC32A_SIZE); /* entity size */ -} - -static void -elf_x86_x32_handle_reloc_addend(yasm_intnum *intn, - elf_reloc_entry *reloc, - unsigned long offset) -{ - /* .rela: copy value out as addend, replace original with 0 */ - reloc->addend = yasm_intnum_copy(intn); - yasm_intnum_zero(intn); -} - -static unsigned int -elf_x86_x32_map_reloc_info_to_type(elf_reloc_entry *reloc) -{ - if (reloc->wrt) { - const elf_machine_ssym *ssym = (elf_machine_ssym *) - yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); - if (!ssym || reloc->valsize != ssym->size) - yasm_internal_error(N_("Unsupported WRT")); - - /* Force TLS type; this is required by the linker. */ - if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { - elf_symtab_entry *esym; - - esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); - if (esym) - esym->type = STT_TLS; - } - /* Map PC-relative GOT to appropriate relocation */ - if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32) - return (unsigned char) R_X86_64_GOTPCREL; - return (unsigned char) ssym->reloc; - } else if (reloc->is_GOT_sym && reloc->valsize == 32) { - return (unsigned char) R_X86_64_GOTPC32; - } else if (reloc->is_GOT_sym && reloc->valsize == 64) { - yasm_internal_error(N_("Unsupported relocation size")); - } else if (reloc->rtype_rel) { - switch (reloc->valsize) { - case 8: return (unsigned char) R_X86_64_PC8; - case 16: return (unsigned char) R_X86_64_PC16; - case 32: return (unsigned char) R_X86_64_PC32; - default: yasm_internal_error(N_("Unsupported relocation size")); - } - } else { - switch (reloc->valsize) { - case 8: return (unsigned char) R_X86_64_8; - case 16: return (unsigned char) R_X86_64_16; - case 32: return (unsigned char) R_X86_64_32; - case 64: return (unsigned char) R_X86_64_64; - default: yasm_internal_error(N_("Unsupported relocation size")); - } - } - return 0; -} - -static void -elf_x86_x32_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, - unsigned int r_type, unsigned int r_sym) -{ - YASM_WRITE_32I_L(bufp, reloc->reloc.addr); - YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type)); - if (reloc->addend) - YASM_WRITE_32I_L(bufp, reloc->addend); - else { - YASM_WRITE_32_L(bufp, 0); - } -} - -static void -elf_x86_x32_write_proghead(unsigned char **bufpp, - elf_offset secthead_addr, - unsigned long secthead_count, - elf_section_index shstrtab_index) -{ - unsigned char *bufp = *bufpp; - unsigned char *buf = bufp-4; - YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */ - YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ - YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ - YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */ - YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */ - while (bufp-buf < EI_NIDENT) /* e_ident padding */ - YASM_WRITE_8(bufp, 0); - - YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ - YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */ - YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ - YASM_WRITE_32_L(bufp, 0); /* e_entry */ - YASM_WRITE_32_L(bufp, 0); /* e_phoff */ - YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff secthead off */ - - YASM_WRITE_32_L(bufp, 0); /* e_flags */ - YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */ - YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ - YASM_WRITE_16_L(bufp, 0); /* e_phnum */ - YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */ - YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ - YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ - *bufpp = bufp; -} - -const elf_machine_handler -elf_machine_handler_x86_x32 = { - "x86", "x32", ".rela", - SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32A_SIZE, SHDR32_SIZE, EHDR32_SIZE, - elf_x86_x32_accepts_reloc, - elf_x86_x32_write_symtab_entry, - elf_x86_x32_write_secthead, - elf_x86_x32_write_secthead_rel, - elf_x86_x32_handle_reloc_addend, - elf_x86_x32_map_reloc_info_to_type, - elf_x86_x32_write_reloc, - elf_x86_x32_write_proghead, - elf_x86_x32_ssyms, - sizeof(elf_x86_x32_ssyms)/sizeof(elf_x86_x32_ssyms[0]), - 32 -}; +/* + * ELF object format helpers - x86:x32 + * + * Copyright (C) 2012 Michael Urman and H.J. Lu + * + * 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 YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static elf_machine_ssym elf_x86_x32_ssyms[] = { + {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32}, + {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32}, + {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSGD, 32}, + {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSLD, 32}, + {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTTPOFF, 32}, + {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TPOFF32, 32}, + {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_DTPOFF32, 32}, + {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32}, + {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_GOTPC32_TLSDESC, 32}, + {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_X86_64_TLSDESC_CALL, 32} +}; + +static int +elf_x86_x32_accepts_reloc(size_t val, yasm_symrec *wrt) +{ + if (wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); + if (!ssym || val != ssym->size) + return 0; + return 1; + } + return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); +} + +static void +elf_x86_x32_write_symtab_entry(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn) +{ + YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); + YASM_WRITE_32I_L(bufp, value_intn); + YASM_WRITE_32I_L(bufp, size_intn); + + YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type)); + YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis)); + if (entry->sect) { + elf_secthead *shead = + yasm_section_get_data(entry->sect, &elf_section_data); + if (!shead) + yasm_internal_error(N_("symbol references section without data")); + YASM_WRITE_16_L(bufp, shead->index); + } else { + YASM_WRITE_16_L(bufp, entry->index); + } +} + +static void +elf_x86_x32_write_secthead(unsigned char *bufp, elf_secthead *shead) +{ + YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); + YASM_WRITE_32_L(bufp, shead->type); + YASM_WRITE_32_L(bufp, shead->flags); + YASM_WRITE_32_L(bufp, 0); /* vmem address */ + YASM_WRITE_32_L(bufp, shead->offset); + YASM_WRITE_32I_L(bufp, shead->size); + + YASM_WRITE_32_L(bufp, shead->link); + YASM_WRITE_32_L(bufp, shead->info); + + YASM_WRITE_32_L(bufp, shead->align); + YASM_WRITE_32_L(bufp, shead->entsize); +} + +static void +elf_x86_x32_write_secthead_rel(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex) +{ + yasm_intnum *nreloc; + yasm_intnum *relocsize; + + YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); + YASM_WRITE_32_L(bufp, SHT_RELA); + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, shead->rel_offset); + + nreloc = yasm_intnum_create_uint(shead->nreloc); + relocsize = yasm_intnum_create_uint(RELOC32A_SIZE); + yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc); + YASM_WRITE_32I_L(bufp, relocsize); /* size */ + yasm_intnum_destroy(nreloc); + yasm_intnum_destroy(relocsize); + + YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ + YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ + YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */ + YASM_WRITE_32_L(bufp, RELOC32A_SIZE); /* entity size */ +} + +static void +elf_x86_x32_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + /* .rela: copy value out as addend, replace original with 0 */ + reloc->addend = yasm_intnum_copy(intn); + yasm_intnum_zero(intn); +} + +static unsigned int +elf_x86_x32_map_reloc_info_to_type(elf_reloc_entry *reloc) +{ + if (reloc->wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); + if (!ssym || reloc->valsize != ssym->size) + yasm_internal_error(N_("Unsupported WRT")); + + /* Force TLS type; this is required by the linker. */ + if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + esym->type = STT_TLS; + } + /* Map PC-relative GOT to appropriate relocation */ + if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32) + return (unsigned char) R_X86_64_GOTPCREL; + return (unsigned char) ssym->reloc; + } else if (reloc->is_GOT_sym && reloc->valsize == 32) { + return (unsigned char) R_X86_64_GOTPC32; + } else if (reloc->is_GOT_sym && reloc->valsize == 64) { + yasm_internal_error(N_("Unsupported relocation size")); + } else if (reloc->rtype_rel) { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_PC8; + case 16: return (unsigned char) R_X86_64_PC16; + case 32: return (unsigned char) R_X86_64_PC32; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } else { + switch (reloc->valsize) { + case 8: return (unsigned char) R_X86_64_8; + case 16: return (unsigned char) R_X86_64_16; + case 32: return (unsigned char) R_X86_64_32; + case 64: return (unsigned char) R_X86_64_64; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } + return 0; +} + +static void +elf_x86_x32_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, + unsigned int r_type, unsigned int r_sym) +{ + YASM_WRITE_32I_L(bufp, reloc->reloc.addr); + YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type)); + if (reloc->addend) + YASM_WRITE_32I_L(bufp, reloc->addend); + else { + YASM_WRITE_32_L(bufp, 0); + } +} + +static void +elf_x86_x32_write_proghead(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char *bufp = *bufpp; + unsigned char *buf = bufp-4; + YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */ + YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ + YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */ + YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */ + while (bufp-buf < EI_NIDENT) /* e_ident padding */ + YASM_WRITE_8(bufp, 0); + + YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ + YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */ + YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_32_L(bufp, 0); /* e_entry */ + YASM_WRITE_32_L(bufp, 0); /* e_phoff */ + YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff secthead off */ + + YASM_WRITE_32_L(bufp, 0); /* e_flags */ + YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phnum */ + YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */ + YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ + YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ + *bufpp = bufp; +} + +const elf_machine_handler +elf_machine_handler_x86_x32 = { + "x86", "x32", ".rela", + SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32A_SIZE, SHDR32_SIZE, EHDR32_SIZE, + elf_x86_x32_accepts_reloc, + elf_x86_x32_write_symtab_entry, + elf_x86_x32_write_secthead, + elf_x86_x32_write_secthead_rel, + elf_x86_x32_handle_reloc_addend, + elf_x86_x32_map_reloc_info_to_type, + elf_x86_x32_write_reloc, + elf_x86_x32_write_proghead, + elf_x86_x32_ssyms, + sizeof(elf_x86_x32_ssyms)/sizeof(elf_x86_x32_ssyms[0]), + 32 +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c index d79ec6eabd..8ebaa87381 100644 --- a/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c +++ b/contrib/tools/yasm/modules/objfmts/elf/elf-x86-x86.c @@ -1,242 +1,242 @@ -/* - * ELF object format helpers - x86:x86 - * - * Copyright (C) 2004-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> - -#include <libyasm.h> -#define YASM_OBJFMT_ELF_INTERNAL -#include "elf.h" -#include "elf-machine.h" - -static elf_machine_ssym elf_x86_x86_ssyms[] = { - {"plt", ELF_SSYM_SYM_RELATIVE, R_386_PLT32, 32}, - {"gotoff", 0, R_386_GOTOFF, 32}, - /* special one for NASM */ - {"gotpc", ELF_SSYM_CURPOS_ADJUST, R_386_GOTPC, 32}, - {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_GD, 32}, - {"tlsldm", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_LDM, 32}, - {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_IE_32, 32}, - {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_LE_32, 32}, - {"ntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_LE, 32}, - {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_LDO_32, 32}, - {"gotntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_GOTIE, 32}, - {"indntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_IE, 32}, - {"got", ELF_SSYM_SYM_RELATIVE, R_386_GOT32, 32}, - {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_GOTDESC, 32}, - {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, - R_386_TLS_DESC_CALL, 32} -}; - -static int -elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt) -{ - if (wrt) { - const elf_machine_ssym *ssym = (elf_machine_ssym *) - yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); - if (!ssym || val != ssym->size) - return 0; - return 1; - } - return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); -} - -static void -elf_x86_x86_write_symtab_entry(unsigned char *bufp, - elf_symtab_entry *entry, - yasm_intnum *value_intn, - yasm_intnum *size_intn) -{ - YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); - YASM_WRITE_32I_L(bufp, value_intn); - YASM_WRITE_32I_L(bufp, size_intn); - - YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type)); - YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis)); - if (entry->sect) { - elf_secthead *shead = - yasm_section_get_data(entry->sect, &elf_section_data); - if (!shead) - yasm_internal_error(N_("symbol references section without data")); - YASM_WRITE_16_L(bufp, shead->index); - } else { - YASM_WRITE_16_L(bufp, entry->index); - } -} - -static void -elf_x86_x86_write_secthead(unsigned char *bufp, elf_secthead *shead) -{ - YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); - YASM_WRITE_32_L(bufp, shead->type); - YASM_WRITE_32_L(bufp, shead->flags); - YASM_WRITE_32_L(bufp, 0); /* vmem address */ - - YASM_WRITE_32_L(bufp, shead->offset); - YASM_WRITE_32I_L(bufp, shead->size); - YASM_WRITE_32_L(bufp, shead->link); - YASM_WRITE_32_L(bufp, shead->info); - - YASM_WRITE_32_L(bufp, shead->align); - YASM_WRITE_32_L(bufp, shead->entsize); - -} - -static void -elf_x86_x86_write_secthead_rel(unsigned char *bufp, - elf_secthead *shead, - elf_section_index symtab_idx, - elf_section_index sindex) -{ - YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); - YASM_WRITE_32_L(bufp, SHT_REL); - YASM_WRITE_32_L(bufp, 0); - YASM_WRITE_32_L(bufp, 0); - - YASM_WRITE_32_L(bufp, shead->rel_offset); - YASM_WRITE_32_L(bufp, RELOC32_SIZE * shead->nreloc);/* size */ - YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ - YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ - - YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */ - YASM_WRITE_32_L(bufp, RELOC32_SIZE); /* entity size */ -} - -static void -elf_x86_x86_handle_reloc_addend(yasm_intnum *intn, - elf_reloc_entry *reloc, - unsigned long offset) -{ - if (!reloc->wrt && reloc->is_GOT_sym && reloc->valsize == 32 && offset != 0) - { - yasm_intnum *off_intn = yasm_intnum_create_uint(offset); - yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn); - yasm_intnum_destroy(off_intn); - } - return; /* .rel: Leave addend in intn */ -} - -static unsigned int -elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc) -{ - if (reloc->wrt) { - const elf_machine_ssym *ssym = (elf_machine_ssym *) - yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); - if (!ssym || reloc->valsize != ssym->size) - yasm_internal_error(N_("Unsupported WRT")); - - /* Force TLS type; this is required by the linker. */ - if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { - elf_symtab_entry *esym; - - esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); - if (esym) - esym->type = STT_TLS; - } - return (unsigned char) ssym->reloc; - } else if (reloc->is_GOT_sym && reloc->valsize == 32) { - return (unsigned char) R_386_GOTPC; - } else if (reloc->rtype_rel) { - switch (reloc->valsize) { - case 8: return (unsigned char) R_386_PC8; - case 16: return (unsigned char) R_386_PC16; - case 32: return (unsigned char) R_386_PC32; - default: yasm_internal_error(N_("Unsupported relocation size")); - } - } else { - switch (reloc->valsize) { - case 8: return (unsigned char) R_386_8; - case 16: return (unsigned char) R_386_16; - case 32: return (unsigned char) R_386_32; - default: yasm_internal_error(N_("Unsupported relocation size")); - } - } - return 0; -} - -static void -elf_x86_x86_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, - unsigned int r_type, unsigned int r_sym) -{ - YASM_WRITE_32I_L(bufp, reloc->reloc.addr); - YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type)); -} - -static void -elf_x86_x86_write_proghead(unsigned char **bufpp, - elf_offset secthead_addr, - unsigned long secthead_count, - elf_section_index shstrtab_index) -{ - unsigned char *bufp = *bufpp; - unsigned char *buf = bufp-4; - YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */ - YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ - YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ - while (bufp-buf < EI_NIDENT) /* e_ident padding */ - YASM_WRITE_8(bufp, 0); - - YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ - YASM_WRITE_16_L(bufp, EM_386); /* e_machine - or others */ - YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ - YASM_WRITE_32_L(bufp, 0); /* e_entry exection startaddr */ - YASM_WRITE_32_L(bufp, 0); /* e_phoff program header off */ - YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff section header off */ - YASM_WRITE_32_L(bufp, 0); /* e_flags also by arch */ - YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */ - YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ - YASM_WRITE_16_L(bufp, 0); /* e_phnum */ - YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */ - YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ - YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ - *bufpp = bufp; -} - -const elf_machine_handler -elf_machine_handler_x86_x86 = { - "x86", "x86", ".rel", - SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE, - elf_x86_x86_accepts_reloc, - elf_x86_x86_write_symtab_entry, - elf_x86_x86_write_secthead, - elf_x86_x86_write_secthead_rel, - elf_x86_x86_handle_reloc_addend, - elf_x86_x86_map_reloc_info_to_type, - elf_x86_x86_write_reloc, - elf_x86_x86_write_proghead, - elf_x86_x86_ssyms, - sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0]), - 32 -}; +/* + * ELF object format helpers - x86:x86 + * + * Copyright (C) 2004-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> + +#include <libyasm.h> +#define YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static elf_machine_ssym elf_x86_x86_ssyms[] = { + {"plt", ELF_SSYM_SYM_RELATIVE, R_386_PLT32, 32}, + {"gotoff", 0, R_386_GOTOFF, 32}, + /* special one for NASM */ + {"gotpc", ELF_SSYM_CURPOS_ADJUST, R_386_GOTPC, 32}, + {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_GD, 32}, + {"tlsldm", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LDM, 32}, + {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_IE_32, 32}, + {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LE_32, 32}, + {"ntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LE, 32}, + {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_LDO_32, 32}, + {"gotntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_GOTIE, 32}, + {"indntpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_IE, 32}, + {"got", ELF_SSYM_SYM_RELATIVE, R_386_GOT32, 32}, + {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_GOTDESC, 32}, + {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL, + R_386_TLS_DESC_CALL, 32} +}; + +static int +elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt) +{ + if (wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(wrt, &elf_ssym_symrec_data); + if (!ssym || val != ssym->size) + return 0; + return 1; + } + return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); +} + +static void +elf_x86_x86_write_symtab_entry(unsigned char *bufp, + elf_symtab_entry *entry, + yasm_intnum *value_intn, + yasm_intnum *size_intn) +{ + YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0); + YASM_WRITE_32I_L(bufp, value_intn); + YASM_WRITE_32I_L(bufp, size_intn); + + YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type)); + YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis)); + if (entry->sect) { + elf_secthead *shead = + yasm_section_get_data(entry->sect, &elf_section_data); + if (!shead) + yasm_internal_error(N_("symbol references section without data")); + YASM_WRITE_16_L(bufp, shead->index); + } else { + YASM_WRITE_16_L(bufp, entry->index); + } +} + +static void +elf_x86_x86_write_secthead(unsigned char *bufp, elf_secthead *shead) +{ + YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0); + YASM_WRITE_32_L(bufp, shead->type); + YASM_WRITE_32_L(bufp, shead->flags); + YASM_WRITE_32_L(bufp, 0); /* vmem address */ + + YASM_WRITE_32_L(bufp, shead->offset); + YASM_WRITE_32I_L(bufp, shead->size); + YASM_WRITE_32_L(bufp, shead->link); + YASM_WRITE_32_L(bufp, shead->info); + + YASM_WRITE_32_L(bufp, shead->align); + YASM_WRITE_32_L(bufp, shead->entsize); + +} + +static void +elf_x86_x86_write_secthead_rel(unsigned char *bufp, + elf_secthead *shead, + elf_section_index symtab_idx, + elf_section_index sindex) +{ + YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0); + YASM_WRITE_32_L(bufp, SHT_REL); + YASM_WRITE_32_L(bufp, 0); + YASM_WRITE_32_L(bufp, 0); + + YASM_WRITE_32_L(bufp, shead->rel_offset); + YASM_WRITE_32_L(bufp, RELOC32_SIZE * shead->nreloc);/* size */ + YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */ + YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */ + + YASM_WRITE_32_L(bufp, RELOC32_ALIGN); /* align */ + YASM_WRITE_32_L(bufp, RELOC32_SIZE); /* entity size */ +} + +static void +elf_x86_x86_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + if (!reloc->wrt && reloc->is_GOT_sym && reloc->valsize == 32 && offset != 0) + { + yasm_intnum *off_intn = yasm_intnum_create_uint(offset); + yasm_intnum_calc(intn, YASM_EXPR_ADD, off_intn); + yasm_intnum_destroy(off_intn); + } + return; /* .rel: Leave addend in intn */ +} + +static unsigned int +elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc) +{ + if (reloc->wrt) { + const elf_machine_ssym *ssym = (elf_machine_ssym *) + yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data); + if (!ssym || reloc->valsize != ssym->size) + yasm_internal_error(N_("Unsupported WRT")); + + /* Force TLS type; this is required by the linker. */ + if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) { + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + esym->type = STT_TLS; + } + return (unsigned char) ssym->reloc; + } else if (reloc->is_GOT_sym && reloc->valsize == 32) { + return (unsigned char) R_386_GOTPC; + } else if (reloc->rtype_rel) { + switch (reloc->valsize) { + case 8: return (unsigned char) R_386_PC8; + case 16: return (unsigned char) R_386_PC16; + case 32: return (unsigned char) R_386_PC32; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } else { + switch (reloc->valsize) { + case 8: return (unsigned char) R_386_8; + case 16: return (unsigned char) R_386_16; + case 32: return (unsigned char) R_386_32; + default: yasm_internal_error(N_("Unsupported relocation size")); + } + } + return 0; +} + +static void +elf_x86_x86_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc, + unsigned int r_type, unsigned int r_sym) +{ + YASM_WRITE_32I_L(bufp, reloc->reloc.addr); + YASM_WRITE_32_L(bufp, ELF32_R_INFO((unsigned long)r_sym, (unsigned char)r_type)); +} + +static void +elf_x86_x86_write_proghead(unsigned char **bufpp, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char *bufp = *bufpp; + unsigned char *buf = bufp-4; + YASM_WRITE_8(bufp, ELFCLASS32); /* elf class */ + YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */ + YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */ + while (bufp-buf < EI_NIDENT) /* e_ident padding */ + YASM_WRITE_8(bufp, 0); + + YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */ + YASM_WRITE_16_L(bufp, EM_386); /* e_machine - or others */ + YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */ + YASM_WRITE_32_L(bufp, 0); /* e_entry exection startaddr */ + YASM_WRITE_32_L(bufp, 0); /* e_phoff program header off */ + YASM_WRITE_32_L(bufp, secthead_addr); /* e_shoff section header off */ + YASM_WRITE_32_L(bufp, 0); /* e_flags also by arch */ + YASM_WRITE_16_L(bufp, EHDR32_SIZE); /* e_ehsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phentsize */ + YASM_WRITE_16_L(bufp, 0); /* e_phnum */ + YASM_WRITE_16_L(bufp, SHDR32_SIZE); /* e_shentsize */ + YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */ + YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */ + *bufpp = bufp; +} + +const elf_machine_handler +elf_machine_handler_x86_x86 = { + "x86", "x86", ".rel", + SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE, + elf_x86_x86_accepts_reloc, + elf_x86_x86_write_symtab_entry, + elf_x86_x86_write_secthead, + elf_x86_x86_write_secthead_rel, + elf_x86_x86_handle_reloc_addend, + elf_x86_x86_map_reloc_info_to_type, + elf_x86_x86_write_reloc, + elf_x86_x86_write_proghead, + elf_x86_x86_ssyms, + sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0]), + 32 +}; diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf.c b/contrib/tools/yasm/modules/objfmts/elf/elf.c index 2486bba8df..04f3fe661a 100644 --- a/contrib/tools/yasm/modules/objfmts/elf/elf.c +++ b/contrib/tools/yasm/modules/objfmts/elf/elf.c @@ -1,960 +1,960 @@ -/* - * ELF object format helpers - * - * 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> - -#include <libyasm.h> -#define YASM_OBJFMT_ELF_INTERNAL -#include "elf.h" -#include "elf-machine.h" - -static void elf_section_data_destroy(void *data); -static void elf_secthead_print(void *data, FILE *f, int indent_level); - -const yasm_assoc_data_callback elf_section_data = { - elf_section_data_destroy, - elf_secthead_print -}; - -static void elf_symrec_data_destroy(/*@only@*/ void *d); -static void elf_symtab_entry_print(void *data, FILE *f, int indent_level); -static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level); - -const yasm_assoc_data_callback elf_symrec_data = { - elf_symrec_data_destroy, - elf_symtab_entry_print -}; - -const yasm_assoc_data_callback elf_ssym_symrec_data = { - elf_symrec_data_destroy, - elf_ssym_symtab_entry_print -}; - -extern elf_machine_handler - elf_machine_handler_x86_x86, - elf_machine_handler_x86_amd64, - elf_machine_handler_x86_x32; - -static const elf_machine_handler *elf_machine_handlers[] = -{ - &elf_machine_handler_x86_x86, - &elf_machine_handler_x86_amd64, - &elf_machine_handler_x86_x32, - NULL -}; -static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0}; -static elf_machine_handler const *elf_march = &elf_null_machine; -static yasm_symrec **elf_ssyms; - -const elf_machine_handler * -elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref) -{ - const char *machine = yasm_arch_get_machine(arch); - int i; - - for (i=0, elf_march = elf_machine_handlers[0]; - elf_march != NULL; - elf_march = elf_machine_handlers[++i]) - { - if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0) { - if (yasm__strcasecmp(machine, elf_march->machine)==0) { - if (bits_pref == 0 || bits_pref == elf_march->bits) - break; - } else if (bits_pref == elf_march->bits - && yasm__strcasecmp(machine, "amd64") == 0 - && yasm__strcasecmp(elf_march->machine, "x32") == 0) - break; - } - } - - if (elf_march && elf_march->num_ssyms > 0) - { - /* Allocate "special" syms */ - elf_ssyms = - yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *)); - for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) - { - /* FIXME: misuse of NULL bytecode */ - elf_ssyms[i] = yasm_symtab_define_label(symtab, - elf_march->ssyms[i].name, - NULL, 0, 0); - yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data, - (void*)&elf_march->ssyms[i]); - } - } - - return elf_march; -} - -yasm_symrec * -elf_get_special_sym(const char *name, const char *parser) -{ - int i; - for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) { - if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0) - return elf_ssyms[i]; - } - return NULL; -} - -/* reloc functions */ -int elf_ssym_has_flag(yasm_symrec *wrt, int flag); - -int -elf_is_wrt_sym_relative(yasm_symrec *wrt) -{ - return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE); -} - -int -elf_is_wrt_pos_adjusted(yasm_symrec *wrt) -{ - return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST); -} - -int -elf_ssym_has_flag(yasm_symrec *wrt, int flag) -{ - int i; - for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) { - if (elf_ssyms[i] == wrt) - return (elf_march->ssyms[i].sym_rel & flag) != 0; - } - return 0; -} - -/* takes ownership of addr */ -elf_reloc_entry * -elf_reloc_entry_create(yasm_symrec *sym, - yasm_symrec *wrt, - yasm_intnum *addr, - int rel, - size_t valsize, - int is_GOT_sym) -{ - elf_reloc_entry *entry; - - if (!elf_march->accepts_reloc) - yasm_internal_error(N_("Unsupported machine for ELF output")); - - if (!elf_march->accepts_reloc(valsize, wrt)) - { - if (addr) - yasm_intnum_destroy(addr); - return NULL; - } - - if (sym == NULL) - yasm_internal_error("sym is null"); - - entry = yasm_xmalloc(sizeof(elf_reloc_entry)); - entry->reloc.sym = sym; - entry->reloc.addr = addr; - entry->rtype_rel = rel; - entry->valsize = valsize; - entry->addend = NULL; - entry->wrt = wrt; - entry->is_GOT_sym = is_GOT_sym; - - return entry; -} - -void -elf_reloc_entry_destroy(void *entry) -{ - if (((elf_reloc_entry*)entry)->addend) - yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend); - yasm_xfree(entry); -} - -/* strtab functions */ -elf_strtab_entry * -elf_strtab_entry_create(const char *str) -{ - elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry)); - entry->str = yasm__xstrdup(str); - entry->index = 0; - return entry; -} - -void -elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str) -{ - elf_strtab_entry *last; - if (entry->str) - yasm_xfree(entry->str); - entry->str = yasm__xstrdup(str); - - /* Update all following indices since string length probably changes */ - last = entry; - entry = STAILQ_NEXT(last, qlink); - while (entry) { - entry->index = last->index + (unsigned long)strlen(last->str) + 1; - last = entry; - entry = STAILQ_NEXT(last, qlink); - } -} - -elf_strtab_head * -elf_strtab_create() -{ - elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head)); - elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry)); - - STAILQ_INIT(strtab); - entry->index = 0; - entry->str = yasm__xstrdup(""); - - STAILQ_INSERT_TAIL(strtab, entry, qlink); - return strtab; -} - -elf_strtab_entry * -elf_strtab_append_str(elf_strtab_head *strtab, const char *str) -{ - elf_strtab_entry *last, *entry; - - if (strtab == NULL) - yasm_internal_error("strtab is null"); - if (STAILQ_EMPTY(strtab)) - yasm_internal_error("strtab is missing initial dummy entry"); - - last = STAILQ_LAST(strtab, elf_strtab_entry, qlink); - - entry = elf_strtab_entry_create(str); - entry->index = last->index + (unsigned long)strlen(last->str) + 1; - - STAILQ_INSERT_TAIL(strtab, entry, qlink); - return entry; -} - -void -elf_strtab_destroy(elf_strtab_head *strtab) -{ - elf_strtab_entry *s1, *s2; - - if (strtab == NULL) - yasm_internal_error("strtab is null"); - if (STAILQ_EMPTY(strtab)) - yasm_internal_error("strtab is missing initial dummy entry"); - - s1 = STAILQ_FIRST(strtab); - while (s1 != NULL) { - s2 = STAILQ_NEXT(s1, qlink); - yasm_xfree(s1->str); - yasm_xfree(s1); - s1 = s2; - } - yasm_xfree(strtab); -} - -unsigned long -elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab) -{ - unsigned long size = 0; - elf_strtab_entry *entry; - - if (strtab == NULL) - yasm_internal_error("strtab is null"); - - /* consider optimizing tables here */ - STAILQ_FOREACH(entry, strtab, qlink) { - size_t len = 1 + strlen(entry->str); - fwrite(entry->str, len, 1, f); - size += (unsigned long)len; - } - return size; -} - - - -/* symtab functions */ -elf_symtab_entry * -elf_symtab_entry_create(elf_strtab_entry *name, - yasm_symrec *sym) -{ - elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry)); - entry->in_table = 0; - entry->sym = sym; - entry->sect = NULL; - entry->name = name; - entry->value = 0; - - entry->xsize = NULL; - entry->size = 0; - entry->index = 0; - entry->bind = 0; - entry->type = STT_NOTYPE; - entry->vis = STV_DEFAULT; - - return entry; -} - -static void -elf_symtab_entry_destroy(elf_symtab_entry *entry) -{ - if (entry == NULL) - yasm_internal_error("symtab entry is null"); - - yasm_xfree(entry); -} - -static void -elf_symrec_data_destroy(void *data) -{ - /* do nothing, as this stuff is in the symtab anyway... this speaks of bad - * design/use or this stuff, i fear */ - - /* watch for double-free here ... */ - /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/ -} - -static void -elf_symtab_entry_print(void *data, FILE *f, int indent_level) -{ - elf_symtab_entry *entry = data; - if (entry == NULL) - yasm_internal_error("symtab entry is null"); - - fprintf(f, "%*sbind=", indent_level, ""); - switch (entry->bind) { - case STB_LOCAL: fprintf(f, "local\n"); break; - case STB_GLOBAL: fprintf(f, "global\n"); break; - case STB_WEAK: fprintf(f, "weak\n"); break; - default: fprintf(f, "undef\n"); break; - } - fprintf(f, "%*stype=", indent_level, ""); - switch (entry->type) { - case STT_NOTYPE: fprintf(f, "notype\n"); break; - case STT_OBJECT: fprintf(f, "object\n"); break; - case STT_FUNC: fprintf(f, "func\n"); break; - case STT_SECTION: fprintf(f, "section\n");break; - case STT_FILE: fprintf(f, "file\n"); break; - default: fprintf(f, "undef\n"); break; - } - fprintf(f, "%*ssize=", indent_level, ""); - if (entry->xsize) - yasm_expr_print(entry->xsize, f); - else - fprintf(f, "%ld", entry->size); - fprintf(f, "\n"); -} - -static void -elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level) -{ - /* TODO */ -} - -elf_symtab_head * -elf_symtab_create() -{ - elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head)); - elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry)); - - STAILQ_INIT(symtab); - entry->in_table = 1; - entry->sym = NULL; - entry->sect = NULL; - entry->name = NULL; - entry->value = 0; - entry->xsize = NULL; - entry->size = 0; - entry->index = SHN_UNDEF; - entry->bind = STB_LOCAL; - entry->type = STT_NOTYPE; - entry->vis = STV_DEFAULT; - entry->symindex = 0; - STAILQ_INSERT_TAIL(symtab, entry, qlink); - return symtab; -} - -void -elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry) -{ - if (symtab == NULL) - yasm_internal_error("symtab is null"); - if (entry == NULL) - yasm_internal_error("symtab entry is null"); - if (STAILQ_EMPTY(symtab)) - yasm_internal_error(N_("symtab is missing initial dummy entry")); - - STAILQ_INSERT_TAIL(symtab, entry, qlink); - entry->in_table = 1; -} - -void -elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry) -{ - elf_symtab_entry *after = STAILQ_FIRST(symtab); - elf_symtab_entry *before = NULL; - - while (after && (after->bind == STB_LOCAL)) { - before = after; - if (before->type == STT_FILE) break; - after = STAILQ_NEXT(after, qlink); - } - STAILQ_INSERT_AFTER(symtab, before, entry, qlink); - entry->in_table = 1; -} - -void -elf_symtab_destroy(elf_symtab_head *symtab) -{ - elf_symtab_entry *s1, *s2; - - if (symtab == NULL) - yasm_internal_error("symtab is null"); - if (STAILQ_EMPTY(symtab)) - yasm_internal_error(N_("symtab is missing initial dummy entry")); - - s1 = STAILQ_FIRST(symtab); - while (s1 != NULL) { - s2 = STAILQ_NEXT(s1, qlink); - elf_symtab_entry_destroy(s1); - s1 = s2; - } - yasm_xfree(symtab); -} - -unsigned long -elf_symtab_assign_indices(elf_symtab_head *symtab) -{ - elf_symtab_entry *entry, *prev=NULL; - unsigned long last_local=0; - - if (symtab == NULL) - yasm_internal_error("symtab is null"); - if (STAILQ_EMPTY(symtab)) - yasm_internal_error(N_("symtab is missing initial dummy entry")); - - STAILQ_FOREACH(entry, symtab, qlink) { - if (prev) - entry->symindex = prev->symindex + 1; - if (entry->bind == STB_LOCAL) - last_local = entry->symindex; - prev = entry; - } - return last_local + 1; -} - -unsigned long -elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab, - yasm_errwarns *errwarns) -{ - unsigned char buf[SYMTAB_MAXSIZE], *bufp; - elf_symtab_entry *entry; - unsigned long size = 0; - - if (!symtab) - yasm_internal_error(N_("symtab is null")); - - STAILQ_FOREACH(entry, symtab, qlink) { - - yasm_intnum *size_intn=NULL, *value_intn=NULL; - bufp = buf; - - /* get size (if specified); expr overrides stored integer */ - if (entry->xsize) { - size_intn = yasm_intnum_copy( - yasm_expr_get_intnum(&entry->xsize, 1)); - if (!size_intn) { - yasm_error_set(YASM_ERROR_VALUE, - N_("size specifier not an integer expression")); - yasm_errwarn_propagate(errwarns, entry->xsize->line); - } - } - else - size_intn = yasm_intnum_create_uint(entry->size); - - /* get EQU value for constants */ - if (entry->sym) { - const yasm_expr *equ_expr_c; - equ_expr_c = yasm_symrec_get_equ(entry->sym); - - if (equ_expr_c != NULL) { - const yasm_intnum *equ_intn; - yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c); - equ_intn = yasm_expr_get_intnum(&equ_expr, 1); - - if (equ_intn == NULL) { - yasm_error_set(YASM_ERROR_VALUE, - N_("EQU value not an integer expression")); - yasm_errwarn_propagate(errwarns, equ_expr->line); - } else - value_intn = yasm_intnum_copy(equ_intn); - entry->index = SHN_ABS; - yasm_expr_destroy(equ_expr); - } - } - if (value_intn == NULL) - value_intn = yasm_intnum_create_uint(entry->value); - - /* If symbol is in a TLS section, force its type to TLS. */ - if (entry->sym) { - yasm_bytecode *precbc; - yasm_section *sect; - elf_secthead *shead; - if (yasm_symrec_get_label(entry->sym, &precbc) && - (sect = yasm_bc_get_section(precbc)) && - (shead = yasm_section_get_data(sect, &elf_section_data)) && - shead->flags & SHF_TLS) { - entry->type = STT_TLS; - } - } - - if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size) - yasm_internal_error(N_("Unsupported machine for ELF output")); - elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn); - fwrite(buf, elf_march->symtab_entry_size, 1, f); - size += elf_march->symtab_entry_size; - - yasm_intnum_destroy(size_intn); - yasm_intnum_destroy(value_intn); - } - return size; -} - -void elf_symtab_set_nonzero(elf_symtab_entry *entry, - yasm_section *sect, - elf_section_index sectidx, - elf_symbol_binding bind, - elf_symbol_type type, - yasm_expr *xsize, - elf_address *value) -{ - if (!entry) - yasm_internal_error("NULL entry"); - if (sect) entry->sect = sect; - if (sectidx) entry->index = sectidx; - if (bind) entry->bind = bind; - if (type) entry->type = type; - if (xsize) entry->xsize = xsize; - if (value) entry->value = *value; -} - -void -elf_sym_set_visibility(elf_symtab_entry *entry, - elf_symbol_vis vis) -{ - entry->vis = ELF_ST_VISIBILITY(vis); -} - -void -elf_sym_set_type(elf_symtab_entry *entry, - elf_symbol_type type) -{ - entry->type = type; -} - -void -elf_sym_set_size(elf_symtab_entry *entry, - struct yasm_expr *size) -{ - if (entry->xsize) - yasm_expr_destroy(entry->xsize); - entry->xsize = size; -} - -int -elf_sym_in_table(elf_symtab_entry *entry) -{ - return entry->in_table; -} - -elf_secthead * -elf_secthead_create(elf_strtab_entry *name, - elf_section_type type, - elf_section_flags flags, - elf_address offset, - elf_size size) -{ - elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead)); - - esd->type = type; - esd->flags = flags; - esd->offset = offset; - esd->size = yasm_intnum_create_uint(size); - esd->link = 0; - esd->info = 0; - esd->align = 0; - esd->entsize = 0; - esd->index = 0; - - esd->sym = NULL; - esd->name = name; - esd->index = 0; - esd->rel_name = NULL; - esd->rel_index = 0; - esd->rel_offset = 0; - esd->nreloc = 0; - - if (name && (strcmp(name->str, ".symtab") == 0)) { - if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align) - yasm_internal_error(N_("unsupported ELF format")); - esd->entsize = elf_march->symtab_entry_size; - esd->align = elf_march->symtab_entry_align; - } - - return esd; -} - -void -elf_secthead_destroy(elf_secthead *shead) -{ - if (shead == NULL) - yasm_internal_error(N_("shead is null")); - - yasm_intnum_destroy(shead->size); - - yasm_xfree(shead); -} - -static void -elf_section_data_destroy(void *data) -{ - elf_secthead_destroy((elf_secthead *)data); -} - -static void -elf_secthead_print(void *data, FILE *f, int indent_level) -{ - elf_secthead *sect = data; - fprintf(f, "%*sname=%s\n", indent_level, "", - sect->name ? sect->name->str : "<undef>"); - fprintf(f, "%*ssym=\n", indent_level, ""); - yasm_symrec_print(sect->sym, f, indent_level+1); - fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index); - fprintf(f, "%*sflags=", indent_level, ""); - if (sect->flags & SHF_WRITE) - fprintf(f, "WRITE "); - if (sect->flags & SHF_ALLOC) - fprintf(f, "ALLOC "); - if (sect->flags & SHF_EXECINSTR) - fprintf(f, "EXEC "); - /*if (sect->flags & SHF_MASKPROC) - fprintf(f, "PROC-SPECIFIC"); */ - fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset); - fprintf(f, "%*ssize=0x%lx\n", indent_level, "", - yasm_intnum_get_uint(sect->size)); - fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link); - fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align); - fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc); -} - -unsigned long -elf_secthead_write_to_file(FILE *f, elf_secthead *shead, - elf_section_index sindex) -{ - unsigned char buf[SHDR_MAXSIZE], *bufp = buf; - shead->index = sindex; - - if (shead == NULL) - yasm_internal_error("shead is null"); - - if (!elf_march->write_secthead || !elf_march->secthead_size) - yasm_internal_error(N_("Unsupported machine for ELF output")); - elf_march->write_secthead(bufp, shead); - if (fwrite(buf, elf_march->secthead_size, 1, f)) - return elf_march->secthead_size; - yasm_internal_error(N_("Failed to write an elf section header")); - return 0; -} - -void -elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead, - elf_reloc_entry *reloc) -{ - if (sect == NULL) - yasm_internal_error("sect is null"); - if (shead == NULL) - yasm_internal_error("shead is null"); - if (reloc == NULL) - yasm_internal_error("reloc is null"); - - shead->nreloc++; - yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy); -} - -char * -elf_secthead_name_reloc_section(const char *basesect) -{ - if (!elf_march->reloc_section_prefix) - { - yasm_internal_error(N_("Unsupported machine for ELF output")); - return NULL; - } - else - { - size_t prepend_length = strlen(elf_march->reloc_section_prefix); - char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1); - strcpy(sectname, elf_march->reloc_section_prefix); - strcat(sectname, basesect); - return sectname; - } -} - -void -elf_handle_reloc_addend(yasm_intnum *intn, - elf_reloc_entry *reloc, - unsigned long offset) -{ - if (!elf_march->handle_reloc_addend) - yasm_internal_error(N_("Unsupported machine for ELF output")); - elf_march->handle_reloc_addend(intn, reloc, offset); -} - -unsigned long -elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab_idx, - yasm_section *sect, elf_secthead *shead, - elf_section_index sindex) -{ - unsigned char buf[SHDR_MAXSIZE], *bufp = buf; - - if (shead == NULL) - yasm_internal_error("shead is null"); - - if (!yasm_section_relocs_first(sect)) - return 0; /* no relocations, no .rel.* section header */ - - shead->rel_index = sindex; - - if (!elf_march->write_secthead_rel || !elf_march->secthead_size) - yasm_internal_error(N_("Unsupported machine for ELF output")); - elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex); - if (fwrite(buf, elf_march->secthead_size, 1, f)) - return elf_march->secthead_size; - yasm_internal_error(N_("Failed to write an elf section header")); - return 0; -} - -unsigned long -elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect, - elf_secthead *shead, yasm_errwarns *errwarns) -{ - elf_reloc_entry *reloc; - unsigned char buf[RELOC_MAXSIZE], *bufp; - unsigned long size = 0; - long pos; - - if (shead == NULL) - yasm_internal_error("shead is null"); - - reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect); - if (!reloc) - return 0; - - /* first align section to multiple of 4 */ - pos = ftell(f); - if (pos == -1) { - yasm_error_set(YASM_ERROR_IO, - N_("couldn't read position on output stream")); - yasm_errwarn_propagate(errwarns, 0); - } - pos = (pos + 3) & ~3; - if (fseek(f, pos, SEEK_SET) < 0) { - yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream")); - yasm_errwarn_propagate(errwarns, 0); - } - shead->rel_offset = (unsigned long)pos; - - - while (reloc) { - unsigned int r_type=0, r_sym; - elf_symtab_entry *esym; - - esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); - if (esym) - r_sym = esym->symindex; - else - r_sym = STN_UNDEF; - - if (!elf_march->map_reloc_info_to_type) - yasm_internal_error(N_("Unsupported arch/machine for elf output")); - r_type = elf_march->map_reloc_info_to_type(reloc); - - bufp = buf; - if (!elf_march->write_reloc || !elf_march->reloc_entry_size) - yasm_internal_error(N_("Unsupported arch/machine for elf output")); - elf_march->write_reloc(bufp, reloc, r_type, r_sym); - fwrite(buf, elf_march->reloc_entry_size, 1, f); - size += elf_march->reloc_entry_size; - - reloc = (elf_reloc_entry *) - yasm_section_reloc_next((yasm_reloc *)reloc); - } - return size; -} - -elf_section_type -elf_secthead_get_type(elf_secthead *shead) -{ - return shead->type; -} - -void -elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type, - elf_section_flags flags) -{ - shead->type = type; - shead->flags = flags; -} - -int -elf_secthead_is_empty(elf_secthead *shead) -{ - return yasm_intnum_is_zero(shead->size); -} - -yasm_symrec * -elf_secthead_get_sym(elf_secthead *shead) -{ - return shead->sym; -} - -elf_section_index -elf_secthead_get_index(elf_secthead *shead) -{ - return shead->index; -} - -unsigned long -elf_secthead_get_align(const elf_secthead *shead) -{ - return shead->align; -} - -unsigned long -elf_secthead_set_align(elf_secthead *shead, unsigned long align) -{ - return shead->align = align; -} - -elf_section_info -elf_secthead_set_info(elf_secthead *shead, elf_section_info info) -{ - return shead->info = info; -} - -elf_section_index -elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx) -{ - return shead->index = sectidx; -} - -elf_section_index -elf_secthead_set_link(elf_secthead *shead, elf_section_index link) -{ - return shead->link = link; -} - -elf_section_index -elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx) -{ - return shead->rel_index = sectidx; -} - -elf_strtab_entry * -elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry) -{ - return shead->rel_name = entry; -} - -elf_size -elf_secthead_set_entsize(elf_secthead *shead, elf_size size) -{ - return shead->entsize = size; -} - -yasm_symrec * -elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym) -{ - return shead->sym = sym; -} - -void -elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size) -{ - if (size) { - yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size); - } -} - -long -elf_secthead_set_file_offset(elf_secthead *shead, long pos) -{ - unsigned long align = shead->align; - - if (align == 0 || align == 1) { - shead->offset = (unsigned long)pos; - return pos; - } - else if (align & (align - 1)) - yasm_internal_error( - N_("alignment %d for section `%s' is not a power of 2")); - /*, align, sect->name->str);*/ - - shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1)); - return (long)shead->offset; -} - -unsigned long -elf_proghead_get_size(void) -{ - if (!elf_march->proghead_size) - yasm_internal_error(N_("Unsupported ELF format for output")); - return elf_march->proghead_size; -} - -unsigned long -elf_proghead_write_to_file(FILE *f, - elf_offset secthead_addr, - unsigned long secthead_count, - elf_section_index shstrtab_index) -{ - unsigned char buf[EHDR_MAXSIZE], *bufp = buf; - - YASM_WRITE_8(bufp, ELFMAG0); /* ELF magic number */ - YASM_WRITE_8(bufp, ELFMAG1); - YASM_WRITE_8(bufp, ELFMAG2); - YASM_WRITE_8(bufp, ELFMAG3); - - if (!elf_march->write_proghead || !elf_march->proghead_size) - yasm_internal_error(N_("Unsupported ELF format for output")); - elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index); - - if (((unsigned)(bufp - buf)) != elf_march->proghead_size) - yasm_internal_error(N_("ELF program header is not proper length")); - - if (fwrite(buf, elf_march->proghead_size, 1, f)) - return elf_march->proghead_size; - - yasm_internal_error(N_("Failed to write ELF program header")); - return 0; -} +/* + * ELF object format helpers + * + * 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> + +#include <libyasm.h> +#define YASM_OBJFMT_ELF_INTERNAL +#include "elf.h" +#include "elf-machine.h" + +static void elf_section_data_destroy(void *data); +static void elf_secthead_print(void *data, FILE *f, int indent_level); + +const yasm_assoc_data_callback elf_section_data = { + elf_section_data_destroy, + elf_secthead_print +}; + +static void elf_symrec_data_destroy(/*@only@*/ void *d); +static void elf_symtab_entry_print(void *data, FILE *f, int indent_level); +static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level); + +const yasm_assoc_data_callback elf_symrec_data = { + elf_symrec_data_destroy, + elf_symtab_entry_print +}; + +const yasm_assoc_data_callback elf_ssym_symrec_data = { + elf_symrec_data_destroy, + elf_ssym_symtab_entry_print +}; + +extern elf_machine_handler + elf_machine_handler_x86_x86, + elf_machine_handler_x86_amd64, + elf_machine_handler_x86_x32; + +static const elf_machine_handler *elf_machine_handlers[] = +{ + &elf_machine_handler_x86_x86, + &elf_machine_handler_x86_amd64, + &elf_machine_handler_x86_x32, + NULL +}; +static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0}; +static elf_machine_handler const *elf_march = &elf_null_machine; +static yasm_symrec **elf_ssyms; + +const elf_machine_handler * +elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref) +{ + const char *machine = yasm_arch_get_machine(arch); + int i; + + for (i=0, elf_march = elf_machine_handlers[0]; + elf_march != NULL; + elf_march = elf_machine_handlers[++i]) + { + if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0) { + if (yasm__strcasecmp(machine, elf_march->machine)==0) { + if (bits_pref == 0 || bits_pref == elf_march->bits) + break; + } else if (bits_pref == elf_march->bits + && yasm__strcasecmp(machine, "amd64") == 0 + && yasm__strcasecmp(elf_march->machine, "x32") == 0) + break; + } + } + + if (elf_march && elf_march->num_ssyms > 0) + { + /* Allocate "special" syms */ + elf_ssyms = + yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *)); + for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) + { + /* FIXME: misuse of NULL bytecode */ + elf_ssyms[i] = yasm_symtab_define_label(symtab, + elf_march->ssyms[i].name, + NULL, 0, 0); + yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data, + (void*)&elf_march->ssyms[i]); + } + } + + return elf_march; +} + +yasm_symrec * +elf_get_special_sym(const char *name, const char *parser) +{ + int i; + for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) { + if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0) + return elf_ssyms[i]; + } + return NULL; +} + +/* reloc functions */ +int elf_ssym_has_flag(yasm_symrec *wrt, int flag); + +int +elf_is_wrt_sym_relative(yasm_symrec *wrt) +{ + return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE); +} + +int +elf_is_wrt_pos_adjusted(yasm_symrec *wrt) +{ + return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST); +} + +int +elf_ssym_has_flag(yasm_symrec *wrt, int flag) +{ + int i; + for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) { + if (elf_ssyms[i] == wrt) + return (elf_march->ssyms[i].sym_rel & flag) != 0; + } + return 0; +} + +/* takes ownership of addr */ +elf_reloc_entry * +elf_reloc_entry_create(yasm_symrec *sym, + yasm_symrec *wrt, + yasm_intnum *addr, + int rel, + size_t valsize, + int is_GOT_sym) +{ + elf_reloc_entry *entry; + + if (!elf_march->accepts_reloc) + yasm_internal_error(N_("Unsupported machine for ELF output")); + + if (!elf_march->accepts_reloc(valsize, wrt)) + { + if (addr) + yasm_intnum_destroy(addr); + return NULL; + } + + if (sym == NULL) + yasm_internal_error("sym is null"); + + entry = yasm_xmalloc(sizeof(elf_reloc_entry)); + entry->reloc.sym = sym; + entry->reloc.addr = addr; + entry->rtype_rel = rel; + entry->valsize = valsize; + entry->addend = NULL; + entry->wrt = wrt; + entry->is_GOT_sym = is_GOT_sym; + + return entry; +} + +void +elf_reloc_entry_destroy(void *entry) +{ + if (((elf_reloc_entry*)entry)->addend) + yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend); + yasm_xfree(entry); +} + +/* strtab functions */ +elf_strtab_entry * +elf_strtab_entry_create(const char *str) +{ + elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry)); + entry->str = yasm__xstrdup(str); + entry->index = 0; + return entry; +} + +void +elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str) +{ + elf_strtab_entry *last; + if (entry->str) + yasm_xfree(entry->str); + entry->str = yasm__xstrdup(str); + + /* Update all following indices since string length probably changes */ + last = entry; + entry = STAILQ_NEXT(last, qlink); + while (entry) { + entry->index = last->index + (unsigned long)strlen(last->str) + 1; + last = entry; + entry = STAILQ_NEXT(last, qlink); + } +} + +elf_strtab_head * +elf_strtab_create() +{ + elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head)); + elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry)); + + STAILQ_INIT(strtab); + entry->index = 0; + entry->str = yasm__xstrdup(""); + + STAILQ_INSERT_TAIL(strtab, entry, qlink); + return strtab; +} + +elf_strtab_entry * +elf_strtab_append_str(elf_strtab_head *strtab, const char *str) +{ + elf_strtab_entry *last, *entry; + + if (strtab == NULL) + yasm_internal_error("strtab is null"); + if (STAILQ_EMPTY(strtab)) + yasm_internal_error("strtab is missing initial dummy entry"); + + last = STAILQ_LAST(strtab, elf_strtab_entry, qlink); + + entry = elf_strtab_entry_create(str); + entry->index = last->index + (unsigned long)strlen(last->str) + 1; + + STAILQ_INSERT_TAIL(strtab, entry, qlink); + return entry; +} + +void +elf_strtab_destroy(elf_strtab_head *strtab) +{ + elf_strtab_entry *s1, *s2; + + if (strtab == NULL) + yasm_internal_error("strtab is null"); + if (STAILQ_EMPTY(strtab)) + yasm_internal_error("strtab is missing initial dummy entry"); + + s1 = STAILQ_FIRST(strtab); + while (s1 != NULL) { + s2 = STAILQ_NEXT(s1, qlink); + yasm_xfree(s1->str); + yasm_xfree(s1); + s1 = s2; + } + yasm_xfree(strtab); +} + +unsigned long +elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab) +{ + unsigned long size = 0; + elf_strtab_entry *entry; + + if (strtab == NULL) + yasm_internal_error("strtab is null"); + + /* consider optimizing tables here */ + STAILQ_FOREACH(entry, strtab, qlink) { + size_t len = 1 + strlen(entry->str); + fwrite(entry->str, len, 1, f); + size += (unsigned long)len; + } + return size; +} + + + +/* symtab functions */ +elf_symtab_entry * +elf_symtab_entry_create(elf_strtab_entry *name, + yasm_symrec *sym) +{ + elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry)); + entry->in_table = 0; + entry->sym = sym; + entry->sect = NULL; + entry->name = name; + entry->value = 0; + + entry->xsize = NULL; + entry->size = 0; + entry->index = 0; + entry->bind = 0; + entry->type = STT_NOTYPE; + entry->vis = STV_DEFAULT; + + return entry; +} + +static void +elf_symtab_entry_destroy(elf_symtab_entry *entry) +{ + if (entry == NULL) + yasm_internal_error("symtab entry is null"); + + yasm_xfree(entry); +} + +static void +elf_symrec_data_destroy(void *data) +{ + /* do nothing, as this stuff is in the symtab anyway... this speaks of bad + * design/use or this stuff, i fear */ + + /* watch for double-free here ... */ + /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/ +} + +static void +elf_symtab_entry_print(void *data, FILE *f, int indent_level) +{ + elf_symtab_entry *entry = data; + if (entry == NULL) + yasm_internal_error("symtab entry is null"); + + fprintf(f, "%*sbind=", indent_level, ""); + switch (entry->bind) { + case STB_LOCAL: fprintf(f, "local\n"); break; + case STB_GLOBAL: fprintf(f, "global\n"); break; + case STB_WEAK: fprintf(f, "weak\n"); break; + default: fprintf(f, "undef\n"); break; + } + fprintf(f, "%*stype=", indent_level, ""); + switch (entry->type) { + case STT_NOTYPE: fprintf(f, "notype\n"); break; + case STT_OBJECT: fprintf(f, "object\n"); break; + case STT_FUNC: fprintf(f, "func\n"); break; + case STT_SECTION: fprintf(f, "section\n");break; + case STT_FILE: fprintf(f, "file\n"); break; + default: fprintf(f, "undef\n"); break; + } + fprintf(f, "%*ssize=", indent_level, ""); + if (entry->xsize) + yasm_expr_print(entry->xsize, f); + else + fprintf(f, "%ld", entry->size); + fprintf(f, "\n"); +} + +static void +elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level) +{ + /* TODO */ +} + +elf_symtab_head * +elf_symtab_create() +{ + elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head)); + elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry)); + + STAILQ_INIT(symtab); + entry->in_table = 1; + entry->sym = NULL; + entry->sect = NULL; + entry->name = NULL; + entry->value = 0; + entry->xsize = NULL; + entry->size = 0; + entry->index = SHN_UNDEF; + entry->bind = STB_LOCAL; + entry->type = STT_NOTYPE; + entry->vis = STV_DEFAULT; + entry->symindex = 0; + STAILQ_INSERT_TAIL(symtab, entry, qlink); + return symtab; +} + +void +elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry) +{ + if (symtab == NULL) + yasm_internal_error("symtab is null"); + if (entry == NULL) + yasm_internal_error("symtab entry is null"); + if (STAILQ_EMPTY(symtab)) + yasm_internal_error(N_("symtab is missing initial dummy entry")); + + STAILQ_INSERT_TAIL(symtab, entry, qlink); + entry->in_table = 1; +} + +void +elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry) +{ + elf_symtab_entry *after = STAILQ_FIRST(symtab); + elf_symtab_entry *before = NULL; + + while (after && (after->bind == STB_LOCAL)) { + before = after; + if (before->type == STT_FILE) break; + after = STAILQ_NEXT(after, qlink); + } + STAILQ_INSERT_AFTER(symtab, before, entry, qlink); + entry->in_table = 1; +} + +void +elf_symtab_destroy(elf_symtab_head *symtab) +{ + elf_symtab_entry *s1, *s2; + + if (symtab == NULL) + yasm_internal_error("symtab is null"); + if (STAILQ_EMPTY(symtab)) + yasm_internal_error(N_("symtab is missing initial dummy entry")); + + s1 = STAILQ_FIRST(symtab); + while (s1 != NULL) { + s2 = STAILQ_NEXT(s1, qlink); + elf_symtab_entry_destroy(s1); + s1 = s2; + } + yasm_xfree(symtab); +} + +unsigned long +elf_symtab_assign_indices(elf_symtab_head *symtab) +{ + elf_symtab_entry *entry, *prev=NULL; + unsigned long last_local=0; + + if (symtab == NULL) + yasm_internal_error("symtab is null"); + if (STAILQ_EMPTY(symtab)) + yasm_internal_error(N_("symtab is missing initial dummy entry")); + + STAILQ_FOREACH(entry, symtab, qlink) { + if (prev) + entry->symindex = prev->symindex + 1; + if (entry->bind == STB_LOCAL) + last_local = entry->symindex; + prev = entry; + } + return last_local + 1; +} + +unsigned long +elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab, + yasm_errwarns *errwarns) +{ + unsigned char buf[SYMTAB_MAXSIZE], *bufp; + elf_symtab_entry *entry; + unsigned long size = 0; + + if (!symtab) + yasm_internal_error(N_("symtab is null")); + + STAILQ_FOREACH(entry, symtab, qlink) { + + yasm_intnum *size_intn=NULL, *value_intn=NULL; + bufp = buf; + + /* get size (if specified); expr overrides stored integer */ + if (entry->xsize) { + size_intn = yasm_intnum_copy( + yasm_expr_get_intnum(&entry->xsize, 1)); + if (!size_intn) { + yasm_error_set(YASM_ERROR_VALUE, + N_("size specifier not an integer expression")); + yasm_errwarn_propagate(errwarns, entry->xsize->line); + } + } + else + size_intn = yasm_intnum_create_uint(entry->size); + + /* get EQU value for constants */ + if (entry->sym) { + const yasm_expr *equ_expr_c; + equ_expr_c = yasm_symrec_get_equ(entry->sym); + + if (equ_expr_c != NULL) { + const yasm_intnum *equ_intn; + yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c); + equ_intn = yasm_expr_get_intnum(&equ_expr, 1); + + if (equ_intn == NULL) { + yasm_error_set(YASM_ERROR_VALUE, + N_("EQU value not an integer expression")); + yasm_errwarn_propagate(errwarns, equ_expr->line); + } else + value_intn = yasm_intnum_copy(equ_intn); + entry->index = SHN_ABS; + yasm_expr_destroy(equ_expr); + } + } + if (value_intn == NULL) + value_intn = yasm_intnum_create_uint(entry->value); + + /* If symbol is in a TLS section, force its type to TLS. */ + if (entry->sym) { + yasm_bytecode *precbc; + yasm_section *sect; + elf_secthead *shead; + if (yasm_symrec_get_label(entry->sym, &precbc) && + (sect = yasm_bc_get_section(precbc)) && + (shead = yasm_section_get_data(sect, &elf_section_data)) && + shead->flags & SHF_TLS) { + entry->type = STT_TLS; + } + } + + if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn); + fwrite(buf, elf_march->symtab_entry_size, 1, f); + size += elf_march->symtab_entry_size; + + yasm_intnum_destroy(size_intn); + yasm_intnum_destroy(value_intn); + } + return size; +} + +void elf_symtab_set_nonzero(elf_symtab_entry *entry, + yasm_section *sect, + elf_section_index sectidx, + elf_symbol_binding bind, + elf_symbol_type type, + yasm_expr *xsize, + elf_address *value) +{ + if (!entry) + yasm_internal_error("NULL entry"); + if (sect) entry->sect = sect; + if (sectidx) entry->index = sectidx; + if (bind) entry->bind = bind; + if (type) entry->type = type; + if (xsize) entry->xsize = xsize; + if (value) entry->value = *value; +} + +void +elf_sym_set_visibility(elf_symtab_entry *entry, + elf_symbol_vis vis) +{ + entry->vis = ELF_ST_VISIBILITY(vis); +} + +void +elf_sym_set_type(elf_symtab_entry *entry, + elf_symbol_type type) +{ + entry->type = type; +} + +void +elf_sym_set_size(elf_symtab_entry *entry, + struct yasm_expr *size) +{ + if (entry->xsize) + yasm_expr_destroy(entry->xsize); + entry->xsize = size; +} + +int +elf_sym_in_table(elf_symtab_entry *entry) +{ + return entry->in_table; +} + +elf_secthead * +elf_secthead_create(elf_strtab_entry *name, + elf_section_type type, + elf_section_flags flags, + elf_address offset, + elf_size size) +{ + elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead)); + + esd->type = type; + esd->flags = flags; + esd->offset = offset; + esd->size = yasm_intnum_create_uint(size); + esd->link = 0; + esd->info = 0; + esd->align = 0; + esd->entsize = 0; + esd->index = 0; + + esd->sym = NULL; + esd->name = name; + esd->index = 0; + esd->rel_name = NULL; + esd->rel_index = 0; + esd->rel_offset = 0; + esd->nreloc = 0; + + if (name && (strcmp(name->str, ".symtab") == 0)) { + if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align) + yasm_internal_error(N_("unsupported ELF format")); + esd->entsize = elf_march->symtab_entry_size; + esd->align = elf_march->symtab_entry_align; + } + + return esd; +} + +void +elf_secthead_destroy(elf_secthead *shead) +{ + if (shead == NULL) + yasm_internal_error(N_("shead is null")); + + yasm_intnum_destroy(shead->size); + + yasm_xfree(shead); +} + +static void +elf_section_data_destroy(void *data) +{ + elf_secthead_destroy((elf_secthead *)data); +} + +static void +elf_secthead_print(void *data, FILE *f, int indent_level) +{ + elf_secthead *sect = data; + fprintf(f, "%*sname=%s\n", indent_level, "", + sect->name ? sect->name->str : "<undef>"); + fprintf(f, "%*ssym=\n", indent_level, ""); + yasm_symrec_print(sect->sym, f, indent_level+1); + fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index); + fprintf(f, "%*sflags=", indent_level, ""); + if (sect->flags & SHF_WRITE) + fprintf(f, "WRITE "); + if (sect->flags & SHF_ALLOC) + fprintf(f, "ALLOC "); + if (sect->flags & SHF_EXECINSTR) + fprintf(f, "EXEC "); + /*if (sect->flags & SHF_MASKPROC) + fprintf(f, "PROC-SPECIFIC"); */ + fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset); + fprintf(f, "%*ssize=0x%lx\n", indent_level, "", + yasm_intnum_get_uint(sect->size)); + fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link); + fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align); + fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc); +} + +unsigned long +elf_secthead_write_to_file(FILE *f, elf_secthead *shead, + elf_section_index sindex) +{ + unsigned char buf[SHDR_MAXSIZE], *bufp = buf; + shead->index = sindex; + + if (shead == NULL) + yasm_internal_error("shead is null"); + + if (!elf_march->write_secthead || !elf_march->secthead_size) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->write_secthead(bufp, shead); + if (fwrite(buf, elf_march->secthead_size, 1, f)) + return elf_march->secthead_size; + yasm_internal_error(N_("Failed to write an elf section header")); + return 0; +} + +void +elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead, + elf_reloc_entry *reloc) +{ + if (sect == NULL) + yasm_internal_error("sect is null"); + if (shead == NULL) + yasm_internal_error("shead is null"); + if (reloc == NULL) + yasm_internal_error("reloc is null"); + + shead->nreloc++; + yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy); +} + +char * +elf_secthead_name_reloc_section(const char *basesect) +{ + if (!elf_march->reloc_section_prefix) + { + yasm_internal_error(N_("Unsupported machine for ELF output")); + return NULL; + } + else + { + size_t prepend_length = strlen(elf_march->reloc_section_prefix); + char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1); + strcpy(sectname, elf_march->reloc_section_prefix); + strcat(sectname, basesect); + return sectname; + } +} + +void +elf_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset) +{ + if (!elf_march->handle_reloc_addend) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->handle_reloc_addend(intn, reloc, offset); +} + +unsigned long +elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab_idx, + yasm_section *sect, elf_secthead *shead, + elf_section_index sindex) +{ + unsigned char buf[SHDR_MAXSIZE], *bufp = buf; + + if (shead == NULL) + yasm_internal_error("shead is null"); + + if (!yasm_section_relocs_first(sect)) + return 0; /* no relocations, no .rel.* section header */ + + shead->rel_index = sindex; + + if (!elf_march->write_secthead_rel || !elf_march->secthead_size) + yasm_internal_error(N_("Unsupported machine for ELF output")); + elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex); + if (fwrite(buf, elf_march->secthead_size, 1, f)) + return elf_march->secthead_size; + yasm_internal_error(N_("Failed to write an elf section header")); + return 0; +} + +unsigned long +elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect, + elf_secthead *shead, yasm_errwarns *errwarns) +{ + elf_reloc_entry *reloc; + unsigned char buf[RELOC_MAXSIZE], *bufp; + unsigned long size = 0; + long pos; + + if (shead == NULL) + yasm_internal_error("shead is null"); + + reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect); + if (!reloc) + return 0; + + /* first align section to multiple of 4 */ + pos = ftell(f); + if (pos == -1) { + yasm_error_set(YASM_ERROR_IO, + N_("couldn't read position on output stream")); + yasm_errwarn_propagate(errwarns, 0); + } + pos = (pos + 3) & ~3; + if (fseek(f, pos, SEEK_SET) < 0) { + yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream")); + yasm_errwarn_propagate(errwarns, 0); + } + shead->rel_offset = (unsigned long)pos; + + + while (reloc) { + unsigned int r_type=0, r_sym; + elf_symtab_entry *esym; + + esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data); + if (esym) + r_sym = esym->symindex; + else + r_sym = STN_UNDEF; + + if (!elf_march->map_reloc_info_to_type) + yasm_internal_error(N_("Unsupported arch/machine for elf output")); + r_type = elf_march->map_reloc_info_to_type(reloc); + + bufp = buf; + if (!elf_march->write_reloc || !elf_march->reloc_entry_size) + yasm_internal_error(N_("Unsupported arch/machine for elf output")); + elf_march->write_reloc(bufp, reloc, r_type, r_sym); + fwrite(buf, elf_march->reloc_entry_size, 1, f); + size += elf_march->reloc_entry_size; + + reloc = (elf_reloc_entry *) + yasm_section_reloc_next((yasm_reloc *)reloc); + } + return size; +} + +elf_section_type +elf_secthead_get_type(elf_secthead *shead) +{ + return shead->type; +} + +void +elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type, + elf_section_flags flags) +{ + shead->type = type; + shead->flags = flags; +} + +int +elf_secthead_is_empty(elf_secthead *shead) +{ + return yasm_intnum_is_zero(shead->size); +} + +yasm_symrec * +elf_secthead_get_sym(elf_secthead *shead) +{ + return shead->sym; +} + +elf_section_index +elf_secthead_get_index(elf_secthead *shead) +{ + return shead->index; +} + +unsigned long +elf_secthead_get_align(const elf_secthead *shead) +{ + return shead->align; +} + +unsigned long +elf_secthead_set_align(elf_secthead *shead, unsigned long align) +{ + return shead->align = align; +} + +elf_section_info +elf_secthead_set_info(elf_secthead *shead, elf_section_info info) +{ + return shead->info = info; +} + +elf_section_index +elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx) +{ + return shead->index = sectidx; +} + +elf_section_index +elf_secthead_set_link(elf_secthead *shead, elf_section_index link) +{ + return shead->link = link; +} + +elf_section_index +elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx) +{ + return shead->rel_index = sectidx; +} + +elf_strtab_entry * +elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry) +{ + return shead->rel_name = entry; +} + +elf_size +elf_secthead_set_entsize(elf_secthead *shead, elf_size size) +{ + return shead->entsize = size; +} + +yasm_symrec * +elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym) +{ + return shead->sym = sym; +} + +void +elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size) +{ + if (size) { + yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size); + } +} + +long +elf_secthead_set_file_offset(elf_secthead *shead, long pos) +{ + unsigned long align = shead->align; + + if (align == 0 || align == 1) { + shead->offset = (unsigned long)pos; + return pos; + } + else if (align & (align - 1)) + yasm_internal_error( + N_("alignment %d for section `%s' is not a power of 2")); + /*, align, sect->name->str);*/ + + shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1)); + return (long)shead->offset; +} + +unsigned long +elf_proghead_get_size(void) +{ + if (!elf_march->proghead_size) + yasm_internal_error(N_("Unsupported ELF format for output")); + return elf_march->proghead_size; +} + +unsigned long +elf_proghead_write_to_file(FILE *f, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index) +{ + unsigned char buf[EHDR_MAXSIZE], *bufp = buf; + + YASM_WRITE_8(bufp, ELFMAG0); /* ELF magic number */ + YASM_WRITE_8(bufp, ELFMAG1); + YASM_WRITE_8(bufp, ELFMAG2); + YASM_WRITE_8(bufp, ELFMAG3); + + if (!elf_march->write_proghead || !elf_march->proghead_size) + yasm_internal_error(N_("Unsupported ELF format for output")); + elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index); + + if (((unsigned)(bufp - buf)) != elf_march->proghead_size) + yasm_internal_error(N_("ELF program header is not proper length")); + + if (fwrite(buf, elf_march->proghead_size, 1, f)) + return elf_march->proghead_size; + + yasm_internal_error(N_("Failed to write ELF program header")); + return 0; +} diff --git a/contrib/tools/yasm/modules/objfmts/elf/elf.h b/contrib/tools/yasm/modules/objfmts/elf/elf.h index fce629ae45..73498477e8 100644 --- a/contrib/tools/yasm/modules/objfmts/elf/elf.h +++ b/contrib/tools/yasm/modules/objfmts/elf/elf.h @@ -1,532 +1,532 @@ -/* - * ELF object format helpers - * - * 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. - */ - -#ifndef ELF_H_INCLUDED -#define ELF_H_INCLUDED - -typedef struct elf_reloc_entry elf_reloc_entry; -typedef struct elf_reloc_head elf_reloc_head; -typedef struct elf_secthead elf_secthead; -typedef struct elf_strtab_entry elf_strtab_entry; -typedef struct elf_strtab_head elf_strtab_head; -typedef struct elf_symtab_entry elf_symtab_entry; -typedef struct elf_symtab_head elf_symtab_head; - -typedef struct elf_machine_handler elf_machine_handler; - -typedef unsigned long elf_address; -typedef unsigned long elf_offset; -typedef unsigned long elf_size; -typedef unsigned long elf_section_info; - -typedef enum { - ET_NONE = 0, - ET_REL = 1, /* Relocatable */ - ET_EXEC = 2, /* Executable */ - ET_DYN = 3, /* Shared object */ - ET_CORE = 4, /* Core */ - ET_LOOS = 0xfe00, /* Environment specific */ - ET_HIOS = 0xfeff, - ET_LOPROC = 0xff00, /* Processor specific */ - ET_HIPROC = 0xffff -} elf_file_type; - -typedef enum { - EM_NONE = 0, - EM_M32 = 1, /* AT&T WE 32100 */ - EM_SPARC = 2, /* SPARC */ - EM_386 = 3, /* Intel 80386 */ - EM_68K = 4, /* Motorola 68000 */ - EM_88K = 5, /* Motorola 88000 */ - EM_860 = 7, /* Intel 80860 */ - EM_MIPS = 8, /* MIPS RS3000 */ - - EM_S370 = 9, /* IBM System/370 */ - EM_MIPS_RS4_BE = 10, /* MIPS R4000 Big-Endian (dep)*/ - EM_PARISC = 15, /* HPPA */ - EM_SPARC32PLUS = 18, /* SPARC v8plus */ - EM_PPC = 20, /* PowerPC 32-bit */ - EM_PPC64 = 21, /* PowerPC 64-bit */ - EM_ARM = 40, /* ARM */ - EM_SPARCV9 = 43, /* SPARC v9 64-bit */ - EM_IA_64 = 50, /* Intel IA-64 */ - EM_X86_64 = 62, /* AMD x86-64 */ - EM_ALPHA = 0x9026 /* Alpha (no ABI) */ -} elf_machine; - -typedef enum { - ELFMAG0 = 0x7f, - ELFMAG1 = 0x45, - ELFMAG2 = 0x4c, - ELFMAG3 = 0x46 -} elf_magic; - -typedef enum { - EV_NONE = 0, /* invalid */ - EV_CURRENT = 1 /* current */ -} elf_version; - -typedef enum { - EI_MAG0 = 0, /* File id */ - EI_MAG1 = 1, - EI_MAG2 = 2, - EI_MAG3 = 3, - EI_CLASS = 4, /* File class */ - EI_DATA = 5, /* Data encoding */ - EI_VERSION = 6, /* File version */ - EI_OSABI = 7, /* OS and ABI */ - EI_ABIVERSION = 8, /* version of ABI */ - - EI_PAD = 9, /* Pad to end; start here */ - EI_NIDENT = 16 /* Sizeof e_ident[] */ -} elf_identification_index; - -typedef enum { - ELFOSABI_SYSV = 0, /* System V ABI */ - ELFOSABI_HPUX = 1, /* HP-UX os */ - ELFOSABI_STANDALONE = 255 /* Standalone / embedded app */ -} elf_osabi_index; - -typedef enum { - ELFCLASSNONE = 0, /* invalid */ - ELFCLASS32 = 1, /* 32-bit */ - ELFCLASS64 = 2 /* 64-bit */ -} elf_class; - -typedef enum { - ELFDATANONE = 0, - ELFDATA2LSB = 1, - ELFDATA2MSB = 2 -} elf_data_encoding; - -/* elf section types - index of semantics */ -typedef enum { - SHT_NULL = 0, /* inactive section - no associated data */ - SHT_PROGBITS = 1, /* defined by program for its own meaning */ - SHT_SYMTAB = 2, /* symbol table (primarily) for linking */ - SHT_STRTAB = 3, /* string table - symbols need names */ - SHT_RELA = 4, /* relocation entries w/ explicit addends */ - SHT_HASH = 5, /* symbol hash table - for dynamic linking */ - SHT_DYNAMIC = 6, /* information for dynamic linking */ - SHT_NOTE = 7, /* extra data marking the file somehow */ - SHT_NOBITS = 8, /* no stored data, but occupies runtime space */ - SHT_REL = 9, /* relocations entries w/o explicit addends */ - SHT_SHLIB = 10, /* reserved; unspecified semantics */ - SHT_DYNSYM = 11, /* like symtab, but more for dynamic linking */ - - SHT_LOOS = 0x60000000, /* reserved for environment specific use */ - SHT_HIOS = 0x6fffffff, - SHT_LOPROC = 0x70000000, /* reserved for processor specific semantics */ - SHT_HIPROC = 0x7fffffff/*, - SHT_LOUSER = 0x80000000,*/ /* reserved for applications; safe */ - /*SHT_HIUSER = 0xffffffff*/ -} elf_section_type; - -/* elf section flags - bitfield of attributes */ -typedef enum { - SHF_WRITE = 0x1, /* data should be writable at runtime */ - SHF_ALLOC = 0x2, /* occupies memory at runtime */ - SHF_EXECINSTR = 0x4, /* contains machine instructions */ - SHF_MERGE = 0x10, /* data can be merged */ - SHF_STRINGS = 0x20, /* contains 0-terminated strings */ - SHF_GROUP = 0x200, /* member of a section group */ - SHF_TLS = 0x400, /* thread local storage */ - SHF_MASKOS = 0x0f000000/*,*//* environment specific use */ - /*SHF_MASKPROC = 0xf0000000*/ /* bits reserved for processor specific needs */ -} elf_section_flags; - -/* elf section index - just the special ones */ -typedef enum { - SHN_UNDEF = 0, /* undefined symbol; requires other global */ - SHN_LORESERVE = 0xff00, /* reserved for various semantics */ - SHN_LOPROC = 0xff00, /* reserved for processor specific semantics */ - SHN_HIPROC = 0xff1f, - SHN_LOOS = 0xff20, /* reserved for environment specific use */ - SHN_HIOS = 0xff3f, - SHN_ABS = 0xfff1, /* associated symbols don't change on reloc */ - SHN_COMMON = 0xfff2, /* associated symbols refer to unallocated */ - SHN_HIRESERVE = 0xffff -} elf_section_index; - -/* elf symbol binding - index of visibility/behavior */ -typedef enum { - STB_LOCAL = 0, /* invisible outside defining file */ - STB_GLOBAL = 1, /* visible to all combined object files */ - STB_WEAK = 2, /* global but lower precedence */ - - STB_LOOS = 10, /* Environment specific use */ - STB_HIOS = 12, - STB_LOPROC = 13, /* reserved for processor specific semantics */ - STB_HIPROC = 15 -} elf_symbol_binding; - -/* elf symbol type - index of classifications */ -typedef enum { - STT_NOTYPE = 0, /* type not specified */ - STT_OBJECT = 1, /* data object such as a variable, array, etc */ - STT_FUNC = 2, /* a function or executable code */ - STT_SECTION = 3, /* a section: often for relocation, STB_LOCAL */ - STT_FILE = 4, /* often source filename: STB_LOCAL, SHN_ABS */ - STT_COMMON = 5, /* Uninitialized common block. */ - STT_TLS = 6, /* TLS object. */ - STT_NUM = 7, - - STT_LOOS = 10, /* Environment specific use */ - STT_HIOS = 12, - STT_LOPROC = 13, /* reserved for processor specific semantics */ - STT_HIPROC = 15 -} elf_symbol_type; - -typedef enum { - STN_UNDEF = 0 -} elf_symbol_index; - -/* elf symbol visibility - lower two bits of OTHER field */ -typedef enum { - STV_DEFAULT = 0, /* Default symbol visibility rules */ - STV_INTERNAL = 1, /* Processor specific hidden class */ - STV_HIDDEN = 2, /* Sym unavailable in other modules */ - STV_PROTECTED = 3 /* Not preemptable, not exported */ -} elf_symbol_vis; - - -/* internal only object definitions */ -#ifdef YASM_OBJFMT_ELF_INTERNAL - -#define ELF_VISIBILITY_MASK 0x03 -#define ELF_ST_VISIBILITY(v) ((v) & ELF_VISIBILITY_MASK) - -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) -#define ELF32_ST_OTHER(vis) ELF_ST_VISIBILITY(vis) - -#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#define ELF64_R_INFO(s,t) (((s)<<32) + ((t) & 0xffffffffL)) -#define ELF64_ST_OTHER(vis) ELF_ST_VISIBILITY(vis) - -#define EHDR32_SIZE 52 -#define EHDR64_SIZE 64 -#define EHDR_MAXSIZE 64 - -#define SHDR32_SIZE 40 -#define SHDR64_SIZE 64 -#define SHDR_MAXSIZE 64 - -#define SYMTAB32_SIZE 16 -#define SYMTAB64_SIZE 24 -#define SYMTAB_MAXSIZE 24 - -#define SYMTAB32_ALIGN 4 -#define SYMTAB64_ALIGN 8 - -#define RELOC32_SIZE 8 -#define RELOC32A_SIZE 12 -#define RELOC64_SIZE 16 -#define RELOC64A_SIZE 24 -#define RELOC_MAXSIZE 24 - -#define RELOC32_ALIGN 4 -#define RELOC64_ALIGN 8 - - -/* elf relocation type - index of semantics - * - * A = Addend (r_addend for RELA, value at location for REL) - * B = Base address - * G = Offset into global offset table (GOT) - * GOT = Address of the global offset table (GOT) - * L = Location of procedure linkage table (PLT) - * P = Location of location being relocated (r_offset) - * S = Value of symbol - */ -typedef enum { - R_386_NONE = 0, /* none */ - R_386_32 = 1, /* word32, S + A */ - R_386_PC32 = 2, /* word32, S + A - P */ - R_386_GOT32 = 3, /* word32, G + A - P */ - R_386_PLT32 = 4, /* word32, L + A - P */ - R_386_COPY = 5, /* none */ - R_386_GLOB_DAT = 6, /* word32, S */ - R_386_JMP_SLOT = 7, /* word32, S */ - R_386_RELATIVE = 8, /* word32, B + A */ - R_386_GOTOFF = 9, /* word32, S + A - GOT */ - R_386_GOTPC = 10, /* word32, GOT + A - P */ - R_386_TLS_TPOFF = 14, /* Negative offset in static TLS block (GNU - version) */ - R_386_TLS_IE = 15, /* Absolute address of GOT entry for negative - static TLS block offset */ - R_386_TLS_GOTIE = 16, /* GOT entry for negative static TLS block - offset */ - R_386_TLS_LE = 17, /* Negative offset relative to static TLS - (GNU version) */ - R_386_TLS_GD = 18, /* Direct 32 bit for GNU version of GD TLS */ - R_386_TLS_LDM = 19, /* Direct 32 bit for GNU version of LD TLS - in LE code */ - R_386_16 = 20, /* word16, S + A (GNU extension) */ - R_386_PC16 = 21, /* word16, S + A - P (GNU extension) */ - R_386_8 = 22, /* word8, S + A (GNU extension) */ - R_386_PC8 = 23, /* word8, S + A - P (GNU extension) */ - R_386_TLS_GD_32 = 24, /* Direct 32 bit for GD TLS */ - R_386_TLS_GD_PUSH = 25, /* Tag for pushl in GD TLS code */ - R_386_TLS_GD_CALL = 26, /* Relocation for call to */ - R_386_TLS_GD_POP = 27, /* Tag for popl in GD TLS code */ - R_386_TLS_LDM_32 = 28, /* Direct 32 bit for local dynamic code */ - R_386_TLS_LDM_PUSH = 29, /* Tag for pushl in LDM TLS code */ - R_386_TLS_LDM_CALL = 30, /* Relocation for call to */ - R_386_TLS_LDM_POP = 31, /* Tag for popl in LDM TLS code */ - R_386_TLS_LDO_32 = 32, /* Offset relative to TLS block */ - R_386_TLS_IE_32 = 33, /* GOT entry for static TLS block */ - R_386_TLS_LE_32 = 34, /* Offset relative to static TLS block */ - R_386_TLS_DTPMOD32 = 35, /* ID of module containing symbol */ - R_386_TLS_DTPOFF32 = 36, /* Offset in TLS block */ - R_386_TLS_TPOFF32 = 37, /* Offset in static TLS block */ - R_386_TLS_GOTDESC = 39, - R_386_TLS_DESC_CALL = 40, - R_386_TLS_DESC = 41 -} elf_386_relocation_type; - -typedef enum { - R_X86_64_NONE = 0, /* none */ - R_X86_64_64 = 1, /* word64, S + A */ - R_X86_64_PC32 = 2, /* word32, S + A - P */ - R_X86_64_GOT32 = 3, /* word32, G + A */ - R_X86_64_PLT32 = 4, /* word32, L + A - P */ - R_X86_64_COPY = 5, /* none */ - R_X86_64_GLOB_DAT = 6, /* word64, S, set GOT entry to data address */ - R_X86_64_JMP_SLOT = 7, /* word64, S, set GOT entry to code address */ - R_X86_64_RELATIVE = 8, /* word64, B + A */ - R_X86_64_GOTPCREL = 9, /* word32, G + GOT + A - P */ - R_X86_64_32 = 10, /* word32 (zero extend), S + A */ - R_X86_64_32S = 11, /* word32 (sign extend), S + A */ - R_X86_64_16 = 12, /* word16, S + A */ - R_X86_64_PC16 = 13, /* word16, S + A - P */ - R_X86_64_8 = 14, /* word8, S + A */ - R_X86_64_PC8 = 15, /* word8, S + A - P */ - R_X86_64_DPTMOD64 = 16, /* word64, ID of module containing symbol */ - R_X86_64_DTPOFF64 = 17, /* word64, offset in TLS block */ - R_X86_64_TPOFF64 = 18, /* word64, offset in initial TLS block */ - R_X86_64_TLSGD = 19, /* word32, PC-rel offset to GD GOT block */ - R_X86_64_TLSLD = 20, /* word32, PC-rel offset to LD GOT block */ - R_X86_64_DTPOFF32 = 21, /* word32, offset to TLS block */ - R_X86_64_GOTTPOFF = 22, /* word32, PC-rel offset to IE GOT entry */ - R_X86_64_TPOFF32 = 23, /* word32, offset in initial TLS block */ - R_X86_64_PC64 = 24, /* word64, PC relative */ - R_X86_64_GOTOFF64 = 25, /* word64, offset to GOT */ - R_X86_64_GOTPC32 = 26, /* word32, signed pc relative to GOT */ - R_X86_64_GOT64 = 27, /* word64, GOT entry offset */ - R_X86_64_GOTPCREL64 = 28, /* word64, signed pc relative to GOT entry */ - R_X86_64_GOTPC64 = 29, /* word64, signed pc relative to GOT */ - R_X86_64_GOTPLT64 = 30, /* like GOT64, but indicates PLT entry needed */ - R_X86_64_PLTOFF64 = 31, /* word64, GOT relative offset to PLT entry */ - R_X86_64_GOTPC32_TLSDESC = 34, /* GOT offset for TLS descriptor */ - R_X86_64_TLSDESC_CALL = 35, /* Marker for call through TLS descriptor */ - R_X86_64_TLSDESC = 36 /* TLS descriptor */ -} elf_x86_64_relocation_type; - -struct elf_secthead { - elf_section_type type; - elf_section_flags flags; - elf_address offset; - yasm_intnum *size; - elf_section_index link; - elf_section_info info; /* see note ESD1 */ - unsigned long align; - elf_size entsize; - - yasm_symrec *sym; - elf_strtab_entry *name; - elf_section_index index; - - elf_strtab_entry *rel_name; - elf_section_index rel_index; - elf_address rel_offset; - unsigned long nreloc; -}; - -/* Note ESD1: - * for section types SHT_REL, SHT_RELA: - * link -> index of associated symbol table - * info -> index of relocated section - * for section types SHT_SYMTAB, SHT_DYNSYM: - * link -> index of associated string table - * info -> 1+index of last "local symbol" (bind == STB_LOCAL) - * (for section type SHT_DNAMIC: - * link -> index of string table - * info -> 0 ) - * (for section type SHT_HASH: - * link -> index of symbol table to which hash applies - * info -> 0 ) - * for all others: - * link -> SHN_UNDEF - * info -> 0 - */ - -struct elf_reloc_entry { - yasm_reloc reloc; - int rtype_rel; - size_t valsize; - yasm_intnum *addend; - /*@null@*/ yasm_symrec *wrt; - int is_GOT_sym; -}; - -STAILQ_HEAD(elf_strtab_head, elf_strtab_entry); -struct elf_strtab_entry { - STAILQ_ENTRY(elf_strtab_entry) qlink; - unsigned long index; - char *str; -}; - -STAILQ_HEAD(elf_symtab_head, elf_symtab_entry); -struct elf_symtab_entry { - STAILQ_ENTRY(elf_symtab_entry) qlink; - int in_table; - yasm_symrec *sym; - yasm_section *sect; - elf_strtab_entry *name; - elf_address value; - /*@dependent@*/ yasm_expr *xsize; - elf_size size; - elf_section_index index; - elf_symbol_binding bind; - elf_symbol_type type; - elf_symbol_vis vis; - elf_symbol_index symindex; -}; - -#endif /* defined(YASM_OBJFMT_ELF_INTERNAL) */ - -extern const yasm_assoc_data_callback elf_section_data; -extern const yasm_assoc_data_callback elf_symrec_data; -extern const yasm_assoc_data_callback elf_ssym_symrec_data; - - -const elf_machine_handler *elf_set_arch(struct yasm_arch *arch, - yasm_symtab *symtab, - int bits_pref); - -yasm_symrec *elf_get_special_sym(const char *name, const char *parser); - -/* reloc functions */ -int elf_is_wrt_sym_relative(yasm_symrec *wrt); -int elf_is_wrt_pos_adjusted(yasm_symrec *wrt); -elf_reloc_entry *elf_reloc_entry_create(yasm_symrec *sym, - /*@null@*/ yasm_symrec *wrt, - yasm_intnum *addr, - int rel, - size_t valsize, - int is_GOT_sym); -void elf_reloc_entry_destroy(void *entry); - -/* strtab functions */ -elf_strtab_entry *elf_strtab_entry_create(const char *str); -void elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str); -elf_strtab_head *elf_strtab_create(void); -elf_strtab_entry *elf_strtab_append_str(elf_strtab_head *head, const char *str); -void elf_strtab_destroy(elf_strtab_head *head); -unsigned long elf_strtab_output_to_file(FILE *f, elf_strtab_head *head); - -/* symtab functions */ -elf_symtab_entry *elf_symtab_entry_create(elf_strtab_entry *name, - struct yasm_symrec *sym); -elf_symtab_head *elf_symtab_create(void); -void elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry); -void elf_symtab_insert_local_sym(elf_symtab_head *symtab, - elf_symtab_entry *entry); -void elf_symtab_destroy(elf_symtab_head *head); -unsigned long elf_symtab_assign_indices(elf_symtab_head *symtab); -unsigned long elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab, - yasm_errwarns *errwarns); -void elf_symtab_set_nonzero(elf_symtab_entry *entry, - struct yasm_section *sect, - elf_section_index sectidx, - elf_symbol_binding bind, - elf_symbol_type type, - struct yasm_expr *size, - elf_address *value); -void elf_sym_set_visibility(elf_symtab_entry *entry, - elf_symbol_vis vis); -void elf_sym_set_type(elf_symtab_entry *entry, elf_symbol_type type); -void elf_sym_set_size(elf_symtab_entry *entry, struct yasm_expr *size); -int elf_sym_in_table(elf_symtab_entry *entry); - -/* section header functions */ -elf_secthead *elf_secthead_create(elf_strtab_entry *name, - elf_section_type type, - elf_section_flags flags, - elf_address offset, - elf_size size); -void elf_secthead_destroy(elf_secthead *esd); -unsigned long elf_secthead_write_to_file(FILE *f, elf_secthead *esd, - elf_section_index sindex); -void elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead, - elf_reloc_entry *reloc); -elf_section_type elf_secthead_get_type(elf_secthead *shead); -void elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type, - elf_section_flags flags); -int elf_secthead_is_empty(elf_secthead *shead); -struct yasm_symrec *elf_secthead_get_sym(elf_secthead *shead); -unsigned long elf_secthead_get_align(const elf_secthead *shead); -unsigned long elf_secthead_set_align(elf_secthead *shead, unsigned long align); -elf_section_index elf_secthead_get_index(elf_secthead *shead); -elf_section_info elf_secthead_set_info(elf_secthead *shead, - elf_section_info info); -elf_section_index elf_secthead_set_index(elf_secthead *shead, - elf_section_index sectidx); -elf_section_index elf_secthead_set_link(elf_secthead *shead, - elf_section_index link); -elf_section_index elf_secthead_set_rel_index(elf_secthead *shead, - elf_section_index sectidx); -elf_strtab_entry *elf_secthead_set_rel_name(elf_secthead *shead, - elf_strtab_entry *entry); -elf_size elf_secthead_set_entsize(elf_secthead *shead, elf_size size); -struct yasm_symrec *elf_secthead_set_sym(elf_secthead *shead, - struct yasm_symrec *sym); -void elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size); -char *elf_secthead_name_reloc_section(const char *basesect); -void elf_handle_reloc_addend(yasm_intnum *intn, - elf_reloc_entry *reloc, - unsigned long offset); -unsigned long elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab, - yasm_section *sect, - elf_secthead *esd, - elf_section_index sindex); -unsigned long elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect, - elf_secthead *shead, - yasm_errwarns *errwarns); -long elf_secthead_set_file_offset(elf_secthead *shead, long pos); - -/* program header function */ -unsigned long -elf_proghead_get_size(void); -unsigned long -elf_proghead_write_to_file(FILE *f, - elf_offset secthead_addr, - unsigned long secthead_count, - elf_section_index shstrtab_index); - -#endif /* ELF_H_INCLUDED */ +/* + * ELF object format helpers + * + * 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. + */ + +#ifndef ELF_H_INCLUDED +#define ELF_H_INCLUDED + +typedef struct elf_reloc_entry elf_reloc_entry; +typedef struct elf_reloc_head elf_reloc_head; +typedef struct elf_secthead elf_secthead; +typedef struct elf_strtab_entry elf_strtab_entry; +typedef struct elf_strtab_head elf_strtab_head; +typedef struct elf_symtab_entry elf_symtab_entry; +typedef struct elf_symtab_head elf_symtab_head; + +typedef struct elf_machine_handler elf_machine_handler; + +typedef unsigned long elf_address; +typedef unsigned long elf_offset; +typedef unsigned long elf_size; +typedef unsigned long elf_section_info; + +typedef enum { + ET_NONE = 0, + ET_REL = 1, /* Relocatable */ + ET_EXEC = 2, /* Executable */ + ET_DYN = 3, /* Shared object */ + ET_CORE = 4, /* Core */ + ET_LOOS = 0xfe00, /* Environment specific */ + ET_HIOS = 0xfeff, + ET_LOPROC = 0xff00, /* Processor specific */ + ET_HIPROC = 0xffff +} elf_file_type; + +typedef enum { + EM_NONE = 0, + EM_M32 = 1, /* AT&T WE 32100 */ + EM_SPARC = 2, /* SPARC */ + EM_386 = 3, /* Intel 80386 */ + EM_68K = 4, /* Motorola 68000 */ + EM_88K = 5, /* Motorola 88000 */ + EM_860 = 7, /* Intel 80860 */ + EM_MIPS = 8, /* MIPS RS3000 */ + + EM_S370 = 9, /* IBM System/370 */ + EM_MIPS_RS4_BE = 10, /* MIPS R4000 Big-Endian (dep)*/ + EM_PARISC = 15, /* HPPA */ + EM_SPARC32PLUS = 18, /* SPARC v8plus */ + EM_PPC = 20, /* PowerPC 32-bit */ + EM_PPC64 = 21, /* PowerPC 64-bit */ + EM_ARM = 40, /* ARM */ + EM_SPARCV9 = 43, /* SPARC v9 64-bit */ + EM_IA_64 = 50, /* Intel IA-64 */ + EM_X86_64 = 62, /* AMD x86-64 */ + EM_ALPHA = 0x9026 /* Alpha (no ABI) */ +} elf_machine; + +typedef enum { + ELFMAG0 = 0x7f, + ELFMAG1 = 0x45, + ELFMAG2 = 0x4c, + ELFMAG3 = 0x46 +} elf_magic; + +typedef enum { + EV_NONE = 0, /* invalid */ + EV_CURRENT = 1 /* current */ +} elf_version; + +typedef enum { + EI_MAG0 = 0, /* File id */ + EI_MAG1 = 1, + EI_MAG2 = 2, + EI_MAG3 = 3, + EI_CLASS = 4, /* File class */ + EI_DATA = 5, /* Data encoding */ + EI_VERSION = 6, /* File version */ + EI_OSABI = 7, /* OS and ABI */ + EI_ABIVERSION = 8, /* version of ABI */ + + EI_PAD = 9, /* Pad to end; start here */ + EI_NIDENT = 16 /* Sizeof e_ident[] */ +} elf_identification_index; + +typedef enum { + ELFOSABI_SYSV = 0, /* System V ABI */ + ELFOSABI_HPUX = 1, /* HP-UX os */ + ELFOSABI_STANDALONE = 255 /* Standalone / embedded app */ +} elf_osabi_index; + +typedef enum { + ELFCLASSNONE = 0, /* invalid */ + ELFCLASS32 = 1, /* 32-bit */ + ELFCLASS64 = 2 /* 64-bit */ +} elf_class; + +typedef enum { + ELFDATANONE = 0, + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 +} elf_data_encoding; + +/* elf section types - index of semantics */ +typedef enum { + SHT_NULL = 0, /* inactive section - no associated data */ + SHT_PROGBITS = 1, /* defined by program for its own meaning */ + SHT_SYMTAB = 2, /* symbol table (primarily) for linking */ + SHT_STRTAB = 3, /* string table - symbols need names */ + SHT_RELA = 4, /* relocation entries w/ explicit addends */ + SHT_HASH = 5, /* symbol hash table - for dynamic linking */ + SHT_DYNAMIC = 6, /* information for dynamic linking */ + SHT_NOTE = 7, /* extra data marking the file somehow */ + SHT_NOBITS = 8, /* no stored data, but occupies runtime space */ + SHT_REL = 9, /* relocations entries w/o explicit addends */ + SHT_SHLIB = 10, /* reserved; unspecified semantics */ + SHT_DYNSYM = 11, /* like symtab, but more for dynamic linking */ + + SHT_LOOS = 0x60000000, /* reserved for environment specific use */ + SHT_HIOS = 0x6fffffff, + SHT_LOPROC = 0x70000000, /* reserved for processor specific semantics */ + SHT_HIPROC = 0x7fffffff/*, + SHT_LOUSER = 0x80000000,*/ /* reserved for applications; safe */ + /*SHT_HIUSER = 0xffffffff*/ +} elf_section_type; + +/* elf section flags - bitfield of attributes */ +typedef enum { + SHF_WRITE = 0x1, /* data should be writable at runtime */ + SHF_ALLOC = 0x2, /* occupies memory at runtime */ + SHF_EXECINSTR = 0x4, /* contains machine instructions */ + SHF_MERGE = 0x10, /* data can be merged */ + SHF_STRINGS = 0x20, /* contains 0-terminated strings */ + SHF_GROUP = 0x200, /* member of a section group */ + SHF_TLS = 0x400, /* thread local storage */ + SHF_MASKOS = 0x0f000000/*,*//* environment specific use */ + /*SHF_MASKPROC = 0xf0000000*/ /* bits reserved for processor specific needs */ +} elf_section_flags; + +/* elf section index - just the special ones */ +typedef enum { + SHN_UNDEF = 0, /* undefined symbol; requires other global */ + SHN_LORESERVE = 0xff00, /* reserved for various semantics */ + SHN_LOPROC = 0xff00, /* reserved for processor specific semantics */ + SHN_HIPROC = 0xff1f, + SHN_LOOS = 0xff20, /* reserved for environment specific use */ + SHN_HIOS = 0xff3f, + SHN_ABS = 0xfff1, /* associated symbols don't change on reloc */ + SHN_COMMON = 0xfff2, /* associated symbols refer to unallocated */ + SHN_HIRESERVE = 0xffff +} elf_section_index; + +/* elf symbol binding - index of visibility/behavior */ +typedef enum { + STB_LOCAL = 0, /* invisible outside defining file */ + STB_GLOBAL = 1, /* visible to all combined object files */ + STB_WEAK = 2, /* global but lower precedence */ + + STB_LOOS = 10, /* Environment specific use */ + STB_HIOS = 12, + STB_LOPROC = 13, /* reserved for processor specific semantics */ + STB_HIPROC = 15 +} elf_symbol_binding; + +/* elf symbol type - index of classifications */ +typedef enum { + STT_NOTYPE = 0, /* type not specified */ + STT_OBJECT = 1, /* data object such as a variable, array, etc */ + STT_FUNC = 2, /* a function or executable code */ + STT_SECTION = 3, /* a section: often for relocation, STB_LOCAL */ + STT_FILE = 4, /* often source filename: STB_LOCAL, SHN_ABS */ + STT_COMMON = 5, /* Uninitialized common block. */ + STT_TLS = 6, /* TLS object. */ + STT_NUM = 7, + + STT_LOOS = 10, /* Environment specific use */ + STT_HIOS = 12, + STT_LOPROC = 13, /* reserved for processor specific semantics */ + STT_HIPROC = 15 +} elf_symbol_type; + +typedef enum { + STN_UNDEF = 0 +} elf_symbol_index; + +/* elf symbol visibility - lower two bits of OTHER field */ +typedef enum { + STV_DEFAULT = 0, /* Default symbol visibility rules */ + STV_INTERNAL = 1, /* Processor specific hidden class */ + STV_HIDDEN = 2, /* Sym unavailable in other modules */ + STV_PROTECTED = 3 /* Not preemptable, not exported */ +} elf_symbol_vis; + + +/* internal only object definitions */ +#ifdef YASM_OBJFMT_ELF_INTERNAL + +#define ELF_VISIBILITY_MASK 0x03 +#define ELF_ST_VISIBILITY(v) ((v) & ELF_VISIBILITY_MASK) + +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) +#define ELF32_ST_OTHER(vis) ELF_ST_VISIBILITY(vis) + +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#define ELF64_R_INFO(s,t) (((s)<<32) + ((t) & 0xffffffffL)) +#define ELF64_ST_OTHER(vis) ELF_ST_VISIBILITY(vis) + +#define EHDR32_SIZE 52 +#define EHDR64_SIZE 64 +#define EHDR_MAXSIZE 64 + +#define SHDR32_SIZE 40 +#define SHDR64_SIZE 64 +#define SHDR_MAXSIZE 64 + +#define SYMTAB32_SIZE 16 +#define SYMTAB64_SIZE 24 +#define SYMTAB_MAXSIZE 24 + +#define SYMTAB32_ALIGN 4 +#define SYMTAB64_ALIGN 8 + +#define RELOC32_SIZE 8 +#define RELOC32A_SIZE 12 +#define RELOC64_SIZE 16 +#define RELOC64A_SIZE 24 +#define RELOC_MAXSIZE 24 + +#define RELOC32_ALIGN 4 +#define RELOC64_ALIGN 8 + + +/* elf relocation type - index of semantics + * + * A = Addend (r_addend for RELA, value at location for REL) + * B = Base address + * G = Offset into global offset table (GOT) + * GOT = Address of the global offset table (GOT) + * L = Location of procedure linkage table (PLT) + * P = Location of location being relocated (r_offset) + * S = Value of symbol + */ +typedef enum { + R_386_NONE = 0, /* none */ + R_386_32 = 1, /* word32, S + A */ + R_386_PC32 = 2, /* word32, S + A - P */ + R_386_GOT32 = 3, /* word32, G + A - P */ + R_386_PLT32 = 4, /* word32, L + A - P */ + R_386_COPY = 5, /* none */ + R_386_GLOB_DAT = 6, /* word32, S */ + R_386_JMP_SLOT = 7, /* word32, S */ + R_386_RELATIVE = 8, /* word32, B + A */ + R_386_GOTOFF = 9, /* word32, S + A - GOT */ + R_386_GOTPC = 10, /* word32, GOT + A - P */ + R_386_TLS_TPOFF = 14, /* Negative offset in static TLS block (GNU + version) */ + R_386_TLS_IE = 15, /* Absolute address of GOT entry for negative + static TLS block offset */ + R_386_TLS_GOTIE = 16, /* GOT entry for negative static TLS block + offset */ + R_386_TLS_LE = 17, /* Negative offset relative to static TLS + (GNU version) */ + R_386_TLS_GD = 18, /* Direct 32 bit for GNU version of GD TLS */ + R_386_TLS_LDM = 19, /* Direct 32 bit for GNU version of LD TLS + in LE code */ + R_386_16 = 20, /* word16, S + A (GNU extension) */ + R_386_PC16 = 21, /* word16, S + A - P (GNU extension) */ + R_386_8 = 22, /* word8, S + A (GNU extension) */ + R_386_PC8 = 23, /* word8, S + A - P (GNU extension) */ + R_386_TLS_GD_32 = 24, /* Direct 32 bit for GD TLS */ + R_386_TLS_GD_PUSH = 25, /* Tag for pushl in GD TLS code */ + R_386_TLS_GD_CALL = 26, /* Relocation for call to */ + R_386_TLS_GD_POP = 27, /* Tag for popl in GD TLS code */ + R_386_TLS_LDM_32 = 28, /* Direct 32 bit for local dynamic code */ + R_386_TLS_LDM_PUSH = 29, /* Tag for pushl in LDM TLS code */ + R_386_TLS_LDM_CALL = 30, /* Relocation for call to */ + R_386_TLS_LDM_POP = 31, /* Tag for popl in LDM TLS code */ + R_386_TLS_LDO_32 = 32, /* Offset relative to TLS block */ + R_386_TLS_IE_32 = 33, /* GOT entry for static TLS block */ + R_386_TLS_LE_32 = 34, /* Offset relative to static TLS block */ + R_386_TLS_DTPMOD32 = 35, /* ID of module containing symbol */ + R_386_TLS_DTPOFF32 = 36, /* Offset in TLS block */ + R_386_TLS_TPOFF32 = 37, /* Offset in static TLS block */ + R_386_TLS_GOTDESC = 39, + R_386_TLS_DESC_CALL = 40, + R_386_TLS_DESC = 41 +} elf_386_relocation_type; + +typedef enum { + R_X86_64_NONE = 0, /* none */ + R_X86_64_64 = 1, /* word64, S + A */ + R_X86_64_PC32 = 2, /* word32, S + A - P */ + R_X86_64_GOT32 = 3, /* word32, G + A */ + R_X86_64_PLT32 = 4, /* word32, L + A - P */ + R_X86_64_COPY = 5, /* none */ + R_X86_64_GLOB_DAT = 6, /* word64, S, set GOT entry to data address */ + R_X86_64_JMP_SLOT = 7, /* word64, S, set GOT entry to code address */ + R_X86_64_RELATIVE = 8, /* word64, B + A */ + R_X86_64_GOTPCREL = 9, /* word32, G + GOT + A - P */ + R_X86_64_32 = 10, /* word32 (zero extend), S + A */ + R_X86_64_32S = 11, /* word32 (sign extend), S + A */ + R_X86_64_16 = 12, /* word16, S + A */ + R_X86_64_PC16 = 13, /* word16, S + A - P */ + R_X86_64_8 = 14, /* word8, S + A */ + R_X86_64_PC8 = 15, /* word8, S + A - P */ + R_X86_64_DPTMOD64 = 16, /* word64, ID of module containing symbol */ + R_X86_64_DTPOFF64 = 17, /* word64, offset in TLS block */ + R_X86_64_TPOFF64 = 18, /* word64, offset in initial TLS block */ + R_X86_64_TLSGD = 19, /* word32, PC-rel offset to GD GOT block */ + R_X86_64_TLSLD = 20, /* word32, PC-rel offset to LD GOT block */ + R_X86_64_DTPOFF32 = 21, /* word32, offset to TLS block */ + R_X86_64_GOTTPOFF = 22, /* word32, PC-rel offset to IE GOT entry */ + R_X86_64_TPOFF32 = 23, /* word32, offset in initial TLS block */ + R_X86_64_PC64 = 24, /* word64, PC relative */ + R_X86_64_GOTOFF64 = 25, /* word64, offset to GOT */ + R_X86_64_GOTPC32 = 26, /* word32, signed pc relative to GOT */ + R_X86_64_GOT64 = 27, /* word64, GOT entry offset */ + R_X86_64_GOTPCREL64 = 28, /* word64, signed pc relative to GOT entry */ + R_X86_64_GOTPC64 = 29, /* word64, signed pc relative to GOT */ + R_X86_64_GOTPLT64 = 30, /* like GOT64, but indicates PLT entry needed */ + R_X86_64_PLTOFF64 = 31, /* word64, GOT relative offset to PLT entry */ + R_X86_64_GOTPC32_TLSDESC = 34, /* GOT offset for TLS descriptor */ + R_X86_64_TLSDESC_CALL = 35, /* Marker for call through TLS descriptor */ + R_X86_64_TLSDESC = 36 /* TLS descriptor */ +} elf_x86_64_relocation_type; + +struct elf_secthead { + elf_section_type type; + elf_section_flags flags; + elf_address offset; + yasm_intnum *size; + elf_section_index link; + elf_section_info info; /* see note ESD1 */ + unsigned long align; + elf_size entsize; + + yasm_symrec *sym; + elf_strtab_entry *name; + elf_section_index index; + + elf_strtab_entry *rel_name; + elf_section_index rel_index; + elf_address rel_offset; + unsigned long nreloc; +}; + +/* Note ESD1: + * for section types SHT_REL, SHT_RELA: + * link -> index of associated symbol table + * info -> index of relocated section + * for section types SHT_SYMTAB, SHT_DYNSYM: + * link -> index of associated string table + * info -> 1+index of last "local symbol" (bind == STB_LOCAL) + * (for section type SHT_DNAMIC: + * link -> index of string table + * info -> 0 ) + * (for section type SHT_HASH: + * link -> index of symbol table to which hash applies + * info -> 0 ) + * for all others: + * link -> SHN_UNDEF + * info -> 0 + */ + +struct elf_reloc_entry { + yasm_reloc reloc; + int rtype_rel; + size_t valsize; + yasm_intnum *addend; + /*@null@*/ yasm_symrec *wrt; + int is_GOT_sym; +}; + +STAILQ_HEAD(elf_strtab_head, elf_strtab_entry); +struct elf_strtab_entry { + STAILQ_ENTRY(elf_strtab_entry) qlink; + unsigned long index; + char *str; +}; + +STAILQ_HEAD(elf_symtab_head, elf_symtab_entry); +struct elf_symtab_entry { + STAILQ_ENTRY(elf_symtab_entry) qlink; + int in_table; + yasm_symrec *sym; + yasm_section *sect; + elf_strtab_entry *name; + elf_address value; + /*@dependent@*/ yasm_expr *xsize; + elf_size size; + elf_section_index index; + elf_symbol_binding bind; + elf_symbol_type type; + elf_symbol_vis vis; + elf_symbol_index symindex; +}; + +#endif /* defined(YASM_OBJFMT_ELF_INTERNAL) */ + +extern const yasm_assoc_data_callback elf_section_data; +extern const yasm_assoc_data_callback elf_symrec_data; +extern const yasm_assoc_data_callback elf_ssym_symrec_data; + + +const elf_machine_handler *elf_set_arch(struct yasm_arch *arch, + yasm_symtab *symtab, + int bits_pref); + +yasm_symrec *elf_get_special_sym(const char *name, const char *parser); + +/* reloc functions */ +int elf_is_wrt_sym_relative(yasm_symrec *wrt); +int elf_is_wrt_pos_adjusted(yasm_symrec *wrt); +elf_reloc_entry *elf_reloc_entry_create(yasm_symrec *sym, + /*@null@*/ yasm_symrec *wrt, + yasm_intnum *addr, + int rel, + size_t valsize, + int is_GOT_sym); +void elf_reloc_entry_destroy(void *entry); + +/* strtab functions */ +elf_strtab_entry *elf_strtab_entry_create(const char *str); +void elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str); +elf_strtab_head *elf_strtab_create(void); +elf_strtab_entry *elf_strtab_append_str(elf_strtab_head *head, const char *str); +void elf_strtab_destroy(elf_strtab_head *head); +unsigned long elf_strtab_output_to_file(FILE *f, elf_strtab_head *head); + +/* symtab functions */ +elf_symtab_entry *elf_symtab_entry_create(elf_strtab_entry *name, + struct yasm_symrec *sym); +elf_symtab_head *elf_symtab_create(void); +void elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry); +void elf_symtab_insert_local_sym(elf_symtab_head *symtab, + elf_symtab_entry *entry); +void elf_symtab_destroy(elf_symtab_head *head); +unsigned long elf_symtab_assign_indices(elf_symtab_head *symtab); +unsigned long elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab, + yasm_errwarns *errwarns); +void elf_symtab_set_nonzero(elf_symtab_entry *entry, + struct yasm_section *sect, + elf_section_index sectidx, + elf_symbol_binding bind, + elf_symbol_type type, + struct yasm_expr *size, + elf_address *value); +void elf_sym_set_visibility(elf_symtab_entry *entry, + elf_symbol_vis vis); +void elf_sym_set_type(elf_symtab_entry *entry, elf_symbol_type type); +void elf_sym_set_size(elf_symtab_entry *entry, struct yasm_expr *size); +int elf_sym_in_table(elf_symtab_entry *entry); + +/* section header functions */ +elf_secthead *elf_secthead_create(elf_strtab_entry *name, + elf_section_type type, + elf_section_flags flags, + elf_address offset, + elf_size size); +void elf_secthead_destroy(elf_secthead *esd); +unsigned long elf_secthead_write_to_file(FILE *f, elf_secthead *esd, + elf_section_index sindex); +void elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead, + elf_reloc_entry *reloc); +elf_section_type elf_secthead_get_type(elf_secthead *shead); +void elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type, + elf_section_flags flags); +int elf_secthead_is_empty(elf_secthead *shead); +struct yasm_symrec *elf_secthead_get_sym(elf_secthead *shead); +unsigned long elf_secthead_get_align(const elf_secthead *shead); +unsigned long elf_secthead_set_align(elf_secthead *shead, unsigned long align); +elf_section_index elf_secthead_get_index(elf_secthead *shead); +elf_section_info elf_secthead_set_info(elf_secthead *shead, + elf_section_info info); +elf_section_index elf_secthead_set_index(elf_secthead *shead, + elf_section_index sectidx); +elf_section_index elf_secthead_set_link(elf_secthead *shead, + elf_section_index link); +elf_section_index elf_secthead_set_rel_index(elf_secthead *shead, + elf_section_index sectidx); +elf_strtab_entry *elf_secthead_set_rel_name(elf_secthead *shead, + elf_strtab_entry *entry); +elf_size elf_secthead_set_entsize(elf_secthead *shead, elf_size size); +struct yasm_symrec *elf_secthead_set_sym(elf_secthead *shead, + struct yasm_symrec *sym); +void elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size); +char *elf_secthead_name_reloc_section(const char *basesect); +void elf_handle_reloc_addend(yasm_intnum *intn, + elf_reloc_entry *reloc, + unsigned long offset); +unsigned long elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab, + yasm_section *sect, + elf_secthead *esd, + elf_section_index sindex); +unsigned long elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect, + elf_secthead *shead, + yasm_errwarns *errwarns); +long elf_secthead_set_file_offset(elf_secthead *shead, long pos); + +/* program header function */ +unsigned long +elf_proghead_get_size(void); +unsigned long +elf_proghead_write_to_file(FILE *f, + elf_offset secthead_addr, + unsigned long secthead_count, + elf_section_index shstrtab_index); + +#endif /* ELF_H_INCLUDED */ |