(elf_machine_runtime_setup): Save original content of .got[1].
authorUlrich Drepper <drepper@redhat.com>
Wed, 12 Dec 2001 00:11:47 +0000 (00:11 +0000)
committerUlrich Drepper <drepper@redhat.com>
Wed, 12 Dec 2001 00:11:47 +0000 (00:11 +0000)
(ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP.
(ELF_MACHINE_PLT_REL): Define.
(elf_machine_rela, elf_machine_rela_relative): New.
(elf_machine_lazy_rel): Reinitialize R_ARM_JUMP_SLOT address instead
of adjusting it if prelinked and prelinking cannot be used.

sysdeps/arm/dl-machine.h

index 2d802b7..cda4247 100644 (file)
@@ -92,6 +92,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
         index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
         and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+        we have to be able to undo the prelinking of .got.plt.
+        The prelinker saved us here address of .plt.  */
+      if (got[1])
+       l->l_mach.plt = got[1] + l->l_addr;
       got[1] = (Elf32_Addr) l; /* Identify this shared object.  */
 
       /* The got[2] entry contains the address of a function which gets
@@ -334,8 +339,9 @@ _dl_start_user:
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT   R_ARM_JUMP_SLOT
 
-/* The ARM never uses Elf32_Rela relocations.  */
-#define ELF_MACHINE_NO_RELA 1
+/* ARM never uses Elf32_Rela relocations for the dynamic linker.
+   Prelinked libraries may use Elf32_Rela though.  */
+#define ELF_MACHINE_PLT_REL 1
 
 /* We define an initialization functions.  This is called very early in
    _dl_sysdep_start.  */
@@ -371,6 +377,12 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
 
 #ifdef RESOLVE
 
+/* ARM never uses Elf32_Rela relocations for the dynamic linker.
+   Prelinked libraries may use Elf32_Rela though.  */
+#ifdef RTLD_BOOTSTRAP
+#define ELF_MACHINE_NO_RELA 1
+#endif
+
 extern char **_dl_argv;
 
 /* Deal with an out-of-range PC24 reloc.  */
@@ -517,6 +529,64 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
     }
 }
 
+#ifndef RTLD_BOOTSTRAP
+static inline void
+elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+                 const Elf32_Sym *sym, const struct r_found_version *version,
+                 Elf32_Addr *const reloc_addr)
+{
+  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+
+  if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
+    *reloc_addr = map->l_addr + reloc->r_addend;
+#ifndef RTLD_BOOTSTRAP
+  else if (__builtin_expect (r_type == R_ARM_NONE, 0))
+    return;
+#endif
+  else
+    {
+      const Elf32_Sym *const refsym = sym;
+      Elf32_Addr value = RESOLVE (&sym, version, r_type);
+      if (sym)
+       value += sym->st_value;
+
+      switch (r_type)
+       {
+       case R_ARM_GLOB_DAT:
+       case R_ARM_JUMP_SLOT:
+       case R_ARM_ABS32:
+         *reloc_addr = value + reloc->r_addend;
+         break;
+       case R_ARM_PC24:
+         {
+            Elf32_Addr newvalue, topbits;
+
+            newvalue = value + reloc->r_addend - (Elf32_Addr)reloc_addr;
+            topbits = newvalue & 0xfe000000;
+            if (topbits != 0xfe000000 && topbits != 0x00000000)
+              {
+                newvalue = fix_bad_pc24(reloc_addr, value)
+                  - (Elf32_Addr)reloc_addr + (addend << 2);
+                topbits = newvalue & 0xfe000000;
+                if (topbits != 0xfe000000 && topbits != 0x00000000)
+                  {
+                    _dl_signal_error (0, map->l_name, NULL,
+                                      "R_ARM_PC24 relocation out of range");
+                  }
+              }
+            newvalue >>= 2;
+            value = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
+            *reloc_addr = value;
+         }
+         break;
+       default:
+         _dl_reloc_bad_type (map, r_type, 0);
+         break;
+       }
+    }
+}
+#endif
+
 static inline void
 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
                          Elf32_Addr *const reloc_addr)
@@ -524,6 +594,15 @@ elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
   *reloc_addr += l_addr;
 }
 
+#ifndef RTLD_BOOTSTRAP
+static inline void
+elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
+                          Elf32_Addr *const reloc_addr)
+{
+  *reloc_addr = l_addr + reloc->r_addend;
+}
+#endif
+
 static inline void
 elf_machine_lazy_rel (struct link_map *map,
                      Elf32_Addr l_addr, const Elf32_Rel *reloc)
@@ -532,7 +611,12 @@ elf_machine_lazy_rel (struct link_map *map,
   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_ARM_JUMP_SLOT, 1))
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+       *reloc_addr += l_addr;
+      else
+       *reloc_addr = map->l_mach.plt;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }