From 4c3023bc803012656cf45749960282351efc8020 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sat, 20 Sep 2014 22:36:23 +0200 Subject: xtensa: add support for NPTL Changes from: https://github.com/foss-xtensa/uClibc/commits/xtensa_nptl Author: Chris Zankel Author: Baruch Siach --- ldso/ldso/xtensa/dl-debug.h | 77 ++++++++++++---------------------- ldso/ldso/xtensa/dl-startup.h | 2 +- ldso/ldso/xtensa/dl-sysdep.h | 9 ++-- ldso/ldso/xtensa/dl-tlsdesc.S | 96 +++++++++++++++++++++++++++++++++++++++++++ ldso/ldso/xtensa/elfinterp.c | 51 ++++++++++++++++++++--- 5 files changed, 176 insertions(+), 59 deletions(-) create mode 100644 ldso/ldso/xtensa/dl-tlsdesc.S (limited to 'ldso/ldso/xtensa') diff --git a/ldso/ldso/xtensa/dl-debug.h b/ldso/ldso/xtensa/dl-debug.h index 4128d9452..18beae5ca 100644 --- a/ldso/ldso/xtensa/dl-debug.h +++ b/ldso/ldso/xtensa/dl-debug.h @@ -8,54 +8,31 @@ static const char * const _dl_reltypes_tab[] = { - "R_XTENSA_NONE", - "R_XTENSA_32", - "R_XTENSA_RTLD", - "R_XTENSA_GLOB_DAT", - "R_XTENSA_JMP_SLOT", - "R_XTENSA_RELATIVE", - "R_XTENSA_PLT", - "R_XTENSA_UNUSED7", - "R_XTENSA_OP0", - "R_XTENSA_OP1", - "R_XTENSA_OP2", - "R_XTENSA_ASM_EXPAND", - "R_XTENSA_ASM_SIMPLIFY", - "R_XTENSA_UNUSED13", - "R_XTENSA_UNUSED14", - "R_XTENSA_GNU_VTINHERIT", - "R_XTENSA_GNU_VTENTRY", - "R_XTENSA_DIFF8", - "R_XTENSA_DIFF16", - "R_XTENSA_DIFF32", - "R_XTENSA_SLOT0_OP", - "R_XTENSA_SLOT1_OP", - "R_XTENSA_SLOT2_OP", - "R_XTENSA_SLOT3_OP", - "R_XTENSA_SLOT4_OP", - "R_XTENSA_SLOT5_OP", - "R_XTENSA_SLOT6_OP", - "R_XTENSA_SLOT7_OP", - "R_XTENSA_SLOT8_OP", - "R_XTENSA_SLOT9_OP", - "R_XTENSA_SLOT10_OP", - "R_XTENSA_SLOT11_OP", - "R_XTENSA_SLOT12_OP", - "R_XTENSA_SLOT13_OP", - "R_XTENSA_SLOT14_OP", - "R_XTENSA_SLOT0_ALT", - "R_XTENSA_SLOT1_ALT", - "R_XTENSA_SLOT2_ALT", - "R_XTENSA_SLOT3_ALT", - "R_XTENSA_SLOT4_ALT", - "R_XTENSA_SLOT5_ALT", - "R_XTENSA_SLOT6_ALT", - "R_XTENSA_SLOT7_ALT", - "R_XTENSA_SLOT8_ALT", - "R_XTENSA_SLOT9_ALT", - "R_XTENSA_SLOT10_ALT", - "R_XTENSA_SLOT11_ALT", - "R_XTENSA_SLOT12_ALT", - "R_XTENSA_SLOT13_ALT", - "R_XTENSA_SLOT14_ALT" + [0] "R_XTENSA_NONE", "R_XTENSA_32", + [2] "R_XTENSA_RTLD", "R_XTENSA_GLOB_DAT", + [4] "R_XTENSA_JMP_SLOT", "R_XTENSA_RELATIVE", + [6] "R_XTENSA_PLT", "R_XTENSA_UNUSED7", + [8] "R_XTENSA_OP0", "R_XTENSA_OP1", + [10] "R_XTENSA_OP2", "R_XTENSA_ASM_EXPAND", + [12] "R_XTENSA_ASM_SIMPLIFY", "R_XTENSA_UNUSED13", + [14] "R_XTENSA_UNUSED14", "R_XTENSA_GNU_VTINHERIT", + [16] "R_XTENSA_GNU_VTENTRY", "R_XTENSA_DIFF8", + [18] "R_XTENSA_DIFF16", "R_XTENSA_DIFF32", + [20] "R_XTENSA_SLOT0_OP", "R_XTENSA_SLOT1_OP", + [22] "R_XTENSA_SLOT2_OP", "R_XTENSA_SLOT3_OP", + [24] "R_XTENSA_SLOT4_OP", "R_XTENSA_SLOT5_OP", + [26] "R_XTENSA_SLOT6_OP", "R_XTENSA_SLOT7_OP", + [28] "R_XTENSA_SLOT8_OP", "R_XTENSA_SLOT9_OP", + [30] "R_XTENSA_SLOT10_OP", "R_XTENSA_SLOT11_OP", + [32] "R_XTENSA_SLOT12_OP", "R_XTENSA_SLOT13_OP", + [34] "R_XTENSA_SLOT14_OP", "R_XTENSA_SLOT0_ALT", + [36] "R_XTENSA_SLOT1_ALT", "R_XTENSA_SLOT2_ALT", + [38] "R_XTENSA_SLOT3_ALT", "R_XTENSA_SLOT4_ALT", + [40] "R_XTENSA_SLOT5_ALT", "R_XTENSA_SLOT6_ALT", + [42] "R_XTENSA_SLOT7_ALT", "R_XTENSA_SLOT8_ALT", + [44] "R_XTENSA_SLOT9_ALT", "R_XTENSA_SLOT10_ALT", + [46] "R_XTENSA_SLOT11_ALT", "R_XTENSA_SLOT12_ALT", + [48] "R_XTENSA_SLOT13_ALT", "R_XTENSA_SLOT14_ALT", + [50] "R_XTENSA_TLSDESC_FN", "R_XTENSA_TLSDESC_ARG", + [52] "R_XTENSA_TLS_TPOFF" }; diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h index b135a4cb8..70a6255d9 100644 --- a/ldso/ldso/xtensa/dl-startup.h +++ b/ldso/ldso/xtensa/dl-startup.h @@ -11,7 +11,7 @@ __asm__ ( " .text\n" " .align 4\n" - " .literal_position\n" + " .literal_position\n" " .global _start\n" " .type _start, @function\n" " .hidden _start\n" diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h index a0ed4e5f2..148de5b95 100644 --- a/ldso/ldso/xtensa/dl-sysdep.h +++ b/ldso/ldso/xtensa/dl-sysdep.h @@ -78,10 +78,13 @@ typedef struct xtensa_got_location_struct { struct elf_resolve; extern unsigned long _dl_linux_resolver (struct elf_resolve *, int); -/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so - undefined references should not be allowed to define the value. */ +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or + TLS variable, so undefined references should not be allowed to define + the value. */ #define elf_machine_type_class(type) \ - (((type) == R_XTENSA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) + (((type) == R_XTENSA_JMP_SLOT || (type) == R_XTENSA_TLS_TPOFF \ + || (type) == R_XTENSA_TLSDESC_FN || (type) == R_XTENSA_TLSDESC_ARG) \ + * ELF_RTYPE_CLASS_PLT) /* Return the link-time address of _DYNAMIC. */ static __always_inline Elf32_Addr diff --git a/ldso/ldso/xtensa/dl-tlsdesc.S b/ldso/ldso/xtensa/dl-tlsdesc.S new file mode 100644 index 000000000..a6ebc949e --- /dev/null +++ b/ldso/ldso/xtensa/dl-tlsdesc.S @@ -0,0 +1,96 @@ +/* Thread-local storage handling in the ELF dynamic linker. Xtensa version. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#include +#include +#include "tlsdesc.h" + + + .text + .align 4 + .hidden _dl_tlsdesc_return + .global _dl_tlsdesc_return + .type _dl_tlsdesc_return, @function +_dl_tlsdesc_return: + entry a1, 16 + rur.threadptr a3 + add a2, a2, a3 + retw + .size _dl_tlsdesc_return, .-_dl_tlsdesc_return + +#ifdef SHARED + + + /* This function is used for symbols that need dynamic TLS. + + The argument passed to this function points to the TLS descriptor. + + The assembly code that follows is a rendition of the following + C code, hand-optimized a little bit. + + ptrdiff_t + _dl_tlsdesc_dynamic(struct tlsdesc_dynamic_arg *td) + { + dtv_t *dtv = (dtv_t *)THREAD_DTV(); + if (td->gen_count <= dtv[0].counter + && dtv[td->tlsinfo.ti_module].pointer.val + != TLS_DTV_UNALLOCATED) + return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset - __builtin_thread_pointer(); + return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); + } + */ + + .align 4 + .hidden _dl_tlsdesc_dynamic + .global _dl_tlsdesc_dynamic + .type _dl_tlsdesc_dynamic, @function +_dl_tlsdesc_dynamic: + entry a1, 32 + + /* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */ + rur.threadptr a3 + l32i a4, a3, 0 + + /* if (td->gen_count <= dtv[0].counter */ + l32i a6, a2, TLSDESC_GEN_COUNT + l32i a7, a4, 0 + blt a7, a6, .Lslow + + /* && dtv[td->tlsinfo.ti_module].pointer.val != TLS_DTV_UNALLOCATED) */ + l32i a6, a2, TLSDESC_MODID + addx8 a6, a3, a6 + l32i a6, a6, 0 + beqi a6, -1, .Lslow + + /* return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset - __builtin_thread_pointer(); */ + l32i a6, a2, TLSDESC_MODOFF + sub a2, a6, a3 + retw + + /* return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); */ +.Lslow: + mov a10, a2 + movi a8, __tls_get_addr + callx8 a8 + sub a2, a10, a3 + retw + .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic + +#endif /* SHARED */ diff --git a/ldso/ldso/xtensa/elfinterp.c b/ldso/ldso/xtensa/elfinterp.c index b4cf9752d..1397e95c9 100644 --- a/ldso/ldso/xtensa/elfinterp.c +++ b/ldso/ldso/xtensa/elfinterp.c @@ -31,6 +31,8 @@ */ #include "ldso.h" +#include "dl-tls.h" +#include "tlsdeschtab.h" unsigned long _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) @@ -146,6 +148,9 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, int reloc_type; int symtab_index; char *symname; +#if defined USE_TLS && USE_TLS + struct elf_resolve *tls_tpnt = NULL; +#endif struct symbol_ref sym_ref; ElfW(Addr) *reloc_addr; ElfW(Addr) symbol_addr; @@ -172,15 +177,22 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, * here, so all bases should be covered. */ if (unlikely (!symbol_addr && + ELF_ST_TYPE (sym_ref.sym->st_info) != STT_TLS && ELF_ST_BIND (sym_ref.sym->st_info) != STB_WEAK)) { - _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", - _dl_progname, symname); - _dl_exit (1); + return 1; } if (_dl_trace_prelink) { _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], &sym_ref, elf_machine_type_class(reloc_type)); } +#if defined USE_TLS && USE_TLS + tls_tpnt = sym_ref.tpnt; +#endif + } else { + symbol_addr =symtab[symtab_index].st_value; +#if defined USE_TLS && USE_TLS + tls_tpnt = tpnt; +#endif } #if defined (__SUPPORT_LD_DEBUG__) @@ -198,8 +210,8 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, case R_XTENSA_RTLD: if (rpnt->r_addend == 1) { - /* Grab the function pointer stashed at the beginning of the - GOT by the GOT_INIT function. */ + /* Grab the function pointer stashed at the beginning + of the GOT by the GOT_INIT function. */ *reloc_addr = *(ElfW(Addr) *) tpnt->dynamic_info[DT_PLTGOT]; } else if (rpnt->r_addend == 2) { /* Store the link map for the object. */ @@ -213,6 +225,35 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, *reloc_addr += tpnt->loadaddr + rpnt->r_addend; break; +#if defined USE_TLS && USE_TLS + case R_XTENSA_TLS_TPOFF: + CHECK_STATIC_TLS((struct link_map *) tls_tpnt); + *reloc_addr = symbol_addr + tls_tpnt->l_tls_offset + rpnt->r_addend; + break; + case R_XTENSA_TLSDESC_FN: +#ifndef SHARED + CHECK_STATIC_TLS((struct link_map *) tls_tpnt); +#else + if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt)) + *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_dynamic; + else +#endif + *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_return; + break; + case R_XTENSA_TLSDESC_ARG: +#ifndef SHARED + CHECK_STATIC_TLS((struct link_map *) tls_tpnt); +#else + if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt)) + *reloc_addr = (ElfW(Addr)) + _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt, + symbol_addr + *reloc_addr); + else +#endif + *reloc_addr += symbol_addr + tls_tpnt->l_tls_offset; + break; +#endif + default: return -1; /* Calls _dl_exit(1). */ } -- cgit v1.2.3