aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--sysdeps/aarch64/dl-dtprocnum.h21
-rw-r--r--sysdeps/aarch64/dl-machine.h42
-rw-r--r--sysdeps/aarch64/linkmap.h1
4 files changed, 69 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 456b9ba8bb..7cc8f6e805 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2019-06-13 Szabolcs Nagy <szabolcs.nagy@arm.com>
+ * sysdeps/aarch64/dl-dtprocnum.h: New file.
+ * sysdeps/aarch64/dl-machine.h (DT_AARCH64): Define.
+ (elf_machine_runtime_setup): Handle DT_AARCH64_VARIANT_PCS.
+ (elf_machine_lazy_rel): Check STO_AARCH64_VARIANT_PCS and bind such
+ symbols at load time.
+ * sysdeps/aarch64/linkmap.h (struct link_map_machine): Add variant_pcs.
+
+2019-06-13 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
* elf/elf.h (STO_AARCH64_VARIANT_PCS): Define.
(DT_AARCH64_VARIANT_PCS): Define.
diff --git a/sysdeps/aarch64/dl-dtprocnum.h b/sysdeps/aarch64/dl-dtprocnum.h
new file mode 100644
index 0000000000..4ac2adf234
--- /dev/null
+++ b/sysdeps/aarch64/dl-dtprocnum.h
@@ -0,0 +1,21 @@
+/* Configuration of lookup functions. AArch64 version.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+/* Number of extra dynamic section entries for this architecture. By
+ default there are none. */
+#define DT_THISPROCNUM DT_AARCH64_NUM
diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
index 823eefba46..4f27637b20 100644
--- a/sysdeps/aarch64/dl-machine.h
+++ b/sysdeps/aarch64/dl-machine.h
@@ -27,6 +27,9 @@
#include <dl-irel.h>
#include <cpu-features.c>
+/* Translate a processor specific dynamic tag to the index in l_info array. */
+#define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
+
/* Return nonzero iff ELF header is compatible with the running host. */
static inline int __attribute__ ((unused))
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
@@ -102,6 +105,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
}
}
+ /* Check if STO_AARCH64_VARIANT_PCS needs to be handled. */
+ if (l->l_info[DT_AARCH64 (VARIANT_PCS)])
+ l->l_mach.variant_pcs = 1;
+
return lazy;
}
@@ -388,10 +395,37 @@ elf_machine_lazy_rel (struct link_map *map,
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
{
- if (__builtin_expect (map->l_mach.plt, 0) == 0)
- *reloc_addr += l_addr;
- else
- *reloc_addr = map->l_mach.plt;
+ if (map->l_mach.plt == 0)
+ {
+ /* Prelinking. */
+ *reloc_addr += l_addr;
+ return;
+ }
+
+ if (__glibc_unlikely (map->l_mach.variant_pcs))
+ {
+ /* Check the symbol table for variant PCS symbols. */
+ 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];
+ if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
+ {
+ /* Avoid lazy resolution of variant PCS symbols. */
+ 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];
+ }
+ elf_machine_rela (map, reloc, sym, version, reloc_addr,
+ skip_ifunc);
+ return;
+ }
+ }
+
+ *reloc_addr = map->l_mach.plt;
}
else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
{
diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h
index ba74fe10e1..7f801b14db 100644
--- a/sysdeps/aarch64/linkmap.h
+++ b/sysdeps/aarch64/linkmap.h
@@ -20,4 +20,5 @@ struct link_map_machine
{
ElfW(Addr) plt; /* Address of .plt */
void *tlsdesc_table; /* Address of TLS descriptor hash table. */
+ int variant_pcs; /* If set, PLT calls may follow a variant PCS. */
};