summaryrefslogtreecommitdiff
path: root/ldso/ldso/sparc
diff options
context:
space:
mode:
authorJoakim Tjernlund <joakim.tjernlund@transmode.se>2005-03-14 13:25:07 +0000
committerJoakim Tjernlund <joakim.tjernlund@transmode.se>2005-03-14 13:25:07 +0000
commit7d137fcf818e9a157a9f7ed9df61896f6cf97490 (patch)
tree4cd0201de5e99f8f7fc3e40ac97fe9e44411d29f /ldso/ldso/sparc
parent3b67c539e3f14a7acf59608d6f7a37b710033a5c (diff)
Generalize optimized relative reloc procesing.
Add elf_machine_dynamic() and elf_machine_load_address() for all archs. elf_machine_dynamic() replaces the #ifdef mess to get at the GOT. elf_machine_load_address() is needed to execute ldso directly, this is not complete yet. I probably broke one or two archs(only tested PPC) so please try and report problems. For a report to be useful you need to enable __SUPPORT_LD_DEBUG_EARLY__ and __SUPPORT_LD_DEBUG__
Diffstat (limited to 'ldso/ldso/sparc')
-rw-r--r--ldso/ldso/sparc/dl-sysdep.h60
1 files changed, 59 insertions, 1 deletions
diff --git a/ldso/ldso/sparc/dl-sysdep.h b/ldso/ldso/sparc/dl-sysdep.h
index d48120e2d..7559a80d2 100644
--- a/ldso/ldso/sparc/dl-sysdep.h
+++ b/ldso/ldso/sparc/dl-sysdep.h
@@ -7,7 +7,7 @@
/* Define this if the system uses RELOCA. */
#define ELF_USES_RELOCA
-
+#include <elf.h>
/*
* Initialization sequence for a GOT. For the Sparc, this points to the
* PLT, and we need to initialize a couple of the slots. The PLT should
@@ -110,3 +110,61 @@ sparc_mod(unsigned long m, unsigned long p)
/* The SPARC overlaps DT_RELA and DT_PLTREL. */
#define ELF_MACHINE_PLTREL_OVERLAP 1
+
+/* We have to do this because elf_machine_{dynamic,load_address} can be
+ invoked from functions that have no GOT references, and thus the compiler
+ has no obligation to load the PIC register. */
+#define LOAD_PIC_REG(PIC_REG) \
+do { register Elf32_Addr pc __asm("o7"); \
+ __asm("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \
+ "call 1f\n\t" \
+ "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n" \
+ "1:\tadd %1, %0, %1" \
+ : "=r" (pc), "=r" (PIC_REG)); \
+} while (0)
+
+/* Return the link-time address of _DYNAMIC. Conveniently, this is the
+ first element of the GOT. This must be inlined in a function which
+ uses global data. */
+static inline Elf32_Addr
+elf_machine_dynamic (void)
+{
+ register Elf32_Addr *got asm ("%l7");
+
+ LOAD_PIC_REG (got);
+
+ return *got;
+}
+
+/* Return the run-time load address of the shared object. */
+static inline Elf32_Addr
+elf_machine_load_address (void)
+{
+ register Elf32_Addr *pc __asm ("%o7"), *got __asm ("%l7");
+
+ __asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t"
+ "call 1f\n\t"
+ " add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t"
+ "call _DYNAMIC\n\t"
+ "call _GLOBAL_OFFSET_TABLE_\n"
+ "1:\tadd %1, %0, %1\n\t" : "=r" (pc), "=r" (got));
+
+ /* got is now l_addr + _GLOBAL_OFFSET_TABLE_
+ *got is _DYNAMIC
+ pc[2]*4 is l_addr + _DYNAMIC - (long)pc - 8
+ pc[3]*4 is l_addr + _GLOBAL_OFFSET_TABLE_ - (long)pc - 12 */
+ return (Elf32_Addr) got - *got + (pc[2] - pc[3]) * 4 - 4;
+}
+
+static inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+ Elf32_Word relative_count)
+{
+ Elf32_Rela * rpnt = (void *) (rel_addr + load_off);
+ --rpnt;
+ do {
+ Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
+
+ *reloc_addr = load_off + rpnt->r_addend;
+ } while (--relative_count);
+}