8a8cfb
commit 82bc69c012838a381c4167c156a06f4598f34227
8a8cfb
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
8a8cfb
Date:   Thu Apr 25 15:35:35 2019 +0100
8a8cfb
8a8cfb
    aarch64: handle STO_AARCH64_VARIANT_PCS
8a8cfb
    
8a8cfb
    Avoid lazy binding of symbols that may follow a variant PCS with different
8a8cfb
    register usage convention from the base PCS.
8a8cfb
    
8a8cfb
    Currently the lazy binding entry code does not preserve all the registers
8a8cfb
    required for AdvSIMD and SVE vector calls.  Saving and restoring all
8a8cfb
    registers unconditionally may break existing binaries, even if they never
8a8cfb
    use vector calls, because of the larger stack requirement for lazy
8a8cfb
    resolution, which can be significant on an SVE system.
8a8cfb
    
8a8cfb
    The solution is to mark all symbols in the symbol table that may follow
8a8cfb
    a variant PCS so the dynamic linker can handle them specially.  In this
8a8cfb
    patch such symbols are always resolved at load time, not lazily.
8a8cfb
    
8a8cfb
    So currently LD_AUDIT for variant PCS symbols are not supported, for that
8a8cfb
    the _dl_runtime_profile entry needs to be changed e.g. to unconditionally
8a8cfb
    save/restore all registers (but pass down arg and retval registers to
8a8cfb
    pltentry/exit callbacks according to the base PCS).
8a8cfb
    
8a8cfb
    This patch also removes a __builtin_expect from the modified code because
8a8cfb
    the branch prediction hint did not seem useful.
8a8cfb
    
8a8cfb
            * sysdeps/aarch64/dl-dtprocnum.h: New file.
8a8cfb
            * sysdeps/aarch64/dl-machine.h (DT_AARCH64): Define.
8a8cfb
            (elf_machine_runtime_setup): Handle DT_AARCH64_VARIANT_PCS.
8a8cfb
            (elf_machine_lazy_rel): Check STO_AARCH64_VARIANT_PCS and bind such
8a8cfb
            symbols at load time.
8a8cfb
            * sysdeps/aarch64/linkmap.h (struct link_map_machine): Add variant_pcs.
8a8cfb
8a8cfb
diff --git a/sysdeps/aarch64/dl-dtprocnum.h b/sysdeps/aarch64/dl-dtprocnum.h
8a8cfb
new file mode 100644
8a8cfb
index 0000000000000000..4ac2adf23458e02d
8a8cfb
--- /dev/null
8a8cfb
+++ b/sysdeps/aarch64/dl-dtprocnum.h
8a8cfb
@@ -0,0 +1,21 @@
8a8cfb
+/* Configuration of lookup functions.  AArch64 version.
8a8cfb
+   Copyright (C) 2019 Free Software Foundation, Inc.
8a8cfb
+   This file is part of the GNU C Library.
8a8cfb
+
8a8cfb
+   The GNU C Library is free software; you can redistribute it and/or
8a8cfb
+   modify it under the terms of the GNU Lesser General Public
8a8cfb
+   License as published by the Free Software Foundation; either
8a8cfb
+   version 2.1 of the License, or (at your option) any later version.
8a8cfb
+
8a8cfb
+   The GNU C Library is distributed in the hope that it will be useful,
8a8cfb
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
8a8cfb
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
8a8cfb
+   Lesser General Public License for more details.
8a8cfb
+
8a8cfb
+   You should have received a copy of the GNU Lesser General Public
8a8cfb
+   License along with the GNU C Library.  If not, see
8a8cfb
+   <http://www.gnu.org/licenses/>.  */
8a8cfb
+
8a8cfb
+/* Number of extra dynamic section entries for this architecture.  By
8a8cfb
+   default there are none.  */
8a8cfb
+#define DT_THISPROCNUM	DT_AARCH64_NUM
8a8cfb
diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
8a8cfb
index 4935aa7c543876db..d4494852b32b8783 100644
8a8cfb
--- a/sysdeps/aarch64/dl-machine.h
8a8cfb
+++ b/sysdeps/aarch64/dl-machine.h
8a8cfb
@@ -27,6 +27,9 @@
8a8cfb
 #include <dl-irel.h>
