]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/s390/s390-64/dl-machine.h
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / sysdeps / s390 / s390-64 / dl-machine.h
index fa893befdf5c9e571de4b5379cd97efed50a4c8a..c17c5c892afe82f5d97698ef4244eb02417c89d7 100644 (file)
@@ -1,6 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.
    64 bit S/390 Version.
-   Copyright (C) 2001-2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2001-2019 Free Software Foundation, Inc.
    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
    This file is part of the GNU C Library.
 
@@ -15,9 +15,8 @@
    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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
 
 #ifndef dl_machine_h
 #define dl_machine_h
 #include <sys/param.h>
 #include <string.h>
 #include <link.h>
+#include <sysdeps/s390/dl-procinfo.h>
+#include <dl-irel.h>
+
+#define ELF_MACHINE_IRELATIVE       R_390_IRELATIVE
 
 /* This is an older, now obsolete value.  */
 #define EM_S390_OLD    0xA390
@@ -48,8 +51,8 @@ elf_machine_dynamic (void)
 {
   register Elf64_Addr *got;
 
-  asm( "       larl   %0,_GLOBAL_OFFSET_TABLE_\n"
-       : "=&a" (got) : : "0" );
+  __asm__ ( "  larl   %0,_GLOBAL_OFFSET_TABLE_\n"
+           : "=&a" (got) : : "0" );
 
   return *got;
 }
@@ -60,11 +63,11 @@ elf_machine_load_address (void)
 {
   Elf64_Addr addr;
 
-  asm( "   larl         %0,_dl_start\n"
-       "   larl         1,_GLOBAL_OFFSET_TABLE_\n"
-       "   lghi         2,_dl_start@GOT\n"
-       "   slg  %0,0(2,1)"
-       : "=&d" (addr) : : "1", "2" );
+  __asm__( "   larl     %0,_dl_start\n"
+          "   larl      1,_GLOBAL_OFFSET_TABLE_\n"
+          "   lghi      2,_dl_start@GOT\n"
+          "   slg       %0,0(2,1)"
+          : "=&d" (addr) : : "1", "2" );
   return addr;
 }
 
