mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-26 06:50:07 +00:00
ARM TLS descriptors support.
This commit is contained in:
parent
57d366bd22
commit
3447f0d785
@ -1,3 +1,23 @@
|
||||
2011-03-05 Nathan Sidwell <nathan@codesourcery.com>
|
||||
Glauber de Oliveira Costa <glommer@gmail.com>
|
||||
|
||||
* sysdeps/arm/dl-tlsdesc.h: New.
|
||||
* sysdeps/arm/dl-tls.h (struct dl_tls_index): Make non-anonymous.
|
||||
* sysdeps/arm/Makefile: Add tlsdesc, dl-tlsdesc for elf
|
||||
subdirectory.
|
||||
* sysdeps/arm/tlsdesc.c: New.
|
||||
* sysdeps/arm/dl-machine.h: #include sysdeps and dl-tlsdesc.h.
|
||||
(elf_machine_runtime_setup): Record dl_tlsdesc_lazy_resolver
|
||||
address.
|
||||
(elf_machine_type_class): Check R_ARM_TLS_DESC.
|
||||
(elf_machine_rel): Add R_ARM_TLS_DESC case.
|
||||
(elf_machine_lazy_rel): Likewise.
|
||||
* sysdeps/arm/dl-tlsdesc.S: New.
|
||||
* sysdeps/arm/bits/linkmap.h (struct link_map_machine): Add
|
||||
tlsdesc_table field.
|
||||
* sysdeps/arm/tlsdesc.sym: New.
|
||||
* sysdeps/arm/dl-lookupcfg.h: New.
|
||||
|
||||
2011-02-16 Manjunath Matti <manjunath81@gmail.com>
|
||||
|
||||
* sysdeps/arm/sysdep.h (CALL_MCOUNT): Use __gnu_mcount_nc
|
||||
|
9
sysdeps/arm/Makefile
Normal file
9
sysdeps/arm/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
ifeq ($(subdir),elf)
|
||||
sysdep-dl-routines += tlsdesc dl-tlsdesc
|
||||
sysdep_routines += tlsdesc dl-tlsdesc
|
||||
sysdep-rtld-routines += tlsdesc dl-tlsdesc
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),csu)
|
||||
gen-as-const-headers += tlsdesc.sym
|
||||
endif
|
@ -1,4 +1,5 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt */
|
||||
void *tlsdesc_table; /* Address of TLS descriptor hash table. */
|
||||
};
|
||||
|
28
sysdeps/arm/dl-lookupcfg.h
Normal file
28
sysdeps/arm/dl-lookupcfg.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* Configuration of lookup functions.
|
||||
Copyright (C) 2006, 2010 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, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#define DL_UNMAP_IS_SPECIAL
|
||||
|
||||
#include_next <dl-lookupcfg.h>
|
||||
|
||||
struct link_map;
|
||||
|
||||
extern void internal_function _dl_unmap (struct link_map *map);
|
||||
|
||||
#define DL_UNMAP(map) _dl_unmap (map)
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <tls.h>
|
||||
#include <dl-tlsdesc.h>
|
||||
|
||||
#define CLEAR_CACHE(BEG,END) \
|
||||
INTERNAL_SYSCALL_ARM (cacheflush, , 3, (BEG), (END), 0)
|
||||
@ -127,6 +128,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
the offset on the stack, and then jump to the resolved address. */
|
||||
got[2] = (Elf32_Addr) &_dl_runtime_resolve;
|
||||
}
|
||||
|
||||
if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy)
|
||||
*(Elf32_Addr*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr)
|
||||
= (Elf32_Addr) &_dl_tlsdesc_lazy_resolver;
|
||||
|
||||
return lazy;
|
||||
}
|
||||
|
||||
@ -239,7 +245,8 @@ _dl_start_user:\n\
|
||||
#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
|
||||
# define elf_machine_type_class(type) \
|
||||
((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \
|
||||
|| (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32) \
|
||||
|| (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32 \
|
||||
|| (type) == R_ARM_TLS_DESC) \
|
||||
* ELF_RTYPE_CLASS_PLT) \
|
||||
| (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
|
||||
#else
|
||||
@ -421,6 +428,39 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
||||
*reloc_addr += value;
|
||||
break;
|
||||
}
|
||||
case R_ARM_TLS_DESC:
|
||||
{
|
||||
struct tlsdesc volatile *td =
|
||||
(struct tlsdesc volatile *)reloc_addr;
|
||||
|
||||
# ifndef RTLD_BOOTSTRAP
|
||||
if (! sym)
|
||||
td->entry = _dl_tlsdesc_undefweak;
|
||||
else
|
||||
# endif
|
||||
{
|
||||
value = sym->st_value + td->argument.value;
|
||||
|
||||
# ifndef RTLD_BOOTSTRAP
|
||||
# ifndef SHARED
|
||||
CHECK_STATIC_TLS (map, sym_map);
|
||||
# else
|
||||
if (!TRY_STATIC_TLS (map, sym_map))
|
||||
{
|
||||
td->argument.pointer
|
||||
= _dl_make_tlsdesc_dynamic (sym_map, value);
|
||||
td->entry = _dl_tlsdesc_dynamic;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
# endif
|
||||
{
|
||||
td->argument.value = value + sym_map->l_tls_offset;
|
||||
td->entry = _dl_tlsdesc_return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_ARM_PC24:
|
||||
{
|
||||
Elf32_Sword addend;
|
||||
@ -612,6 +652,20 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
else
|
||||
*reloc_addr = map->l_mach.plt;
|
||||
}
|
||||
#ifdef USE_TLS
|
||||
else if (__builtin_expect (r_type == R_ARM_TLS_DESC, 1))
|
||||
{
|
||||
struct tlsdesc volatile *td =
|
||||
(struct tlsdesc volatile *)reloc_addr;
|
||||
|
||||
/* The linker must have given us the parameter we need in the
|
||||
first GOT entry, and left the second one empty. We fill the
|
||||
last with the resolver address */
|
||||
assert (td->entry == 0);
|
||||
td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
|
||||
+ map->l_addr);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
_dl_reloc_bad_type (map, r_type, 1);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
/* Type used for the representation of TLS information in the GOT. */
|
||||
typedef struct
|
||||
typedef struct dl_tls_index
|
||||
{
|
||||
unsigned long int ti_module;
|
||||
unsigned long int ti_offset;
|
||||
|
222
sysdeps/arm/dl-tlsdesc.S
Normal file
222
sysdeps/arm/dl-tlsdesc.S
Normal file
@ -0,0 +1,222 @@
|
||||
/* Thread-local storage handling in the ELF dynamic linker. ARM version.
|
||||
Copyright (C) 2006, 2010 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, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <sysdep.h>
|
||||
#include <tls.h>
|
||||
#include "tlsdesc.h"
|
||||
|
||||
#ifdef __USE_BX__
|
||||
#define BX(x) bx x
|
||||
#else
|
||||
#define BX(x) mov pc, x
|
||||
#endif
|
||||
|
||||
.text
|
||||
@ emit debug information with cfi
|
||||
@ use arm-specific pseudos for unwinding itself
|
||||
.cfi_sections .debug_frame
|
||||
#ifdef USE_TLS
|
||||
.hidden _dl_tlsdesc_return
|
||||
.global _dl_tlsdesc_return
|
||||
.type _dl_tlsdesc_return,#function
|
||||
cfi_startproc
|
||||
.fnstart
|
||||
.align 2
|
||||
_dl_tlsdesc_return:
|
||||
ldr r0, [r0]
|
||||
BX (lr)
|
||||
.fnend
|
||||
cfi_endproc
|
||||
.size _dl_tlsdesc_return, .-_dl_tlsdesc_return
|
||||
|
||||
.hidden _dl_tlsdesc_undefweak
|
||||
.global _dl_tlsdesc_undefweak
|
||||
.type _dl_tlsdesc_undefweak,#function
|
||||
cfi_startproc
|
||||
.fnstart
|
||||
.align 2
|
||||
_dl_tlsdesc_undefweak:
|
||||
@ Are we allowed a misaligned stack pointer calling read_tp?
|
||||
.save {lr}
|
||||
stmdb sp!, {lr}
|
||||
cfi_adjust_cfa_offset (4)
|
||||
cfi_rel_offset (lr,0)
|
||||
bl __aeabi_read_tp
|
||||
rsb r0, r0, #0
|
||||
ldmia sp!, {lr}
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
cfi_restore (lr)
|
||||
BX (lr)
|
||||
|
||||
cfi_endproc
|
||||
.fnend
|
||||
.size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
|
||||
|
||||
#ifdef SHARED
|
||||
.hidden _dl_tlsdesc_dynamic
|
||||
.global _dl_tlsdesc_dynamic
|
||||
.type _dl_tlsdesc_dynamic,#function
|
||||
|
||||
|
||||
/*
|
||||
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 *tdp)
|
||||
{
|
||||
struct tlsdesc_dynamic_arg *td = tdp->argument.pointer;
|
||||
dtv_t *dtv = (dtv_t *)THREAD_DTV();
|
||||
if (__builtin_expect (td->gen_count <= dtv[0].counter
|
||||
&& dtv[td->tlsinfo.ti_module].pointer.val
|
||||
!= TLS_DTV_UNALLOCATED,
|
||||
1))
|
||||
return dtv[td->tlsinfo.ti_module].pointer.val +
|
||||
td->tlsinfo.ti_offset - __builtin_thread_pointer();
|
||||
|
||||
return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer();
|
||||
}
|
||||
|
||||
*/
|
||||
cfi_startproc
|
||||
.fnstart
|
||||
.align 2
|
||||
_dl_tlsdesc_dynamic:
|
||||
/* Our calling convention is to clobber r0, r1 and the processor
|
||||
flags. All others that are modified must be saved */
|
||||
.save {r2,r3,r4,lr}
|
||||
stmdb sp!, {r2,r3,r4,lr}
|
||||
cfi_adjust_cfa_offset (16)
|
||||
cfi_rel_offset (r2,0)
|
||||
cfi_rel_offset (r3,4)
|
||||
cfi_rel_offset (r4,8)
|
||||
cfi_rel_offset (lr,12)
|
||||
ldr r1, [r0] /* td */
|
||||
bl __aeabi_read_tp
|
||||
mov r4, r0 /* r4 = tp */
|
||||
ldr r0, [r0]
|
||||
ldr r2, [r1, #8] /* gen_count */
|
||||
ldr r3, [r0]
|
||||
cmp r2, r3
|
||||
bhi 1f
|
||||
ldr r3, [r1]
|
||||
ldr r2, [r0, r3, lsl #3]
|
||||
cmn r2, #1
|
||||
ldrne r3, [r1, #4]
|
||||
addne r3, r2, r3
|
||||
rsbne r0, r4, r3
|
||||
bne 2f
|
||||
1: mov r0, r1
|
||||
bl __tls_get_addr
|
||||
rsb r0, r4, r0
|
||||
2: ldmia sp!, {r2,r3,r4, lr}
|
||||
cfi_adjust_cfa_offset (-16)
|
||||
cfi_restore (lr)
|
||||
cfi_restore (r4)
|
||||
cfi_restore (r3)
|
||||
cfi_restore (r2)
|
||||
BX (lr)
|
||||
.fnend
|
||||
cfi_endproc
|
||||
.size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
|
||||
#endif /* SHARED */
|
||||
|
||||
/* lazy resolved for tls descriptors. */
|
||||
.hidden _dl_tlsdesc_lazy_resolver
|
||||
.global _dl_tlsdesc_lazy_resolver
|
||||
.type _dl_tlsdesc_lazy_resolver,#function
|
||||
cfi_startproc
|
||||
.fnstart
|
||||
.align 2
|
||||
_dl_tlsdesc_lazy_resolver:
|
||||
/* r0 points at the tlsdesc,
|
||||
r1 points at the GOT
|
||||
r2 was pushed by the trampoline and used as a temp,
|
||||
we need to pop it here.
|
||||
We push the remaining call-clobbered registers here, and also
|
||||
R1 -- to keep the stack correctly aligned. */
|
||||
/* Tell the unwinder that r2 has already been pushed. */
|
||||
.save {r2}
|
||||
cfi_adjust_cfa_offset (4)
|
||||
cfi_rel_offset (r2, 0)
|
||||
.save {r0,r1,r3,ip,lr}
|
||||
stmdb sp!, {r0, r1, r3, ip, lr}
|
||||
cfi_adjust_cfa_offset (20)
|
||||
cfi_rel_offset (r0, 0)
|
||||
cfi_rel_offset (r1, 4)
|
||||
cfi_rel_offset (r3, 8)
|
||||
cfi_rel_offset (ip, 12)
|
||||
cfi_rel_offset (lr, 16)
|
||||
bl _dl_tlsdesc_lazy_resolver_fixup
|
||||
ldmia sp!, {r0, r1, r3, ip, lr}
|
||||
cfi_adjust_cfa_offset (-20)
|
||||
cfi_restore (lr)
|
||||
cfi_restore (ip)
|
||||
cfi_restore (r3)
|
||||
cfi_restore (r1)
|
||||
cfi_restore (r0)
|
||||
ldmia sp!, {r2}
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
cfi_restore (r2)
|
||||
ldr r1, [r0, #4]
|
||||
BX (r1)
|
||||
.fnend
|
||||
cfi_endproc
|
||||
.size _dl_tlsdesc_lazy_resolver, .-_dl_tlsdesc_lazy_resolver
|
||||
|
||||
/* Holder for lazy tls descriptors being resolve in another thread.
|
||||
Same ABI as the lazy resolver itself. */
|
||||
.hidden _dl_tlsdesc_resolve_hold
|
||||
.global _dl_tlsdesc_resolve_hold
|
||||
.type _dl_tlsdesc_resolve_hold,#function
|
||||
cfi_startproc
|
||||
.fnstart
|
||||
.align 2
|
||||
_dl_tlsdesc_resolve_hold:
|
||||
/* Tell the unwinder that r2 has already been pushed. */
|
||||
.save {r2}
|
||||
cfi_adjust_cfa_offset (4)
|
||||
cfi_rel_offset (r2, 0)
|
||||
.save {r0,r1,r3,ip,lr}
|
||||
stmdb sp!, {r0, r1, r3, ip, lr}
|
||||
cfi_adjust_cfa_offset (20)
|
||||
cfi_rel_offset (r0, 0)
|
||||
cfi_rel_offset (r1, 4)
|
||||
cfi_rel_offset (r3, 8)
|
||||
cfi_rel_offset (ip, 12)
|
||||
cfi_rel_offset (lr, 16)
|
||||
adr r2, _dl_tlsdesc_resolve_hold
|
||||
bl _dl_tlsdesc_resolve_hold_fixup
|
||||
ldmia sp!, {r0, r1, r3, ip, lr}
|
||||
cfi_adjust_cfa_offset (-20)
|
||||
cfi_restore (lr)
|
||||
cfi_restore (ip)
|
||||
cfi_restore (r3)
|
||||
cfi_restore (r1)
|
||||
cfi_restore (r0)
|
||||
ldmia sp!, {r2}
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
cfi_restore (r2)
|
||||
ldr r1, [r0, #4]
|
||||
BX (r1)
|
||||
.fnend
|
||||
cfi_endproc
|
||||
.size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
|
||||
|
||||
#endif /* USE_TLS */
|
69
sysdeps/arm/dl-tlsdesc.h
Normal file
69
sysdeps/arm/dl-tlsdesc.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* Thread-local storage descriptor handling in the ELF dynamic linker.
|
||||
ARM version.
|
||||
Copyright (C) 2005, 2010 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; witout 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, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#ifndef _ARM_DL_TLSDESC_H
|
||||
# define _ARM_DL_TLSDESC_H 1
|
||||
|
||||
/* Use this to access DT_TLSDESC_PLT and DT_TLSDESC_GOT. */
|
||||
#ifndef ADDRIDX
|
||||
# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
|
||||
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
|
||||
#endif
|
||||
|
||||
/* Type used to represent a TLS descriptor in the GOT. */
|
||||
struct tlsdesc
|
||||
{
|
||||
union
|
||||
{
|
||||
void *pointer;
|
||||
long value;
|
||||
} argument;
|
||||
ptrdiff_t (*entry)(struct tlsdesc *);
|
||||
};
|
||||
|
||||
|
||||
typedef struct dl_tls_index
|
||||
{
|
||||
unsigned long int ti_module;
|
||||
unsigned long int ti_offset;
|
||||
} tls_index;
|
||||
|
||||
/* Type used as the argument in a TLS descriptor for a symbol that
|
||||
needs dynamic TLS offsets. */
|
||||
struct tlsdesc_dynamic_arg
|
||||
{
|
||||
tls_index tlsinfo;
|
||||
size_t gen_count;
|
||||
};
|
||||
|
||||
extern ptrdiff_t attribute_hidden
|
||||
_dl_tlsdesc_return(struct tlsdesc *),
|
||||
_dl_tlsdesc_undefweak(struct tlsdesc *),
|
||||
_dl_tlsdesc_resolve_hold(struct tlsdesc *),
|
||||
_dl_tlsdesc_lazy_resolver(struct tlsdesc *);
|
||||
|
||||
# ifdef SHARED
|
||||
extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
|
||||
|
||||
extern ptrdiff_t attribute_hidden
|
||||
_dl_tlsdesc_dynamic(struct tlsdesc *);
|
||||
# endif
|
||||
|
||||
#endif
|
164
sysdeps/arm/tlsdesc.c
Normal file
164
sysdeps/arm/tlsdesc.c
Normal file
@ -0,0 +1,164 @@
|
||||
/* Manage TLS descriptors. ARM version.
|
||||
Copyright (C) 2005, 2010 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, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <link.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <elf/dynamic-link.h>
|
||||
#include <tls.h>
|
||||
#include <dl-tlsdesc.h>
|
||||
#include <tlsdeschtab.h>
|
||||
|
||||
#ifdef USE_TLS
|
||||
|
||||
/* This function is used to lazily resolve TLS_DESC REL relocations
|
||||
Besides the TLS descriptor itself, we get the module's got address
|
||||
as the second parameter. */
|
||||
|
||||
void
|
||||
attribute_hidden
|
||||
_dl_tlsdesc_lazy_resolver_fixup (struct tlsdesc volatile *td,
|
||||
Elf32_Addr *got)
|
||||
{
|
||||
struct link_map *l = (struct link_map *)got[1];
|
||||
lookup_t result;
|
||||
unsigned long value;
|
||||
|
||||
if (_dl_tlsdesc_resolve_early_return_p
|
||||
(td, (void*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_PLT)]) + l->l_addr)))
|
||||
return;
|
||||
|
||||
if (td->argument.value & 0x80000000)
|
||||
{
|
||||
/* A global symbol, this is the symbol index. */
|
||||
/* The code below was borrowed from _dl_fixup(). */
|
||||
const Elf_Symndx symndx = td->argument.value ^ 0x80000000;
|
||||
const ElfW(Sym) *const symtab
|
||||
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
|
||||
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
|
||||
const ElfW(Sym) *sym = &symtab[symndx];
|
||||
|
||||
/* Look up the target symbol. If the normal lookup rules are not
|
||||
used don't look in the global scope. */
|
||||
if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
|
||||
&& __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
|
||||
{
|
||||
const struct r_found_version *version = NULL;
|
||||
|
||||
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
||||
{
|
||||
const ElfW(Half) *vernum =
|
||||
(const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
|
||||
ElfW(Half) ndx = vernum[symndx] & 0x7fff;
|
||||
version = &l->l_versions[ndx];
|
||||
if (version->hash == 0)
|
||||
version = NULL;
|
||||
}
|
||||
|
||||
result = _dl_lookup_symbol_x
|
||||
(strtab + sym->st_name, l, &sym,
|
||||
l->l_scope, version, ELF_RTYPE_CLASS_PLT,
|
||||
DL_LOOKUP_ADD_DEPENDENCY, NULL);
|
||||
if (sym)
|
||||
value = sym->st_value;
|
||||
else
|
||||
{
|
||||
td->entry = _dl_tlsdesc_undefweak;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We already found the symbol. The module (and therefore its load
|
||||
address) is also known. */
|
||||
result = l;
|
||||
value = sym->st_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A local symbol, this is the offset within our tls section.
|
||||
*/
|
||||
value = td->argument.value;
|
||||
result = l;
|
||||
}
|
||||
|
||||
#ifndef SHARED
|
||||
CHECK_STATIC_TLS (l, result);
|
||||
#else
|
||||
if (!TRY_STATIC_TLS (l, result))
|
||||
{
|
||||
td->argument.pointer = _dl_make_tlsdesc_dynamic (result, value);
|
||||
td->entry = _dl_tlsdesc_dynamic;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
td->argument.value = value + result->l_tls_offset;
|
||||
td->entry = _dl_tlsdesc_return;
|
||||
}
|
||||
|
||||
done:
|
||||
_dl_tlsdesc_wake_up_held_fixups ();
|
||||
}
|
||||
|
||||
/* This function is used to avoid busy waiting for other threads to
|
||||
complete the lazy relocation. Once another thread wins the race to
|
||||
relocate a TLS descriptor, it sets the descriptor up such that this
|
||||
function is called to wait until the resolver releases the
|
||||
lock. */
|
||||
|
||||
void
|
||||
attribute_hidden
|
||||
_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
|
||||
void *caller)
|
||||
{
|
||||
/* Maybe we're lucky and can return early. */
|
||||
if (caller != td->entry)
|
||||
return;
|
||||
|
||||
/* Locking here will stop execution until the running resolver runs
|
||||
_dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
|
||||
|
||||
FIXME: We'd be better off waiting on a condition variable, such
|
||||
that we didn't have to hold the lock throughout the relocation
|
||||
processing. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
|
||||
/* Unmap the dynamic object, but also release its TLS descriptor table
|
||||
if there is one. */
|
||||
|
||||
void
|
||||
internal_function
|
||||
_dl_unmap (struct link_map *map)
|
||||
{
|
||||
__munmap ((void *) (map)->l_map_start,
|
||||
(map)->l_map_end - (map)->l_map_start);
|
||||
|
||||
#if SHARED
|
||||
/* _dl_unmap is only called for dlopen()ed libraries, for which
|
||||
calling free() is safe, or before we've completed the initial
|
||||
relocation, in which case calling free() is probably pointless,
|
||||
but still safe. */
|
||||
if (map->l_mach.tlsdesc_table)
|
||||
htab_delete (map->l_mach.tlsdesc_table);
|
||||
#endif
|
||||
}
|
||||
#endif
|
19
sysdeps/arm/tlsdesc.sym
Normal file
19
sysdeps/arm/tlsdesc.sym
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stddef.h>
|
||||
#include <sysdep.h>
|
||||
#include <tls.h>
|
||||
#include <link.h>
|
||||
#include <dl-tlsdesc.h>
|
||||
|
||||
--
|
||||
|
||||
-- Abuse tls.h macros to derive offsets relative to the thread register.
|
||||
#if defined USE_TLS
|
||||
|
||||
|
||||
TLSDESC_ARG offsetof(struct tlsdesc, argument.pointer)
|
||||
|
||||
TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count)
|
||||
TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
|
||||
TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user