aarch64: Enable ifunc support.
authorWill Newton <will.newton@linaro.org>
Mon, 25 Nov 2013 14:56:28 +0000 (14:56 +0000)
committerWill Newton <will.newton@linaro.org>
Tue, 26 Nov 2013 16:18:04 +0000 (16:18 +0000)
Add support for handling the R_AARCH64_IRELATIVE relocation and
STT_GNU_IFUNC symbols to the aarch64 port.

ports/ChangeLog.aarch64:

2013-11-26  Will Newton  <will.newton@linaro.org>

* sysdeps/aarch64/dl-irel.h: Include ldsodefs.h.
(ELF_MACHINE_IRELA): Define.  (elf_ifunc_invoke): Pass
hwcap to ifunc resolver function.  (elf_irela): New function.
* sysdeps/aarch64/dl-machine.h: Include dl-irel.h.
(elf_machine_rela) Handle STT_GNU_IFUNC symbols and
R_AARCH64_IRELATIVE relocations.  (elf_machine_lazy_rel):
Handle R_AARCH64_IRELATIVE relocations.

ports/ChangeLog.aarch64
ports/sysdeps/aarch64/dl-irel.h
ports/sysdeps/aarch64/dl-machine.h

index 1fd96ee..c6331a4 100644 (file)
@@ -1,3 +1,13 @@
+2013-11-26  Will Newton  <will.newton@linaro.org>
+
+       * sysdeps/aarch64/dl-irel.h: Include ldsodefs.h.
+       (ELF_MACHINE_IRELA): Define.  (elf_ifunc_invoke): Pass
+       hwcap to ifunc resolver function.  (elf_irela): New function.
+       * sysdeps/aarch64/dl-machine.h: Include dl-irel.h.
+       (elf_machine_rela) Handle STT_GNU_IFUNC symbols and
+       R_AARCH64_IRELATIVE relocations.  (elf_machine_lazy_rel):
+       Handle R_AARCH64_IRELATIVE relocations.
+
 2013-10-30  Mike Frysinger  <vapier@gentoo.org>
 
        * sysdeps/unix/sysv/linux/aarch64/configure.in: Moved to ...
index 1a3811e..f37ee39 100644 (file)
 
 #include <stdio.h>
 #include <unistd.h>
+#include <ldsodefs.h>
 
-/* AArch64 does not yet implement IFUNC support.  However since
-   2011-06-20 provision of a elf_ifunc_invoke has been mandatory.  */
+#define ELF_MACHINE_IRELA      1
 
 static inline ElfW(Addr)
 __attribute ((always_inline))
 elf_ifunc_invoke (ElfW(Addr) addr)
 {
-  return ((ElfW(Addr) (*) (void)) (addr)) ();
+  return ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap));
+}
+
+static inline void
+__attribute ((always_inline))
+elf_irela (const ElfW(Rela) *reloc)
+{
+  ElfW(Addr) *const reloc_addr = (void *) reloc->r_offset;
+  const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
+
+  if (__glibc_likely (r_type == R_AARCH64_IRELATIVE))
+    {
+      ElfW(Addr) value = elf_ifunc_invoke (reloc->r_addend);
+      *reloc_addr = value;
+    }
+  else
+    __libc_fatal ("unexpected reloc type in static binary");
 }
 
 #endif
index 71dd6b3..01a214f 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <tls.h>
 #include <dl-tlsdesc.h>
+#include <dl-irel.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int __attribute__ ((unused))
@@ -243,6 +244,12 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
       ElfW(Addr) value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
 
+      if (sym != NULL
+         && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
+         && __glibc_likely (sym->st_shndx != SHN_UNDEF)
+         && __glibc_likely (!skip_ifunc))
+       value = elf_ifunc_invoke (value);
+
       switch (r_type)
        {
        case R_AARCH64_COPY:
@@ -331,6 +338,12 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
            }
          break;
 
+       case R_AARCH64_IRELATIVE:
+         value = map->l_addr + reloc->r_addend;
+         value = elf_ifunc_invoke (value);
+         *reloc_addr = value;
+         break;
+
        default:
          _dl_reloc_bad_type (map, r_type, 0);
          break;
@@ -374,6 +387,13 @@ elf_machine_lazy_rel (struct link_map *map,
       td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
                          + map->l_addr);
     }
+  else if (__glibc_unlikely (r_type == R_AARCH64_IRELATIVE))
+    {
+      ElfW(Addr) value = map->l_addr + reloc->r_addend;
+      if (__glibc_likely (!skip_ifunc))
+       value = elf_ifunc_invoke (value);
+      *reloc_addr = value;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }