]> 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 95056a8ee970635a94688f8f637cdf20f2322ef1..c17c5c892afe82f5d97698ef4244eb02417c89d7 100644 (file)
@@ -1,6 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.
    64 bit S/390 Version.
-   Copyright (C) 2001, 2002 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,123 +108,46 @@ 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 (_dl_name_match_p (GL(dl_profile), l))
+         if (GLRO(dl_profile) != NULL
+             && _dl_name_match_p (GLRO(dl_profile), l))
            /* This is the object we are looking for.  Say that we really
               want profiling and the timers are started.  */
            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;
 }
 
-/* This code is used in dl-runtime.c to call the `fixup' function
-   and then redirect to the address it returns.         */
-
-/* s390:
-   Arguments are in register.
-   r2 - r7 holds the original parameters for the function call, fixup
-   and trampoline code use r0-r5 and r14-15. For the correct function
-   call r2-r5 and r14-15 must be restored.
-   Arguments from the PLT are stored at 48(r15) and 56(r15)
-   and must be moved to r2 and r3 for the fixup call (see elf32-s390.c
-   in the binutils for the PLT code).
-   Fixup function address in r2.
-*/
-#ifndef PROF
-#define ELF_MACHINE_RUNTIME_TRAMPOLINE \
-  asm ( "\
-    .text\n\
-    .globl _dl_runtime_resolve\n\
-    .type _dl_runtime_resolve, @function\n\
-    .align 16\n\
-_dl_runtime_resolve:\n\
-    # save registers\n\
-    stmg   2,5,64(15)\n\
-    stg           14,96(15)\n\
-    lgr           0,15\n\
-    aghi   15,-160\n\
-    stg           0,0(15)\n\
-    # load args saved by PLT\n\
-    lmg           2,3,208(15)\n\
-    brasl  14,fixup    # call fixup
-    lgr           1,2          # function addr returned in r2\n\
-    # restore registers\n\
-    aghi   15,160\n\
-    lg    14,96(15)\n\
-    lmg           2,5,64(15)\n\
-    br    1\n\
-    .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
-\n\
-    .globl _dl_runtime_profile\n\
-    .type _dl_runtime_profile, @function\n\
-    .align 16\n\
-_dl_runtime_profile:\n\
-    # save registers\n\
-    stmg   2,5,64(15)\n\
-    stg           14,96(15)\n\
-    lgr           0,15\n\
-    aghi   15,-160\n\
-    stg           0,0(15)\n\
-    # load args saved by PLT\n\
-    lmg           2,3,208(15)\n\
-    # load return address as third parameter\n\
-    lgr           4,14\n\
-    brasl  14,profile_fixup  # call fixup\n\
-    lgr           1,2          # function addr returned in r2\n\
-    # restore registers\n\
-    aghi   15,160\n\
-    lg    14,96(15)\n\
-    lmg           2,5,64(15)\n\
-    br    1\n\
-    .size _dl_runtime_profile, .-_dl_runtime_profile\n\
-");
-#else
-#define ELF_MACHINE_RUNTIME_TRAMPOLINE \
-  asm ( "\
-    .text\n\
-    .globl _dl_runtime_resolve\n\
-    .globl _dl_runtime_profile\n\
-    .type _dl_runtime_resolve, @function\n\
-    .type _dl_runtime_profile, @function\n\
-    .align 16\n\
-_dl_runtime_resolve:\n\
-_dl_runtime_profile:\n\
-    # save registers\n\
-    stmg   2,5,64(15)\n\
-    stg           14,96(15)\n\
-    lgr           0,15\n\
-    aghi   15,-160\n\
-    stg           0,0(15)\n\
-    # load args saved by PLT\n\
-    lmg           2,3,208(15)\n\
-    # load return address as third parameter\n\
-    lgr           4,14\n\
-    brasl  14,profile_fixup     # call fixup\n\
-    lgr           1,2          # function addr returned in r2\n\
-    # restore registers\n\
-    aghi   15,160\n\
-    lg    14,96(15)\n\
-    lmg           2,5,64(15)\n\
-    br    1\n\
-    .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
-    .size _dl_runtime_profile, .-_dl_runtime_profile\n\
-");
-#endif
-
 /* Initial entry point code for the dynamic linker.
    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\
@@ -235,13 +165,9 @@ _dl_start_user:\n\
        lgr   %r8,%r2\n\
        # Point %r12 at the GOT.\n\
        larl  %r12,_GLOBAL_OFFSET_TABLE_\n\
-       # Store the highest stack address\n\
-       lghi  %r1,__libc_stack_end@GOT
-       lg    %r1,0(%r1,%r12)\n\
-       stg   %r15, 0(%r1)\n\
        # See if we were run as a command with the executable file\n\
        # name as an extra leading argument.\n\
-       lghi  %r1,_dl_skip_args@GOT
+       lghi  %r1,_dl_skip_args@GOT\n\
        lg    %r1,0(%r1,%r12)\n\
        lgf   %r1,0(%r1)          # load _dl_skip_args\n\
        # Get the original argument count.\n\
@@ -262,7 +188,7 @@ _dl_start_user:\n\
        # Call the function to run the initializers.\n\
        # Load the parameters:\n\
        # (%r2, %r3, %r4, %r5) = (_dl_loaded, argc, argv, envp)\n\
-       lghi  %r2,_rtld_local@GOT
+       lghi  %r2,_rtld_local@GOT\n\
        lg    %r2,0(%r2,%r12)\n\
        lg    %r2,0(%r2)\n\
        lg    %r3,160(%r15)\n\
@@ -270,9 +196,9 @@ _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
+       lghi  %r14,_dl_fini@GOT\n\
        lg    %r14,0(%r14,%r12)\n\
        # Free stack frame\n\
        aghi  %r15,160\n\
@@ -284,12 +210,15 @@ _dl_start_user:\n\
 #define RTLD_START_SPECIAL_INIT /* nothing */
 #endif
 
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
-   PLT entries 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_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_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) * ELF_RTYPE_CLASS_PLT)  \
+  ((((type) == R_390_JMP_SLOT || (type) == R_390_TLS_DTPMOD                  \
+     || (type) == R_390_TLS_DTPOFF || (type) == R_390_TLS_TPOFF)             \
+    * ELF_RTYPE_CLASS_PLT)                                                   \
    | (((type) == R_390_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
@@ -297,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.  */
@@ -305,13 +235,14 @@ _dl_start_user:\n\
 static inline void __attribute__ ((unused))
 dl_platform_init (void)
 {
-  if (GL(dl_platform) != NULL && *GL(dl_platform) == '\0')
+  if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
     /* Avoid an empty string which would disturb us.  */
-    GL(dl_platform) = NULL;
+    GLRO(dl_platform) = NULL;
 }
 
 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)
 {
@@ -326,40 +257,120 @@ elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
   return value;
 }
 
+/* Names of the architecture-specific auditing callback functions.  */
+#define ARCH_LA_PLTENTER s390_64_gnu_pltenter
+#define ARCH_LA_PLTEXIT s390_64_gnu_pltexit
+
 #endif /* !dl_machine_h */
 
-#ifdef RESOLVE
+#ifdef RESOLVE_MAP
 
 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
    MAP is the object containing the reloc.  */
 
-static inline void
+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,
-                 Elf64_Addr *const reloc_addr)
+                 const Elf64_Sym *sym, const struct r_found_version *version,
+                 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 (__builtin_expect (r_type == R_390_RELATIVE, 0))
-    *reloc_addr = map->l_addr + reloc->r_addend;
-#ifndef RTLD_BOOTSTRAP
-  else if (__builtin_expect (r_type == R_390_NONE, 0))
-    return;
+#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
+  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;
+        make the reference weak so static programs can still link.
+        This declaration cannot be done when compiling rtld.c
+        (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
+        common defn for _dl_rtld_map, which is incompatible with a
+        weak decl in the same file.  */
+#  ifndef SHARED
+      weak_extern (GL(dl_rtld_map));
+#  endif
+      if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
+# endif
+       *reloc_addr = map->l_addr + reloc->r_addend;
+    }
+  else
 #endif
+  if (__glibc_unlikely (r_type == R_390_NONE))
+    return;
   else
     {
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
+      /* Only needed for R_390_COPY below.  */
       const Elf64_Sym *const refsym = sym;
-      Elf64_Addr value = RESOLVE (&sym, version, r_type);
-      if (sym)
-       value += sym->st_value;
+#endif
+      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+      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;
+
+#ifndef RESOLVE_CONFLICT_FIND_MAP
+       case R_390_TLS_DTPMOD:
+# ifdef RTLD_BOOTSTRAP
+         /* During startup the dynamic linker is always the module
+            with index 1.
+            XXX If this relocation is necessary move before RESOLVE
+            call.  */
+         *reloc_addr = 1;
+# else
+         /* Get the information from the link map returned by the
+            resolv function.  */
+         if (sym_map != NULL)
+           *reloc_addr = sym_map->l_tls_modid;
+# endif
+         break;
+       case R_390_TLS_DTPOFF:
+# ifndef RTLD_BOOTSTRAP
+         /* During relocation all TLS symbols are defined and used.
+            Therefore the offset is already correct.  */
+         if (sym != NULL)
+           *reloc_addr = sym->st_value + reloc->r_addend;
+# endif
+         break;
+       case R_390_TLS_TPOFF:
+         /* The offset is negative, forward from the thread pointer.  */
+# ifdef RTLD_BOOTSTRAP
+         *reloc_addr = sym->st_value + reloc->r_addend - map->l_tls_offset;
+# else
+         /* We know the offset of the object the symbol is contained in.
+            It is a negative value which will be added to the
+            thread pointer.  */
+         if (sym != NULL)
+           {
+             CHECK_STATIC_TLS (map, sym_map);
+             *reloc_addr = (sym->st_value + reloc->r_addend
+                            - sym_map->l_tls_offset);
+           }
+#endif
+         break;
+#endif  /* use TLS */
+
 #ifndef RTLD_BOOTSTRAP
+# ifndef RESOLVE_CONFLICT_FIND_MAP
+       /* Not needed for dl-conflict.c.  */
        case R_390_COPY:
          if (sym == NULL)
            /* This can happen in trace mode if an object could not be
@@ -367,19 +378,19 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
            break;
          if (__builtin_expect (sym->st_size > refsym->st_size, 0)
              || (__builtin_expect (sym->st_size < refsym->st_size, 0)
-                 && __builtin_expect (GL(dl_verbose), 0)))
+                 && __builtin_expect (GLRO(dl_verbose), 0)))
            {
              const char *strtab;
 
              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, (void *) value, MIN (sym->st_size,
-                                                  refsym->st_size));
+         memcpy (reloc_addr_arg, (void *) value,
+                 MIN (sym->st_size, refsym->st_size));
          break;
+# endif
        case R_390_64:
          *reloc_addr = value + reloc->r_addend;
          break;
@@ -392,11 +403,11 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
        case R_390_8:
          *(char *) reloc_addr = value + reloc->r_addend;
          break;
+# ifndef RESOLVE_CONFLICT_FIND_MAP
        case R_390_PC64:
          *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;
@@ -405,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,6 +425,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
          break;
        case R_390_NONE:
          break;
+# endif
 #endif
 #if !defined(RTLD_BOOTSTRAP) || defined(_NDEBUG)
        default:
@@ -427,31 +438,40 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
     }
 }
 
-static inline void
+auto inline void
+__attribute__ ((always_inline))
 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
-                          Elf64_Addr *const reloc_addr)
+                          void *const reloc_addr_arg)
 {
+  Elf64_Addr *const reloc_addr = reloc_addr_arg;
   *reloc_addr = l_addr + reloc->r_addend;
 }
 
-static inline void
+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 = ELF32_R_TYPE (reloc->r_info);
+  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);
 }
 
-#endif /* RESOLVE */
+#endif /* RESOLVE_MAP */