From 23bb649090ff588e8642f0c581cfe7ce2d29c757 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sat, 16 Dec 2017 21:01:39 +0100 Subject: m68k: add NPTL/TLS support Port over NPTL/TLS support from GNU C Library. In the first step only the slower syscall is used for TLS access. The uClibc-ng testsuite shows 79 errors, so their is room for bugfixes and improvements. --- ldso/ldso/m68k/dl-sysdep.h | 12 +++++++---- ldso/ldso/m68k/elfinterp.c | 45 ++++++++++++++++++++++++++++++---------- ldso/ldso/m68k/m68k_read_tp.S | 48 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 ldso/ldso/m68k/m68k_read_tp.S (limited to 'ldso') diff --git a/ldso/ldso/m68k/dl-sysdep.h b/ldso/ldso/m68k/dl-sysdep.h index 8ac892655..21937b259 100644 --- a/ldso/ldso/m68k/dl-sysdep.h +++ b/ldso/ldso/m68k/dl-sysdep.h @@ -27,12 +27,16 @@ do { \ 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 - PLT entries should not be allowed to define the value. - ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one +/* 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. + ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one of the main executable's symbols, as for a COPY reloc. */ #define elf_machine_type_class(type) \ - ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ + ((((type) == R_68K_JMP_SLOT \ + || (type) == R_68K_TLS_DTPMOD32 \ + || (type) == R_68K_TLS_DTPREL32 \ + || (type) == R_68K_TLS_TPREL32) * ELF_RTYPE_CLASS_PLT) \ | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY)) /* Return the link-time address of _DYNAMIC. Conveniently, this is the diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c index 15a2c43b1..25ea23067 100644 --- a/ldso/ldso/m68k/elfinterp.c +++ b/ldso/ldso/m68k/elfinterp.c @@ -150,6 +150,9 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, #if defined (__SUPPORT_LD_DEBUG__) ElfW(Addr) old_val; #endif +#if defined USE_TLS && USE_TLS + struct elf_resolve *tls_tpnt = NULL; +#endif reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); reloc_type = ELF_R_TYPE(rpnt->r_info); @@ -167,16 +170,28 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, * might have been intentional. We should not be linking local * symbols here, so all bases should be covered. */ - if (unlikely(!symbol_addr && 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); + if (unlikely (!symbol_addr && + ELF_ST_TYPE (sym_ref.sym->st_info) != STT_TLS && + ELF_ST_BIND (sym_ref.sym->st_info) != STB_WEAK)) { + 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 } +#if defined USE_TLS && USE_TLS + /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous' + symbol. This is the case for a static tls variable, so the lookup + module is just that one is referencing the tls variable. */ + if (!tls_tpnt) + tls_tpnt = tpnt; +#endif + #if defined (__SUPPORT_LD_DEBUG__) old_val = *reloc_addr; #endif @@ -209,13 +224,6 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, case R_68K_JMP_SLOT: *reloc_addr = symbol_addr + rpnt->r_addend; break; - /* handled by elf_machine_relative() - case R_68K_RELATIVE: - *reloc_addr = ((unsigned int) tpnt->loadaddr - / * Compatibility kludge. * / - + (rpnt->r_addend ? : *reloc_addr)); - */ - break; case R_68K_COPY: if (symbol_addr) { #if defined (__SUPPORT_LD_DEBUG__) @@ -234,7 +242,22 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, _dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n"); #endif break; - +#if defined USE_TLS && USE_TLS + case R_68K_TLS_DTPMOD32: + *reloc_addr = tls_tpnt->l_tls_modid; + break; + case R_68K_TLS_DTPREL32: + if (sym_ref.sym != NULL) + *reloc_addr = TLS_DTPREL_VALUE (sym_ref.sym, rpnt); + break; + case R_68K_TLS_TPREL32: + if (sym_ref.sym != NULL) + { + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = TLS_TPREL_VALUE ((struct link_map *) tls_tpnt, sym_ref.sym, rpnt); + } + break; +#endif default: return -1; /* Calls _dl_exit(1). */ } diff --git a/ldso/ldso/m68k/m68k_read_tp.S b/ldso/ldso/m68k/m68k_read_tp.S new file mode 100644 index 000000000..cb5280e67 --- /dev/null +++ b/ldso/ldso/m68k/m68k_read_tp.S @@ -0,0 +1,48 @@ +/* Copyright (C) 2010-2017 Free Software Foundation, Inc. + Contributed by Maxim Kuvyrkov , 2010. + + 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. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + 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 + + .text +# ifdef IS_IN_rtld +/* rtld gets a hidden copy of __m68k_read_tp. */ + .hidden __m68k_read_tp +# endif + +ENTRY (__m68k_read_tp) + move.l #__NR_get_thread_area, %d0 + trap #0 + move.l %d0, %a0 + rts +END (__m68k_read_tp) -- cgit v1.2.3