From: Chris Johns <chr...@rtems.org> This change requires an rtems-tools update for symbol generation.
Working architectures: - aarch64 - arm - powerpc - sparc No newlib TLS support but checked: - i386 - m69k Updates #4920 --- cpukit/include/rtems/rtl/rtl-sym.h | 26 ++++- cpukit/include/rtems/rtl/rtl.h | 8 +- cpukit/libdl/rtl-elf.c | 20 +++- cpukit/libdl/rtl-mdreloc-aarch64.c | 6 +- cpukit/libdl/rtl-mdreloc-arm.c | 3 +- cpukit/libdl/rtl-mdreloc-powerpc.c | 18 +++- cpukit/libdl/rtl-mdreloc-sparc.c | 154 ++++++++++++++++++++++++----- cpukit/libdl/rtl-sym.c | 40 ++++++-- cpukit/libdl/rtl-tls.c | 114 +++++++++++++++++++++ cpukit/libdl/rtl-tls.h | 51 ++++++++++ cpukit/libdl/rtl.c | 8 +- spec/build/cpukit/objdl.yml | 1 + testsuites/libtests/dl11/dl-load.c | 27 ++++- 13 files changed, 418 insertions(+), 58 deletions(-) create mode 100644 cpukit/libdl/rtl-tls.c create mode 100644 cpukit/libdl/rtl-tls.h diff --git a/cpukit/include/rtems/rtl/rtl-sym.h b/cpukit/include/rtems/rtl/rtl-sym.h index 0d29a6ae40..3502b303b8 100644 --- a/cpukit/include/rtems/rtl/rtl-sym.h +++ b/cpukit/include/rtems/rtl/rtl-sym.h @@ -62,6 +62,22 @@ typedef struct rtems_rtl_symbols size_t nbuckets; } rtems_rtl_symbols; +/** + * A TLS variable offset call. There is one per base image TLS + * variable. + */ +typedef size_t (*rtems_rtl_tls_offset_func)(void); + +/** + * A TLS symbol offset entry. It is used with an exported symbol table + * to find a TSL table offset for a variable at runtime. + */ +typedef struct rtems_rtl_tls_offset +{ + size_t index; /** exported symbol table index */ + rtems_rtl_tls_offset_func offset; /** TLS offset function */ +} rtems_rtl_tls_offset; + /** * Open a symbol table with the specified number of buckets. * @@ -101,10 +117,14 @@ void rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols); * @param obj The object table the symbols are for. * @param esyms The exported symbol table. * @param size The size of the table in bytes. + * @param tls_offsets The TLS offsets table. If NULL none provided. + * @param tls_size The number TLS offset entries in the table. */ -bool rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, - const unsigned char* esyms, - unsigned int size); +bool rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, + const unsigned char* esyms, + unsigned int size, + rtems_rtl_tls_offset* tls_offsets, + unsigned int tls_size); /** * Find a symbol given the symbol label in the global symbol table. diff --git a/cpukit/include/rtems/rtl/rtl.h b/cpukit/include/rtems/rtl/rtl.h index 0fd4e74cdf..bd3dce588a 100644 --- a/cpukit/include/rtems/rtl/rtl.h +++ b/cpukit/include/rtems/rtl/rtl.h @@ -393,9 +393,13 @@ bool rtems_rtl_path_prepend (const char* path); * * @param esyms The exported symbol table. * @param count The size of the exported symbol table. + * @param tls_offsets The TLS offsets table. If NULL none provided. + * @param tls_size The number TLS offset entries in the table. */ -void rtems_rtl_base_sym_global_add (const unsigned char* esyms, - unsigned int count); +void rtems_rtl_base_sym_global_add (const unsigned char* esyms, + unsigned int count, + rtems_rtl_tls_offset* tls_offsets, + unsigned int tls_size); /** * Return the object file descriptor for the base image. The object file diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c index 5754070518..b46d2ac3a0 100644 --- a/cpukit/libdl/rtl-elf.c +++ b/cpukit/libdl/rtl-elf.c @@ -178,12 +178,19 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj, /* * If the symbol type is STT_NOTYPE the symbol references a global - * symbol. The gobal symbol table is searched to find it and that value + * symbol. The global symbol table is searched to find it and that value * returned. If the symbol is local to the object module the section for the * symbol is located and it's base added to the symbol's value giving an * absolute location. + * + * If the symbols type of TLS return the symbols value. It is the + * offset from the thread's TLS area base. The offset is set by the + * linker for the base image and by the TLS allocator for loaded + * modules. There is no section and no absolute base. */ - if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE || sym->st_shndx == SHN_COMMON) + if (ELF_ST_TYPE (sym->st_info) == STT_NOTYPE || + sym->st_shndx == SHN_COMMON || + ELF_ST_TYPE (sym->st_info) == STT_TLS) { /* * Search the object file then the global table for the symbol. @@ -246,6 +253,13 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj* obj, rtems_rtl_word rel_words[3]; rtems_rtl_elf_rel_status rs; + /* + * TLS are not parsed. + */ + if (ELF_ST_TYPE (sym->st_info) == STT_TLS) { + return true; + } + /* * Check the reloc record to see if a trampoline is needed. */ @@ -302,7 +316,7 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj* obj, * Find the symbol's object file. It cannot be NULL so ignore that result * if returned, it means something is corrupted. We are in an iterator. */ - rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol); + rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol); if (sobj != NULL) { /* diff --git a/cpukit/libdl/rtl-mdreloc-aarch64.c b/cpukit/libdl/rtl-mdreloc-aarch64.c index 15396c3de9..3b808f6667 100644 --- a/cpukit/libdl/rtl-mdreloc-aarch64.c +++ b/cpukit/libdl/rtl-mdreloc-aarch64.c @@ -309,11 +309,7 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, } if (!parsing) { - target = (Elf_Addr)symvalue + rela->r_addend; - /* Calculate offset accounting for the DTV */ - target -= (uintptr_t)_TLS_Data_begin; - target += sizeof(TLS_Dynamic_thread_vector); - + target = (Elf_Addr)symvalue; target >>= shift; target &= WIDTHMASK(12); if (of_check && target >= of_check) { diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c index fbfd42dc58..b45708dd46 100644 --- a/cpukit/libdl/rtl-mdreloc-arm.c +++ b/cpukit/libdl/rtl-mdreloc-arm.c @@ -526,7 +526,6 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj, break; case R_TYPE(TLS_LE32): -#if ALLOW_UNTESTED_RELOCS if (!parsing) { addend = *where; *where = symvalue + addend; @@ -535,7 +534,7 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj, (void *)*where, where, rtems_rtl_obj_oname (obj)); } break; -#endif + case R_TYPE(TLS_GD32): case R_TYPE(TLS_LDM32): case R_TYPE(TLS_LDO32): diff --git a/cpukit/libdl/rtl-mdreloc-powerpc.c b/cpukit/libdl/rtl-mdreloc-powerpc.c index c6062c872a..49ed9e848c 100644 --- a/cpukit/libdl/rtl-mdreloc-powerpc.c +++ b/cpukit/libdl/rtl-mdreloc-powerpc.c @@ -348,37 +348,47 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, break; case R_TYPE(16_HA): + case R_TYPE(TPREL16_HA): /* * value:6; Field:half16; Expression: #ha(S+A) + * value:72; Field:half16; Expression: #ha(S+A) */ if (!parsing) { tmp = symvalue + rela->r_addend; *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff); if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: 16_HA %p @ %p in %s\n", + printf ("rtl: %s16_HA %p @ %p in %s\n", + ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HA) ? "TPREL" : "", (void *)*(where), where, rtems_rtl_obj_oname (obj)); } break; case R_TYPE(16_HI): + case R_TYPE(TPREL16_HI): /* * value:5; Field:half16; Expression: #hi(S+A) + * value:71; Field:half16; Expression: #hi(S+A) */ if (!parsing) { *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: 16_HI %p @ %p in %s\n", + printf ("rtl: %s16_HI %p @ %p in %s\n", + ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HI) ? "TPREL" : "", (void *)*where, where, rtems_rtl_obj_oname (obj)); } break; + case R_TYPE(16_LO): + case R_TYPE(TPREL16_LO): /* * value:4; Field:half16; Expression: #lo(S+A) + * value:71; Field:half16; Expression: #lo(S+A) */ if (!parsing) { *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: 16_LO %p @ %p in %s\n", + printf ("rtl: %s16_LO %p @ %p in %s\n", + ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_LO) ? "TPREL" : "", (void *)*where, where, rtems_rtl_obj_oname (obj)); } break; @@ -484,7 +494,7 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, (void *)rela->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %" PRId32 - "in non-PLT relocations", + " in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rela->r_info)); return rtems_rtl_elf_rel_failure; } diff --git a/cpukit/libdl/rtl-mdreloc-sparc.c b/cpukit/libdl/rtl-mdreloc-sparc.c index f8a4312a8a..7dd8a2af2f 100644 --- a/cpukit/libdl/rtl-mdreloc-sparc.c +++ b/cpukit/libdl/rtl-mdreloc-sparc.c @@ -87,46 +87,66 @@ static const uint32_t reloc_target_flags[] = { _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */ - _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */ - _RF_SZ(32) | _RF_RS(0), /* COPY */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */ + _RF_SZ(32) | _RF_RS(0), /* COPY */ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ - _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */ - _RF_A| _RF_B|_RF_SZ(32) | _RF_RS(0), /* RELATIVE */ - _RF_S|_RF_A| _RF_U|_RF_SZ(32) | _RF_RS(0), /* UA_32 */ + _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */ + _RF_A| _RF_B| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */ + _RF_S|_RF_A|_RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */ + + /* TLS and 64 bit relocs not listed here... */ }; +#define RELOC_TARGET_FLAGS_SIZE \ + (sizeof(reloc_target_flags) / sizeof(reloc_target_flags[0])) -#define NOT_CURRENTLY_USED_BUT_MAYBE_USEFUL -#ifdef NOT_CURRENTLY_USED_BUT_MAYBE_USEFUL +#define RTLD_DEBUG_RELOC +#ifdef RTLD_DEBUG_RELOC static const char *reloc_names[] = { "NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8", "DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22", "22", "13", "LO10", "GOT10", "GOT13", "GOT22", "PC10", "PC22", "WPLT30", "COPY", - "GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32" + "GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32", + + /* not used with 32bit userland, besides a few of the TLS ones */ + "PLT32", + "HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", "PCPLT32", + "10", "11", "64", "OLO10", "HH22", + "HM10", "LM22", "PC_HH22", "PC_HM10", "PC_LM22", + "WDISP16", "WDISP19", "GLOB_JMP", "7", "5", "6", + "DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44", + "L44", "REGISTER", "UA64", "UA16", + "TLS_GD_HI22", "TLS_GD_LO10", "TLS_GD_ADD", "TLS_GD_CALL", + "TLS_LDM_HI22", "TLS_LDM_LO10", "TLS_LDM_ADD", "TLS_LDM_CALL", + "TLS_LDO_HIX22", "TLS_LDO_LOX10", "TLS_LDO_ADD", "TLS_IE_HI22", + "TLS_IE_LO10", "TLS_IE_LD", "TLS_IE_LDX", "TLS_IE_ADD", "TLS_LE_HIX22", + "TLS_LE_LOX10", "TLS_DTPMOD32", "TLS_DTPMOD64", "TLS_DTPOFF32", + "TLS_DTPOFF64", "TLS_TPOFF32", "TLS_TPOFF64", }; #endif -#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) -#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) -#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) -#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) -#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) -#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) -#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) +#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) +#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) +#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) +#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) +#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) +#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) +#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) +#define RELOC_TLS(t) (t >= R_TYPE(TLS_GD_HI22)) static const int reloc_target_bitmask[] = { #define _BM(x) (~(-(1ULL << (x)))) - 0, /* NONE */ - _BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */ - _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */ - _BM(30), _BM(22), /* WDISP30, WDISP22 */ - _BM(22), _BM(22), /* HI22, _22 */ - _BM(13), _BM(10), /* RELOC_13, _LO10 */ - _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */ - _BM(10), _BM(22), /* _PC10, _PC22 */ - _BM(30), 0, /* _WPLT30, _COPY */ - -1, -1, -1, /* _GLOB_DAT, JMP_SLOT, _RELATIVE */ - _BM(32) /* _UA32 */ + 0, /* NONE */ + _BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */ + _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */ + _BM(30), _BM(22), /* WDISP30, WDISP22 */ + _BM(22), _BM(22), /* HI22, _22 */ + _BM(13), _BM(10), /* RELOC_13, _LO10 */ + _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */ + _BM(10), _BM(22), /* _PC10, _PC22 */ + _BM(30), 0, /* _WPLT30, _COPY */ + -1, -1, -1, /* _GLOB_DAT, JMP_SLOT, _RELATIVE */ + _BM(32) /* _UA32 */ #undef _BM }; #define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) @@ -173,7 +193,20 @@ rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj, bool rtems_rtl_elf_rel_resolve_sym (Elf_Word type) { - return RELOC_RESOLVE_SYMBOL (type) ? true : false; + bool r = false; + if (type < RELOC_TARGET_FLAGS_SIZE) { + r = RELOC_RESOLVE_SYMBOL (type) ? true : false; + } + switch (type) { + case R_TYPE(TLS_DTPOFF32): + case R_TYPE(TLS_LE_HIX22): + case R_TYPE(TLS_LE_LOX10): + r = true; + break; + default: + break; + } + return r; } size_t @@ -240,6 +273,73 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, value = rela->r_addend; + /* + * Handle TLS relocations here, they are different. + */ + if (RELOC_TLS(type)) { + switch (type) { + case R_TYPE(TLS_DTPMOD32): + #if NETBSD_CODE__NOT_USED + *where = (Elf_Addr)defobj->tlsindex; + #endif + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("rtl: reloc: TLS_DTPMOD32 %s in %s --> %p\n", + symname, rtems_rtl_obj_oname (obj), (void *)*where); + break; + + case R_TYPE(TLS_DTPOFF32): + *where = (Elf_Addr)(symvalue + rela->r_addend); + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("rtl: reloc: TLS_DTPOFF32 %s in %s --> %p\n", + symname, rtems_rtl_obj_oname (obj), (void *)*where); + break; + + case R_TYPE(TLS_TPOFF32): + #if NETBSD_CODE__NOT_USED + if (!defobj->tls_static && + _rtld_tls_offset_allocate(__UNCONST(defobj))) + return ; + + *where = (Elf_Addr)(def->st_value - + defobj->tlsoffset + rela->r_addend); + #endif + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("rtl: reloc: TLS_TPOFF32 %s in %s --> %p\n", + symname, rtems_rtl_obj_oname (obj), (void *)*where); + return rtems_rtl_elf_rel_failure; + + case R_TYPE(TLS_LE_HIX22): + *where |= ((symvalue + rela->r_addend) ^ 0xffffffff) >> 10; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("rtl: reloc: R_SPARC_TLS_LE_HIX22 %s in %s --> %p\n", + symname, rtems_rtl_obj_oname (obj), (void *)*where); + break; + + case R_TYPE(TLS_LE_LOX10): + *where |= ((symvalue + rela->r_addend) & 0x3ff) | 0x1c00; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("rtl: reloc: R_SPARC_TLS_LE_LOX10 %s in %s --> %p\n", + symname, rtems_rtl_obj_oname (obj), (void *)*where); + break; + + default: + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf("rtl: reloc: unknown TLS relo: %d for %s in %s --> %p\n", + type, symname, rtems_rtl_obj_oname (obj), (void *)*where); + return rtems_rtl_elf_rel_failure; + } + return rtems_rtl_elf_rel_no_error; + } + + /* + * If it is no TLS relocation (handled above), we can not + * deal with it if it is beyond R_SPARC_6. + */ + if (type > R_TYPE(6)) + return rtems_rtl_elf_rel_failure; + /* * Handle relative relocs here, as an optimization. */ diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c index 5c9c3981df..bd203fd158 100644 --- a/cpukit/libdl/rtl-sym.c +++ b/cpukit/libdl/rtl-sym.c @@ -77,6 +77,22 @@ rtems_rtl_symbol_global_insert (rtems_rtl_symbols* symbols, &symbol->node); } +static rtems_rtl_tls_offset* +rtems_rtl_symbol_find_tls_offset (size_t index, + rtems_rtl_tls_offset* tls_offsets, + size_t tls_size) +{ + size_t entry; + for (entry = 0; entry < tls_size; ++entry) + { + if (tls_offsets[entry].index == index) + { + return &tls_offsets[entry]; + } + } + return NULL; +} + bool rtems_rtl_symbol_table_open (rtems_rtl_symbols* symbols, size_t buckets) @@ -103,9 +119,11 @@ rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols) } bool -rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, - const unsigned char* esyms, - unsigned int size) +rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, + const unsigned char* esyms, + unsigned int size, + rtems_rtl_tls_offset* tls_offsets, + unsigned int tls_size) { rtems_rtl_symbols* symbols; rtems_rtl_obj_sym* sym; @@ -159,6 +177,9 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, symbols = rtems_rtl_global_symbols (); + obj->global_syms = count; + + count = 0; s = 0; sym = obj->global_table; @@ -171,24 +192,29 @@ rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, */ union { uint8_t data[sizeof (void*)]; - void* value; + void* voidp; } copy_voidp; + rtems_rtl_tls_offset* tls_off; int b; sym->name = (const char*) &esyms[s]; s += strlen (sym->name) + 1; for (b = 0; b < sizeof (void*); ++b, ++s) copy_voidp.data[b] = esyms[s]; - sym->value = copy_voidp.value; + tls_off = rtems_rtl_symbol_find_tls_offset (count, tls_offsets, tls_size); + if (tls_off == NULL) { + sym->value = copy_voidp.voidp; + } else { + sym->value = (void*) tls_off->offset(); + } if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value); if (rtems_rtl_symbol_global_find (sym->name) == NULL) rtems_rtl_symbol_global_insert (symbols, sym); + ++count; ++sym; } - obj->global_syms = count; - return true; } diff --git a/cpukit/libdl/rtl-tls.c b/cpukit/libdl/rtl-tls.c new file mode 100644 index 0000000000..0b940c270b --- /dev/null +++ b/cpukit/libdl/rtl-tls.c @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor Thread Local Storage + * + * TLS support the RTL. + */ + +/* + * COPYRIGHT (c) 2023 Chris Johns <chr...@rtems.org> + * + * 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 COPYRIGHT HOLDERS AND 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 COPYRIGHT OWNER OR 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rtl-tls.h" + +/* + * The cpukit/score should provide a call for any arch that + * supports TLS. This code is here until that happens if it + * happens. + */ + +/* + * Pasted in from: + * + * https://android.googlesource.com/platform/bionic/+/refs/heads/main/libc/platform/bionic/tls.h + * + * Note, "#pragma once" has been removed + */ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS AND 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 + * COPYRIGHT OWNER OR 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. + */ +#if defined(__aarch64__) +# define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; }) +#elif defined(__arm__) +# define __get_tls() ({ void** __val; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); __val; }) +#elif defined(__i386__) +# define __get_tls() ({ void** __val; __asm__("movl %%gs:0, %0" : "=r"(__val)); __val; }) +#elif defined(__riscv) +# define __get_tls() ({ void** __val; __asm__("mv %0, tp" : "=r"(__val)); __val; }) +#elif defined(__x86_64__) +# define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; }) +#elif defined(__sparc__) +#include <stdint.h> +# define __get_tls() ({ void** __val; register uintptr_t g7 __asm__( "g7" ); __val = (void**) g7; __val; }) +#elif defined(__powerpc__) +#include <stdint.h> +# define __get_tls() ({ void** __val; register uintptr_t tp __asm__( "2" ); __val = (void**) tp; __val; }) +#elif defined(__m68k__) || defined(__v850__) +/* No TLS support */ +# define __get_tls() (void*) 0UL +#else +#error unsupported architecture +#endif + +#if defined(__get_tls) + +void* rtems_rtl_tls_get_base (void) +{ + return (void*) __get_tls(); +} + +#endif diff --git a/cpukit/libdl/rtl-tls.h b/cpukit/libdl/rtl-tls.h new file mode 100644 index 0000000000..78dc738dd4 --- /dev/null +++ b/cpukit/libdl/rtl-tls.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Run-Time Link Editor Thread Local Storage + * + * TLS support the RTL. + */ + +/* + * COPYRIGHT (c) 2023 Chris Johns <chr...@rtems.org> + * + * 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 COPYRIGHT HOLDERS AND 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 COPYRIGHT OWNER OR 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. + */ + +#if !defined (_RTEMS_RTL_TLS_H_) +#define _RTEMS_RTL_TLS_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void* rtems_rtl_tls_get_base (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c index 21ddb00aac..8250af24c9 100644 --- a/cpukit/libdl/rtl.c +++ b/cpukit/libdl/rtl.c @@ -857,8 +857,10 @@ rtems_rtl_path_prepend (const char* path) } void -rtems_rtl_base_sym_global_add (const unsigned char* esyms, - unsigned int size) +rtems_rtl_base_sym_global_add (const unsigned char* esyms, + unsigned int size, + rtems_rtl_tls_offset* tls_offsets, + unsigned int tls_size) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) printf ("rtl: adding global symbols, table size %u\n", size); @@ -869,7 +871,7 @@ rtems_rtl_base_sym_global_add (const unsigned char* esyms, return; } - rtems_rtl_symbol_global_add (rtl->base, esyms, size); + rtems_rtl_symbol_global_add (rtl->base, esyms, size, tls_offsets, tls_size); rtems_rtl_unlock (); } diff --git a/spec/build/cpukit/objdl.yml b/spec/build/cpukit/objdl.yml index 133485a93d..f6dc9478a6 100644 --- a/spec/build/cpukit/objdl.yml +++ b/spec/build/cpukit/objdl.yml @@ -66,6 +66,7 @@ source: - cpukit/libdl/rtl-shell.c - cpukit/libdl/rtl-string.c - cpukit/libdl/rtl-sym.c +- cpukit/libdl/rtl-tls.c - cpukit/libdl/rtl-trace.c - cpukit/libdl/rtl-unresolved.c - cpukit/libdl/rtl-unwind-dw2.c diff --git a/testsuites/libtests/dl11/dl-load.c b/testsuites/libtests/dl11/dl-load.c index aee1517269..70d7bf1c65 100644 --- a/testsuites/libtests/dl11/dl-load.c +++ b/testsuites/libtests/dl11/dl-load.c @@ -37,10 +37,17 @@ #define TEST_TRACE 0 #if TEST_TRACE + #define SHOW_GLOBAL_SYMS 1 + #if SHOW_GLOBAL_SYMS + #define TRACE_GLOBAL_SYMBOL RTEMS_RTL_TRACE_GLOBAL_SYM + #else + #define TRACE_GLOBAL_SYMBOL 0 + #endif #define DEBUG_TRACE (RTEMS_RTL_TRACE_DETAIL | \ RTEMS_RTL_TRACE_WARNING | \ RTEMS_RTL_TRACE_LOAD | \ RTEMS_RTL_TRACE_UNLOAD | \ + TRACE_GLOBAL_SYMBOL | \ RTEMS_RTL_TRACE_SYMBOL | \ RTEMS_RTL_TRACE_RELOC | \ RTEMS_RTL_TRACE_ALLOCATOR | \ @@ -69,6 +76,9 @@ static void dl_load_dump (void) typedef int (*int_call_t)(void); typedef int* (*ptr_call_t)(void); +void* get_errno_ptr(void); +int get_errno(void); + int dl_load_test(void) { void* handle; @@ -116,7 +126,7 @@ int dl_load_test(void) } ptr_call_ret = ptr_call (); - if (ptr_call_ret != &errno) + if (ptr_call_ret != get_errno_ptr()) { printf("dlsym ptr_call failed: ret value bad\n"); return 1; @@ -124,7 +134,7 @@ int dl_load_test(void) errno = 12345; int_call_ret = int_call (); - if (int_call_ret != 12345) + if (int_call_ret != get_errno()) { printf("dlsym int_call failed: ret value bad\n"); return 1; @@ -140,3 +150,16 @@ int dl_load_test(void) return 0; } + +/* + * Disasseble these to see how the platform accesses TLS + */ +void* get_errno_ptr(void) +{ + return &errno; +} + +int get_errno(void) +{ + return errno; +} -- 2.37.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel