]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/alpha/dl-machine.h
Update.
[thirdparty/glibc.git] / sysdeps / alpha / dl-machine.h
index a75011fccb2a8fed56dac50437ea30fe9e41c0e0..e42ed3db6811aa23637bfc0fa72826c54b4aab10 100644 (file)
@@ -1,22 +1,22 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  Alpha version.
-Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Richard Henderson <rth@tamu.edu>.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson <rth@tamu.edu>.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 /* This was written in the absence of an ABI -- don't expect
    it to remain unchanged.  */
@@ -37,13 +37,18 @@ elf_machine_matches_host (Elf64_Word e_machine)
   return e_machine == EM_ALPHA;
 }
 
-/* Return the run-time address of the _GLOBAL_OFFSET_TABLE_.
-   Must be inlined in a function which uses global data.  */
-static inline Elf64_Addr *
-elf_machine_got (void)
+/* Return the link-time address of _DYNAMIC.  The multiple-got-capable
+   linker no longer allocates the first .got entry for this.  But not to
+   worry, no special tricks are needed.  */
+static inline Elf64_Addr
+elf_machine_dynamic (void)
 {
-  register Elf64_Addr gp __asm__("$29");
-  return (Elf64_Addr *)(gp - 0x8000);
+#ifndef NO_AXP_MULTI_GOT_LD
+  return (Elf64_Addr) &_DYNAMIC;
+#else
+  register Elf64_Addr *gp __asm__ ("$29");
+  return gp[-4096];
+#endif
 }
 
 /* Return the run-time load address of the shared object.  */
@@ -81,11 +86,12 @@ elf_machine_load_address (void)
 /* Set up the loaded object described by L so its unrelocated PLT
    entries will jump to the on-demand fixup code in dl-runtime.c.  */
 
-static inline void
-elf_machine_runtime_setup (struct link_map *l, int lazy)
+static inline int
+elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 {
   Elf64_Addr plt;
   extern void _dl_runtime_resolve (void);
+  extern void _dl_runtime_profile (void);
 
   if (l->l_info[DT_JMPREL] && lazy)
     {
@@ -95,20 +101,32 @@ elf_machine_runtime_setup (struct link_map *l, int lazy)
       plt = l->l_addr + l->l_info[DT_PLTGOT]->d_un.d_ptr;
 
       /* This function will be called to perform the relocation.  */
-      *(Elf64_Addr *)(plt + 16) = (Elf64_Addr) &_dl_runtime_resolve;
+      if (!profile)
+        *(Elf64_Addr *)(plt + 16) = (Elf64_Addr) &_dl_runtime_resolve;
+      else
+       {
+         *(Elf64_Addr *)(plt + 16) = (Elf64_Addr) &_dl_runtime_profile;
+         /* Say that we really want profiling and the timers are started.  */
+         _dl_profile_map = l;
+       }
 
       /* Identify this shared object */
       *(Elf64_Addr *)(plt + 24) = (Elf64_Addr) l;
+
+      /* If the first instruction of the plt entry is not
+        "br $28, plt0", we cannot do lazy relocation.  */
+      lazy = (*(unsigned *)(plt + 32) == 0xc39ffff7);
     }
+
+  return lazy;
 }
 
 /* This code is used in dl-runtime.c to call the `fixup' function
    and then redirect to the address it returns.  */
-#define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ( \
-"/* Trampoline for _dl_runtime_resolver */
-       .globl _dl_runtime_resolve
-       .ent _dl_runtime_resolve
-_dl_runtime_resolve:
+#define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name, IMB) asm ( "\
+       .globl " #tramp_name "
+       .ent " #tramp_name "
+" #tramp_name ":
        lda     $sp, -168($sp)
        .frame  $sp, 168, $26
        /* Preserve all registers that C normally doesn't.  */
@@ -135,16 +153,20 @@ _dl_runtime_resolve:
        stq     $29, 160($sp)
        .mask   0x27ff01ff, -168
        /* Set up our $gp */
-       br      $gp, 0f
-0:     ldgp    $gp, 0($gp)
+       br      $gp, .+4
+       ldgp    $gp, 0($gp)
        .prologue 1