@@ -76,6 +79,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 {
   extern void _dl_runtime_resolve (Elf64_Word);
   extern void _dl_runtime_profile (Elf64_Word);
+#if defined HAVE_S390_VX_ASM_SUPPORT
+  extern void _dl_runtime_resolve_vx (Elf64_Word);
+  extern void _dl_runtime_profile_vx (Elf64_Word);
+#endif
 
   if (l->l_info[DT_JMPREL] && lazy)
     {
@@ -91,7 +98,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
       if (got[1])
        {
          l->l_mach.plt = got[1] + l->l_addr;
-         l->l_mach.gotplt = (Elf64_Addr) &got[3];
+         l->l_mach.jmprel = (const Elf64_Rela *) D_PTR (l, l_info[DT_JMPREL]);
        }
       got[1] = (Elf64_Addr) l; /* Identify this shared object.  */
 
@@ -101,9 +108,16 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
         to intercept the calls to collect information.  In this case we
         don't store the address in the GOT so that all future calls also
         end in this function.  */
-      if (__builtin_expect (profile, 0))
+      if (__glibc_unlikely (profile))
        {
+#if defined HAVE_S390_VX_ASM_SUPPORT
+         if (GLRO(dl_hwcap) & HWCAP_S390_VX)
+           got[2] = (Elf64_Addr) &_dl_runtime_profile_vx;
+         else
+           got[2] = (Elf64_Addr) &_dl_runtime_profile;
+#else
          got[2] = (Elf64_Addr) &_dl_runtime_profile;
+#endif
 
          if (GLRO(dl_profile) != NULL
              && _dl_name_match_p (GLRO(dl_profile), l))
@@ -112,9 +126,18 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
            GL(dl_profile_map) = l;
        }
       else
-       /* This function will get called to fix up the GOT entry indicated by
-          the offset on the stack, and then jump to the resolved address.  */
-       got[2] = (Elf64_Addr) &_dl_runtime_resolve;
+       {
+         /* This function will get called to fix up the GOT entry indicated by
+            the offset on the stack, and then jump to the resolved address.  */
+#if defined HAVE_S390_VX_ASM_SUPPORT
+         if (GLRO(dl_hwcap) & HWCAP_S390_VX)
+           got[2] = (Elf64_Addr) &_dl_runtime_resolve_vx;
+         else
+           got[2] = (Elf64_Addr) &_dl_runtime_resolve;
+#else
+         got[2] = (Elf64_Addr) &_dl_runtime_resolve;
+#endif
+       }
     }
 
   return lazy;
@@ -124,7 +147,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
    The C function `_dl_start' is the real entry point;
    its return value is the user program's entry point. */
 
-#define RTLD_START asm ("\n\
+#define RTLD_START __asm__ ("\n\
 .text\n\
 .align 4\n\
 .globl _start\n\
@@ -173,7 +196,7 @@ _dl_start_user:\n\
        lgr   %r5,%r3\n\
        sllg  %r5,%r5,3\n\
        la    %r5,176(%r5,%r15)\n\
-       brasl %r14,_dl_init_internal@PLT\n\
+       brasl %r14,_dl_init@PLT\n\
        # Pass our finalizer function to the user in %r14, as per ELF ABI.\n\
        lghi  %r14,_dl_fini@GOT\n\
        lg    %r14,0(%r14,%r12)\n\
@@ -190,7 +213,7 @@ _dl_start_user:\n\
 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
    TLS variable, so undefined references should not be allowed to
    define the value.
-   ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
+   ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
    of the main executable's symbols, as for a COPY reloc.  */
 #define elf_machine_type_class(type) \
   ((((type) == R_390_JMP_SLOT || (type) == R_390_TLS_DTPMOD                  \
@@ -203,6 +226,7 @@ _dl_start_user:\n\
 
 /* The 64 bit S/390 never uses Elf64_Rel relocations.  */
 #define ELF_MACHINE_NO_REL 1
+#define ELF_MACHINE_NO_RELA 0
 
 /* We define an initialization functions.  This is called very early in
    _dl_sysdep_start.  */
@@ -218,6 +242,7 @@ dl_platform_init (void)
 
 static inline Elf64_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+                      const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
                       const Elf64_Rela *reloc,
                       Elf64_Addr *reloc_addr, Elf64_Addr value)
 {
@@ -247,13 +272,13 @@ auto inline void
 __attribute__ ((always_inline))
 elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
                  const Elf64_Sym *sym, const struct r_found_version *version,
-                 void *const reloc_addr_arg)
+                 void *const reloc_addr_arg, int skip_ifunc)
 {
   Elf64_Addr *const reloc_addr = reloc_addr_arg;
   const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
 
 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
-  if (__builtin_expect (r_type == R_390_RELATIVE, 0))
+  if (__glibc_unlikely (r_type == R_390_RELATIVE))
     {
 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
       /* This is defined in rtld.c, but nowhere in the static libc.a;
@@ -271,25 +296,38 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
     }
   else
 #endif
-  if (__builtin_expect (r_type == R_390_NONE, 0))
+  if (__glibc_unlikely (r_type == R_390_NONE))
     return;
   else
     {
-#ifndef RESOLVE_CONFLICT_FIND_MAP
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
+      /* Only needed for R_390_COPY below.  */
       const Elf64_Sym *const refsym = sym;
 #endif
       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
-      Elf64_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
+      Elf64_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
+
+      if (sym != NULL
+         && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC,
+                              0)
+         && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
+         && __builtin_expect (!skip_ifunc, 1))
+       value = elf_ifunc_invoke (value);
 
       switch (r_type)
        {
+       case R_390_IRELATIVE:
+         value = map->l_addr + reloc->r_addend;
+         if (__glibc_likely (!skip_ifunc))
+           value = elf_ifunc_invoke (value);
+         *reloc_addr = value;
+         break;
        case R_390_GLOB_DAT:
        case R_390_JMP_SLOT:
          *reloc_addr = value + reloc->r_addend;
          break;
 
-#if (!defined RTLD_BOOTSTRAP || USE___THREAD) \
-    && !defined RESOLVE_CONFLICT_FIND_MAP
+#ifndef RESOLVE_CONFLICT_FIND_MAP
        case R_390_TLS_DTPMOD:
 # ifdef RTLD_BOOTSTRAP
          /* During startup the dynamic linker is always the module
@@ -347,8 +385,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
              strtab = (const char *) D_PTR (map,l_info[DT_STRTAB]);
              _dl_error_printf ("\
 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
-                               rtld_progname ?: "<program name unknown>",
-                               strtab + refsym->st_name);
+                               RTLD_PROGNAME, strtab + refsym->st_name);
            }
          memcpy (reloc_addr_arg, (void *) value,
                  MIN (sym->st_size, refsym->st_size));
@@ -371,7 +408,6 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
          *reloc_addr = value +reloc->r_addend - (Elf64_Addr) reloc_addr;
          break;
        case R_390_PC32DBL:
-       case R_390_PLT32DBL:
          *(unsigned int *) reloc_addr = (unsigned int)
            ((int) (value + reloc->r_addend - (Elf64_Addr) reloc_addr) >> 1);
          break;
@@ -380,7 +416,6 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
            value + reloc->r_addend - (Elf64_Addr) reloc_addr;
          break;
        case R_390_PC16DBL:
-       case R_390_PLT16DBL:
          *(unsigned short *) reloc_addr = (unsigned short)
            ((short) (value + reloc->r_addend - (Elf64_Addr) reloc_addr) >> 1);
          break;
@@ -415,19 +450,25 @@ elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
 auto inline void
 __attribute__ ((always_inline))
 elf_machine_lazy_rel (struct link_map *map,
-                     Elf64_Addr l_addr, const Elf64_Rela *reloc)
+                     Elf64_Addr l_addr, const Elf64_Rela *reloc,
+                     int skip_ifunc)
 {
   Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
   const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
-  if (__builtin_expect (r_type == R_390_JMP_SLOT, 1))
+  if (__glibc_likely (r_type == R_390_JMP_SLOT))
     {
       if (__builtin_expect (map->l_mach.plt, 0) == 0)
        *reloc_addr += l_addr;
       else
-       *reloc_addr =
-         map->l_mach.plt
-         + (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 4;
+       *reloc_addr = map->l_mach.plt + (reloc - map->l_mach.jmprel) * 32;
+    }
+  else if (__glibc_likely (r_type == R_390_IRELATIVE))
+    {
+      Elf64_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);