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