-       /* Set up the arguments for _dl_runtime_resolve. */
+       /* Set up the arguments for fixup: */
        /* $16 = link_map out of plt0 */
+       /* $17 = offset of reloc entry = ($28 - $27 - 20) /12 * 24 */
+       /* $18 = return address */
+       subq    $28, $27, $17
        ldq     $16, 8($27)
-       /* $17 = offset of reloc entry */
-       mov     $28, $17
+       subq    $17, 20, $17
+       mov     $26, $18
+       addq    $17, $17, $17
        /* Do the fixup */
-       bsr     $26, fixup..ng
+       bsr     $26, " ASM_ALPHA_NG_SYMBOL_PREFIX #fixup_name "..ng
        /* Move the destination address into position.  */
        mov     $0, $27
        /* Restore program registers.  */
@@ -170,14 +192,23 @@ _dl_runtime_resolve:
        ldq     $25, 152($sp)
        ldq     $29, 160($sp)
        /* Flush the Icache after having modified the .plt code.  */
-       imb
+       " #IMB "
        /* Clean up and turn control to the destination */
        lda     $sp, 168($sp)
        jmp     $31, ($27)
-       .end _dl_runtime_resolve");
-
-/* The PLT uses Elf64_Rela relocs.  */
-#define elf_machine_relplt elf_machine_rela
+       .end " #tramp_name)
+
+#ifndef PROF
+#define ELF_MACHINE_RUNTIME_TRAMPOLINE                                 \
+  TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup, imb);       \
+  TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup, #nop);
+#else
+#define ELF_MACHINE_RUNTIME_TRAMPOLINE                         \
+  TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup, imb);       \
+  extern void _dl_runtime_resolve (void);                      \
+  extern void _dl_runtime_profile (void);                      \
+  strong_alias (_dl_runtime_resolve, _dl_runtime_profile);
+#endif
 
 /* Initial entry point code for the dynamic linker.
    The C function `_dl_start' is the real entry point;
@@ -186,13 +217,17 @@ _dl_runtime_resolve:
 #define RTLD_START asm ("\
 .text
        .globl _start
-       .globl _dl_start_user
+       .ent _start
 _start:
-       br      $gp,0f
+       br      $gp, 0f
 0:     ldgp    $gp, 0($gp)
        /* Pass pointer to argument block to _dl_start.  */
        mov     $sp, $16
-       bsr     $26, _dl_start..ng
+       bsr     $26, "ASM_ALPHA_NG_SYMBOL_PREFIX"_dl_start..ng
+       .end _start
+       /* FALLTHRU */
+       .globl _dl_start_user
+       .ent _dl_start_user
 _dl_start_user:
        /* Save the user entry point address in s0.  */
        mov     $0, $9
@@ -207,7 +242,7 @@ _dl_start_user:
        stq     $2, 0($sp)
        /* Load _dl_default_scope[2] into s1 to pass to _dl_init_next.  */
 0:     ldq     $10, _dl_default_scope+16
-       /* Call _dl_init_next to return the address of an initalizer
+       /* Call _dl_init_next to return the address of an initializer
           function to run.  */
 1:     mov     $10, $16
        jsr     $26, _dl_init_next
@@ -217,45 +252,52 @@ _dl_start_user:
        jsr     $26, ($0)
        ldgp    $gp, 0($26)
        br      1b
-2:     /* Pass our finalizer function to the user in $0. */
+2:     /* Clear the startup flag.  */
+       .set at
+       stl     $31, _dl_starting_up
+       .set noat
+       /* Pass our finalizer function to the user in $0. */
        lda     $0, _dl_fini
        /* Jump to the user's entry point.  */
        mov     $9, $27
-       jmp     ($9)");
+       jmp     ($9)
+       .end _dl_start_user
+.previous");
 
 /* Nonzero iff TYPE describes relocation of a PLT entry, so
    PLT entries should not be allowed to define the value.  */
-#define elf_machine_pltrel_p(type)  ((type) == R_ALPHA_JMP_SLOT)
+#define elf_machine_lookup_noplt_p(type)  ((type) == R_ALPHA_JMP_SLOT)
 
