summaryrefslogtreecommitdiff
path: root/sysdeps/arm/dl-machine.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/arm/dl-machine.h')
-rw-r--r--sysdeps/arm/dl-machine.h91
1 files changed, 40 insertions, 51 deletions
diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
index 0905adda7a..1a4fd3f17b 100644
--- a/sysdeps/arm/dl-machine.h
+++ b/sysdeps/arm/dl-machine.h
@@ -1,5 +1,5 @@
/* Machine-dependent ELF dynamic relocation inline functions. ARM version.
- Copyright (C) 1995-2016 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 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
@@ -53,14 +53,29 @@ elf_machine_dynamic (void)
static inline Elf32_Addr __attribute__ ((unused))
elf_machine_load_address (void)
{
- extern Elf32_Addr internal_function __dl_start (void *) asm ("_dl_start");
- Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
Elf32_Addr pcrel_addr;
+#ifdef SHARED
+ extern Elf32_Addr __dl_start (void *) asm ("_dl_start");
+ Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
+ asm ("adr %0, _dl_start" : "=r" (pcrel_addr));
+#else
+ extern Elf32_Addr __dl_relocate_static_pie (void *)
+ asm ("_dl_relocate_static_pie") attribute_hidden;
+ Elf32_Addr got_addr = (Elf32_Addr) &__dl_relocate_static_pie;
+ asm ("adr %0, _dl_relocate_static_pie" : "=r" (pcrel_addr));
+#endif
#ifdef __thumb__
- /* Clear the low bit of the funciton address. */
+ /* Clear the low bit of the function address.
+
+ NOTE: got_addr is from GOT table whose lsb is always set by linker if it's
+ Thumb function address. PCREL_ADDR comes from PC-relative calculation
+ which will finish during assembling. GAS assembler before the fix for
+ PR gas/21458 was not setting the lsb but does after that. Always do the
+ strip for both, so the code works with various combinations of glibc and
+ Binutils. */
got_addr &= ~(Elf32_Addr) 1;
+ pcrel_addr &= ~(Elf32_Addr) 1;
#endif
- asm ("adr %0, _dl_start" : "=r" (pcrel_addr));
return pcrel_addr - got_addr;
}
@@ -112,10 +127,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
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;
}
@@ -263,6 +274,7 @@ dl_platform_init (void)
static inline Elf32_Addr
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+ const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
const Elf32_Rel *reloc,
Elf32_Addr *reloc_addr, Elf32_Addr value)
{
@@ -380,7 +392,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
{
const Elf32_Sym *const refsym = sym;
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
- Elf32_Addr value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
+ Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
if (sym != NULL
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
@@ -440,7 +452,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
binding found in the user program or a loaded library
rather than the dynamic linker's built-in definitions
used while loading those libraries. */
- value -= map->l_addr + refsym->st_value;
+ value -= SYMBOL_ADDRESS (map, refsym, true);
# endif
/* Support relocations on mis-aligned offsets. */
((struct unaligned *) reloc_addr)->x += value;
@@ -448,8 +460,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
}
case R_ARM_TLS_DESC:
{
- struct tlsdesc volatile *td =
- (struct tlsdesc volatile *)reloc_addr;
+ struct tlsdesc *td = (struct tlsdesc *)reloc_addr;
# ifndef RTLD_BOOTSTRAP
if (! sym)
@@ -542,7 +553,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
const Elf32_Sym *const refsym = sym;
# endif
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
- Elf32_Addr value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
+ Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
if (sym != NULL
&& __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
@@ -578,32 +589,6 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
case R_ARM_ABS32:
*reloc_addr = value + reloc->r_addend;
break;
-# ifdef RESOLVE_CONFLICT_FIND_MAP
- case R_ARM_TLS_DESC:
- {
- struct tlsdesc volatile *td =
- (struct tlsdesc volatile *) reloc_addr;
-
- RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
-
- /* Make sure we know what's going on. */
- assert (td->entry
- == (void *) (D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
- + map->l_addr));
- assert (map->l_info[ADDRIDX (DT_TLSDESC_GOT)]);
-
- /* Set up the lazy resolver and store the pointer to our link
- map in _GLOBAL_OFFSET_TABLE[1] now as for a prelinked
- binary elf_machine_runtime_setup() is not called and hence
- neither has been initialized. */
- *(Elf32_Addr *) (D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_GOT)])
- + map->l_addr)
- = (Elf32_Addr) &_dl_tlsdesc_lazy_resolver;
- ((Elf32_Addr *) D_PTR (map, l_info[DT_PLTGOT]))[1]
- = (Elf32_Addr) map;
- }
- break;
-# endif /* RESOLVE_CONFLICT_FIND_MAP */
case R_ARM_PC24:
relocate_pc24 (map, value, reloc_addr, reloc->r_addend);
break;
@@ -679,17 +664,21 @@ elf_machine_lazy_rel (struct link_map *map,
}
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. The latter
- will have been preset by the prelinker if used though.
- We fill it with the resolver address. */
- assert (td->entry == 0
- || map->l_info[VALIDX (DT_GNU_PRELINKED)] != NULL);
- td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
- + map->l_addr);
+ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
+ const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
+ const ElfW (Sym) *sym = &symtab[symndx];
+ const struct r_found_version *version = NULL;
+
+ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW (Half) *vernum =
+ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ version = &map->l_versions[vernum[symndx] & 0x7fff];
+ }
+
+ /* Always initialize TLS descriptors completely, because lazy
+ initialization requires synchronization at every TLS access. */
+ elf_machine_rel (map, reloc, sym, version, reloc_addr, skip_ifunc);
}
else
_dl_reloc_bad_type (map, r_type, 1);