aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/arm
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/arm')
-rw-r--r--sysdeps/arm/bits/link.h4
-rw-r--r--sysdeps/arm/dl-machine.h90
2 files changed, 91 insertions, 3 deletions
diff --git a/sysdeps/arm/bits/link.h b/sysdeps/arm/bits/link.h
new file mode 100644
index 0000000000..648976d7d2
--- /dev/null
+++ b/sysdeps/arm/bits/link.h
@@ -0,0 +1,4 @@
+struct link_map_machine
+ {
+ Elf32_Addr plt; /* Address of .plt */
+ };
diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
index 2d802b7e9b..cda424757b 100644
--- a/sysdeps/arm/dl-machine.h
+++ b/sysdeps/arm/dl-machine.h
@@ -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);
}