-/* The alpha never uses Elf64_Rel relocations.  */
-#define ELF_MACHINE_NO_REL 1
+/* Nonzero iff TYPE should not be allowed to resolve to one of
+   the main executable's symbols, as for a COPY reloc, which we don't use.  */
+#define elf_machine_lookup_noexec_p(type)  (0)
 
-#endif /* !dl_machine_h */
+/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
+#define ELF_MACHINE_JMP_SLOT    R_ALPHA_JMP_SLOT
 
-#ifdef RESOLVE
+/* The alpha never uses Elf64_Rel relocations.  */
+#define ELF_MACHINE_NO_REL 1
 
 /* Fix up the instructions of a PLT entry to invoke the function
    rather than the dynamic linker.  */
 static inline void
-elf_alpha_fix_plt(struct link_map *l,
-                 const Elf64_Rela *reloc,
-                 Elf64_Addr got_addr,
-                 Elf64_Addr value)
+elf_machine_fixup_plt(struct link_map *l, const Elf64_Rela *reloc,
+                     Elf64_Addr *got_addr, Elf64_Addr value)
 {
   const Elf64_Rela *rela_plt;
   Elf64_Word *plte;
   long edisp;
 
+  /* Store the value we are going to load.  */
+  *got_addr = value;
+
   /* Recover the PLT entry address by calculating reloc's index into the
      .rela.plt, and finding that entry in the .plt.  */
-
   rela_plt = (void *)(l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr);
-
   plte = (void *)(l->l_addr + l->l_info[DT_PLTGOT]->d_un.d_ptr + 32);
   plte += 3 * (reloc - rela_plt);
 
   /* Find the displacement from the plt entry to the function.  */
-
   edisp = (long)(value - (Elf64_Addr)&plte[3]) / 4;
 
   if (edisp >= -0x100000 && edisp < 0x100000)
@@ -269,14 +311,18 @@ elf_alpha_fix_plt(struct link_map *l,
       lo = (short)hi;
       hi = (hi - lo) >> 16;
 
-      /* Emit "ldah $27,H($27)" */
-      plte[0] = 0x277b0000 | (hi & 0xffff);
-
-      /* Emit "lda $27,L($27)" */
+      /* Emit "lda $27,lo($27)" */
       plte[1] = 0x237b0000 | (lo & 0xffff);
 
       /* Emit "br $31,function" */
       plte[2] = 0xc3e00000 | (edisp & 0x1fffff);
+
+      /* Think about thread-safety -- the previous instructions must be
+        committed to memory before the first is overwritten.  */
+      __asm__ __volatile__("wmb" : : : "memory");
+
+      /* Emit "ldah $27,hi($27)" */
+      plte[0] = 0x277b0000 | (hi & 0xffff);
     }
   else
     {
@@ -285,18 +331,22 @@ elf_alpha_fix_plt(struct link_map *l,
         into the cache.  */
 
       int hi, lo;
-      hi = got_addr - (Elf64_Addr)&plte[0];
+      hi = (Elf64_Addr)got_addr - (Elf64_Addr)&plte[0];
       lo = (short)hi;
       hi = (hi - lo) >> 16;
 
-      /* Emit "ldah $27,H($27)" */
-      plte[0] = 0x277b0000 | (hi & 0xffff);
-
-      /* Emit "ldq $27,L($27)" */
+      /* Emit "ldq $27,lo($27)" */
       plte[1] = 0xa77b0000 | (lo & 0xffff);
 
       /* Emit "jmp $31,($27)" */
       plte[2] = 0x6bfb0000;
+
+      /* Think about thread-safety -- the previous instructions must be
+        committed to memory before the first is overwritten.  */
+      __asm__ __volatile__("wmb" : : : "memory");
+
+      /* Emit "ldah $27,hi($27)" */
+      plte[0] = 0x277b0000 | (hi & 0xffff);
     }
 
   /* At this point, if we've been doing runtime resolution, Icache is dirty.
@@ -305,15 +355,28 @@ elf_alpha_fix_plt(struct link_map *l,
      hasn't made it into Icache yet, so there's nothing to clean up.  */
 }
 
+/* Return the final value of a plt relocation.  */
+static inline Elf64_Addr
+elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
+                      Elf64_Addr value)
+{
+  return value + reloc->r_addend;
+}
+
+#endif /* !dl_machine_h */
+
+#ifdef RESOLVE
+
 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
    MAP is the object containing the reloc.  */
 static inline void
 elf_machine_rela (struct link_map *map,
                  const Elf64_Rela *reloc,
-                 const Elf64_Sym *sym)
+                 const Elf64_Sym *sym,
+                 const struct r_found_version *version,
+                 Elf64_Addr *const reloc_addr)
 {
-  Elf64_Addr * const reloc_addr = (void *)(map->l_addr + reloc->r_offset);
-  unsigned long const r_info = ELF64_R_TYPE (reloc->r_info);
+  unsigned long const r_type = ELF64_R_TYPE (reloc->r_info);
 
 #ifndef RTLD_BOOTSTRAP
   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
@@ -327,7 +390,7 @@ elf_machine_rela (struct link_map *map,
   /* We cannot use a switch here because we cannot locate the switch
      jump table until we've self-relocated.  */
 
-  if (r_info == R_ALPHA_RELATIVE)
+  if (r_type == R_ALPHA_RELATIVE)
     {
 #ifndef RTLD_BOOTSTRAP
       /* Already done in dynamic linker.  */
@@ -335,24 +398,21 @@ elf_machine_rela (struct link_map *map,
 #endif
        *reloc_addr += map->l_addr;
     }
-  else if (r_info == R_ALPHA_NONE)
+  else if (r_type == R_ALPHA_NONE)
     return;
   else
     {
       Elf64_Addr loadbase, sym_value;
 
-      loadbase = RESOLVE (&sym, (Elf64_Addr)reloc_addr,
-                         r_info == R_ALPHA_JMP_SLOT);
+      loadbase = RESOLVE (&sym, version, r_type);
       sym_value = sym ? loadbase + sym->st_value : 0;
+      sym_value += reloc->r_addend;
 
-      if (r_info == R_ALPHA_GLOB_DAT)
+      if (r_type == R_ALPHA_GLOB_DAT)
        *reloc_addr = sym_value;
-      else if (r_info == R_ALPHA_JMP_SLOT)
-       {
-         *reloc_addr = sym_value;
-         elf_alpha_fix_plt (map, reloc, (Elf64_Addr) reloc_addr, sym_value);
-       }
-      else if (r_info == R_ALPHA_REFQUAD)
+      else if (r_type == R_ALPHA_JMP_SLOT)
+       elf_machine_fixup_plt (map, reloc, reloc_addr, sym_value);
+      else if (r_type == R_ALPHA_REFQUAD)
        {
          sym_value += *reloc_addr;
 #ifndef RTLD_BOOTSTRAP
@@ -367,14 +427,11 @@ elf_machine_rela (struct link_map *map,
                = (void *)(map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
              sym_value -= map->l_addr;
              sym_value -= dlsymtab[ELF64_R_SYM(reloc->r_info)].st_value;
+             sym_value -= reloc->r_addend;
            }
-         else
 #endif
-           sym_value += reloc->r_addend;
          *reloc_addr = sym_value;
        }
-      else if (r_info == R_ALPHA_COPY)
-       memcpy (reloc_addr, (void *) sym_value, sym->st_size);
       else
        assert (! "unexpected dynamic reloc type");
     }
@@ -384,15 +441,15 @@ static inline void
 elf_machine_lazy_rel (struct link_map *map, const Elf64_Rela *reloc)
 {
   Elf64_Addr * const reloc_addr = (void *)(map->l_addr + reloc->r_offset);
-  unsigned long const r_info = ELF64_R_TYPE (reloc->r_info);
+  unsigned long const r_type = ELF64_R_TYPE (reloc->r_info);
 
-  if (r_info == R_ALPHA_JMP_SLOT)
+  if (r_type == R_ALPHA_JMP_SLOT)
     {
       /* Perform a RELATIVE reloc on the .got entry that transfers
         to the .plt.  */
       *reloc_addr += map->l_addr;
     }
-  else if (r_info == R_ALPHA_NONE)
+  else if (r_type == R_ALPHA_NONE)
     return;
   else
     assert (! "unexpected PLT reloc type");