8a8cfb
 #include <cpu-features.c>
8a8cfb
 
8a8cfb
+/* Translate a processor specific dynamic tag to the index in l_info array.  */
8a8cfb
+#define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
8a8cfb
+
8a8cfb
 /* Return nonzero iff ELF header is compatible with the running host.  */
8a8cfb
 static inline int __attribute__ ((unused))
8a8cfb
 elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
8a8cfb
@@ -102,6 +105,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
8a8cfb
 	}
8a8cfb
     }
8a8cfb
 
8a8cfb
+  /* Check if STO_AARCH64_VARIANT_PCS needs to be handled.  */
8a8cfb
+  if (l->l_info[DT_AARCH64 (VARIANT_PCS)])
8a8cfb
+    l->l_mach.variant_pcs = 1;
8a8cfb
+
8a8cfb
   return lazy;
8a8cfb
 }
8a8cfb
 
8a8cfb
@@ -388,10 +395,37 @@ elf_machine_lazy_rel (struct link_map *map,
8a8cfb
   /* Check for unexpected PLT reloc type.  */
8a8cfb
   if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
8a8cfb
     {
8a8cfb
-      if (__builtin_expect (map->l_mach.plt, 0) == 0)
8a8cfb
-	*reloc_addr += l_addr;
8a8cfb
-      else
8a8cfb
-	*reloc_addr = map->l_mach.plt;
8a8cfb
+      if (map->l_mach.plt == 0)
8a8cfb
+	{
8a8cfb
+	  /* Prelinking.  */
8a8cfb
+	  *reloc_addr += l_addr;
8a8cfb
+	  return;
8a8cfb
+	}
8a8cfb
+
8a8cfb
+      if (__glibc_unlikely (map->l_mach.variant_pcs))
8a8cfb
+	{
8a8cfb
+	  /* Check the symbol table for variant PCS symbols.  */
8a8cfb
+	  const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
8a8cfb
+	  const ElfW (Sym) *symtab =
8a8cfb
+	    (const void *)D_PTR (map, l_info[DT_SYMTAB]);
8a8cfb
+	  const ElfW (Sym) *sym = &symtab[symndx];
8a8cfb
+	  if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
8a8cfb
+	    {
8a8cfb
+	      /* Avoid lazy resolution of variant PCS symbols.  */
8a8cfb
+	      const struct r_found_version *version = NULL;
8a8cfb
+	      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
8a8cfb
+		{
8a8cfb
+		  const ElfW (Half) *vernum =
8a8cfb
+		    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
8a8cfb
+		  version = &map->l_versions[vernum[symndx] & 0x7fff];
8a8cfb
+		}
8a8cfb
+	      elf_machine_rela (map, reloc, sym, version, reloc_addr,
8a8cfb
+				skip_ifunc);
8a8cfb
+	      return;
8a8cfb
+	    }
8a8cfb
+	}
8a8cfb
+
8a8cfb
+      *reloc_addr = map->l_mach.plt;
8a8cfb
     }
8a8cfb
   else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
8a8cfb
     {
8a8cfb
diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h
8a8cfb
index 6852f343a1efd150..dd8597470c3d2174 100644
8a8cfb
--- a/sysdeps/aarch64/linkmap.h
8a8cfb
+++ b/sysdeps/aarch64/linkmap.h
8a8cfb
@@ -20,4 +20,5 @@ struct link_map_machine
8a8cfb
 {
8a8cfb
   ElfW(Addr) plt;	  /* Address of .plt */
8a8cfb
   void *tlsdesc_table;	  /* Address of TLS descriptor hash table.  */
8a8cfb
+  int variant_pcs;	  /* If set, PLT calls may follow a variant PCS.  */
8a8cfb
 };