From b49c080965494b4f829bc77fb43bd6fa83893725 Mon Sep 17 00:00:00 2001 From: Peter Johnson <peter@tortall.net> Date: Thu, 21 Feb 2008 08:57:23 +0000 Subject: [PATCH] Set ELF symbol type to TLS if either: - symbol is defined in a TLS section - symbol is used in a TLS relocation This is required by the GNU linker, and matches GNU as behavior. The implementation is not as clean as it perhaps should be, but it does the job. Reported by: Nils Weller <nils@gnulinux.nl> svn path=/trunk/yasm/; revision=2040 --- modules/objfmts/elf/elf-machine.h | 3 +- modules/objfmts/elf/elf-objfmt.c | 7 ++++ modules/objfmts/elf/elf-x86-amd64.c | 27 ++++++++++---- modules/objfmts/elf/elf-x86-x86.c | 36 ++++++++++++++----- modules/objfmts/elf/elf.c | 12 +++++++ modules/objfmts/elf/elf.h | 3 ++ .../elf/tests/gas32/elf_gas32_ssym.hex | 2 +- .../elf/tests/gas64/elf_gas64_ssym.hex | 2 +- 8 files changed, 74 insertions(+), 18 deletions(-) diff --git a/modules/objfmts/elf/elf-machine.h b/modules/objfmts/elf/elf-machine.h index 46cce2db..1742e444 100644 --- a/modules/objfmts/elf/elf-machine.h +++ b/modules/objfmts/elf/elf-machine.h @@ -71,7 +71,8 @@ typedef void (*func_write_proghead)(unsigned char **bufpp, enum { ELF_SSYM_SYM_RELATIVE = 1 << 0, - ELF_SSYM_CURPOS_ADJUST = 1 << 1 + ELF_SSYM_CURPOS_ADJUST = 1 << 1, + ELF_SSYM_THREAD_LOCAL = 1 << 2 }; typedef struct { diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c index b91aec9e..2dbed1f3 100644 --- a/modules/objfmts/elf/elf-objfmt.c +++ b/modules/objfmts/elf/elf-objfmt.c @@ -1069,6 +1069,9 @@ elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams, } 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; } else if (strcmp(sectname, ".rodata") == 0) { data.type = SHT_PROGBITS; data.flags = SHF_ALLOC; @@ -1179,6 +1182,10 @@ dir_type(yasm_object *object, yasm_valparamhead *valparams, 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); diff --git a/modules/objfmts/elf/elf-x86-amd64.c b/modules/objfmts/elf/elf-x86-amd64.c index d9588284..b99f089e 100644 --- a/modules/objfmts/elf/elf-x86-amd64.c +++ b/modules/objfmts/elf/elf-x86-amd64.c @@ -36,11 +36,16 @@ static elf_machine_ssym elf_x86_amd64_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, R_X86_64_TLSGD, 32}, - {"tlsld", ELF_SSYM_SYM_RELATIVE, R_X86_64_TLSLD, 32}, - {"gottpoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTTPOFF, 32}, - {"tpoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_TPOFF32, 32}, - {"dtpoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_DTPOFF32, 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} }; @@ -141,8 +146,18 @@ elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc, size_t i; for (i=0; i<NELEMS(elf_x86_amd64_ssyms); i++) { if (reloc->wrt == ssyms[i] && - reloc->valsize == elf_x86_amd64_ssyms[i].size) + reloc->valsize == elf_x86_amd64_ssyms[i].size) { + /* Force TLS type; this is required by the linker. */ + if (elf_x86_amd64_ssyms[i].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) elf_x86_amd64_ssyms[i].reloc; + } } yasm_internal_error(N_("Unsupported WRT")); } else if (reloc->rtype_rel) { diff --git a/modules/objfmts/elf/elf-x86-x86.c b/modules/objfmts/elf/elf-x86-x86.c index 2a1ba14f..07d60fd2 100644 --- a/modules/objfmts/elf/elf-x86-x86.c +++ b/modules/objfmts/elf/elf-x86-x86.c @@ -38,14 +38,22 @@ static const elf_machine_ssym elf_x86_x86_ssyms[] = { {"gotoff", 0, R_386_GOTOFF, 32}, /* special one for NASM */ {"gotpc", ELF_SSYM_CURPOS_ADJUST, R_386_GOTPC, 32}, - {"tlsgd", ELF_SSYM_SYM_RELATIVE, R_386_TLS_GD, 32}, - {"tlsldm", ELF_SSYM_SYM_RELATIVE, R_386_TLS_LDM, 32}, - {"gottpoff", ELF_SSYM_SYM_RELATIVE, R_386_TLS_IE_32, 32}, - {"tpoff", ELF_SSYM_SYM_RELATIVE, R_386_TLS_LE_32, 32}, - {"ntpoff", ELF_SSYM_SYM_RELATIVE, R_386_TLS_LE, 32}, - {"dtpoff", ELF_SSYM_SYM_RELATIVE, R_386_TLS_LDO_32, 32}, - {"gotntpoff", ELF_SSYM_SYM_RELATIVE, R_386_TLS_GOTIE, 32}, - {"indntpoff", ELF_SSYM_SYM_RELATIVE, R_386_TLS_IE, 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} }; @@ -138,8 +146,18 @@ elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc, size_t i; for (i=0; i<NELEMS(elf_x86_x86_ssyms); i++) { if (reloc->wrt == ssyms[i] && - reloc->valsize == elf_x86_x86_ssyms[i].size) + reloc->valsize == elf_x86_x86_ssyms[i].size) { + /* Force TLS type; this is required by the linker. */ + if (elf_x86_x86_ssyms[i].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) elf_x86_x86_ssyms[i].reloc; + } } yasm_internal_error(N_("Unsupported WRT")); } else if (reloc->rtype_rel) { diff --git a/modules/objfmts/elf/elf.c b/modules/objfmts/elf/elf.c index 807a3afe..01c2fa5b 100644 --- a/modules/objfmts/elf/elf.c +++ b/modules/objfmts/elf/elf.c @@ -495,6 +495,18 @@ elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab, 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")); diff --git a/modules/objfmts/elf/elf.h b/modules/objfmts/elf/elf.h index a10b0b49..1fe18bd2 100644 --- a/modules/objfmts/elf/elf.h +++ b/modules/objfmts/elf/elf.h @@ -191,6 +191,9 @@ typedef enum { 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, diff --git a/modules/objfmts/elf/tests/gas32/elf_gas32_ssym.hex b/modules/objfmts/elf/tests/gas32/elf_gas32_ssym.hex index a6fcecc4..61057e2f 100644 --- a/modules/objfmts/elf/tests/gas32/elf_gas32_ssym.hex +++ b/modules/objfmts/elf/tests/gas32/elf_gas32_ssym.hex @@ -334,7 +334,7 @@ ff 00 00 00 -10 +16 00 00 00 diff --git a/modules/objfmts/elf/tests/gas64/elf_gas64_ssym.hex b/modules/objfmts/elf/tests/gas64/elf_gas64_ssym.hex index 698890fa..06e4c138 100644 --- a/modules/objfmts/elf/tests/gas64/elf_gas64_ssym.hex +++ b/modules/objfmts/elf/tests/gas64/elf_gas64_ssym.hex @@ -462,7 +462,7 @@ ff 00 00 00 -10 +16 00 00 00 -- 2.40.0