[uClibc-cvs] svn commit: trunk/uClibc/ldso/ldso: arm cris i386 m68k mips powerpc sh sh64 etc...

jocke at uclibc.org jocke at uclibc.org
Mon Mar 14 13:25:10 UTC 2005


Author: jocke
Date: 2005-03-14 06:25:07 -0700 (Mon, 14 Mar 2005)
New Revision: 9999

Log:
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__


Modified:
   trunk/uClibc/ldso/ldso/arm/dl-sysdep.h
   trunk/uClibc/ldso/ldso/cris/dl-sysdep.h
   trunk/uClibc/ldso/ldso/dl-elf.c
   trunk/uClibc/ldso/ldso/dl-startup.c
   trunk/uClibc/ldso/ldso/i386/dl-sysdep.h
   trunk/uClibc/ldso/ldso/m68k/dl-sysdep.h
   trunk/uClibc/ldso/ldso/mips/dl-sysdep.h
   trunk/uClibc/ldso/ldso/powerpc/dl-sysdep.h
   trunk/uClibc/ldso/ldso/powerpc/elfinterp.c
   trunk/uClibc/ldso/ldso/sh/dl-sysdep.h
   trunk/uClibc/ldso/ldso/sh64/dl-sysdep.h
   trunk/uClibc/ldso/ldso/sparc/dl-sysdep.h


Changeset:
Modified: trunk/uClibc/ldso/ldso/arm/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/arm/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/arm/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -7,7 +7,7 @@
 
 /* Define this if the system uses RELOCA.  */
 #undef ELF_USES_RELOCA
-
+#include <elf.h>
 /* Initialization sequence for the GOT.  */
 #define INIT_GOT(GOT_BASE,MODULE) \
 {				\
@@ -66,3 +66,38 @@
 #define elf_machine_type_class(type) \
   ((((type) == R_ARM_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* 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 __attribute__ ((unused))
+elf_machine_dynamic (void)
+{
+	register Elf32_Addr *got asm ("r10");
+	return *got;
+}
+
+
+/* Return the run-time load address of the shared object.  */
+static inline Elf32_Addr __attribute__ ((unused))
+elf_machine_load_address (void)
+{
+	extern void __dl_boot asm ("_dl_boot");
+	Elf32_Addr got_addr = (Elf32_Addr) &__dl_boot;
+	Elf32_Addr pcrel_addr;
+	asm ("adr %0, _dl_boot" : "=r" (pcrel_addr));
+	return pcrel_addr - got_addr;
+}
+
+static inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+		      Elf32_Word relative_count)
+{
+	 Elf32_Rel * rpnt = (void *) (rel_addr + load_off);
+	--rpnt;
+	do {
+		Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
+
+		*reloc_addr = load_off;
+	} while (--relative_count);
+}

Modified: trunk/uClibc/ldso/ldso/cris/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/cris/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/cris/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -1,6 +1,6 @@
 /* CRIS can never use Elf32_Rel relocations. */
 #define ELF_USES_RELOCA
-
+#include <elf.h>
 /* Initialization sequence for the GOT.  */
 #define INIT_GOT(GOT_BASE,MODULE)				\
 {								\
@@ -75,3 +75,47 @@
   ((((((type) == R_CRIS_JUMP_SLOT))				\
      || ((type) == R_CRIS_GLOB_DAT)) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_CRIS_COPY) * ELF_RTYPE_CLASS_COPY))
+
+static inline Elf32_Addr
+elf_machine_dynamic (void)
+{
+	/* Don't just set this to an asm variable "r0" since that's not logical
+	   (like, the variable is uninitialized and the register is fixed) and
+	   may make GCC trip over itself doing register allocation.  Yes, I'm
+	   paranoid.  Why do you ask?  */
+	Elf32_Addr *got;
+	
+	__asm__ ("move.d $r0,%0" : "=rm" (got));
+	return *got;
+}
+
+/* Return the run-time load address of the shared object.  We do it like
+   m68k and i386, by taking an arbitrary local symbol, forcing a GOT entry
+   for it, and peeking into the GOT table, which is set to the link-time
+   file-relative symbol value (regardless of whether the target is REL or
+   RELA).  We subtract this link-time file-relative value from the "local"
+   value we calculate from GOT position and GOT offset.  FIXME: Perhaps
+   there's some other symbol we could use, that we don't *have* to force a
+   GOT entry for.  */
+
+static inline Elf32_Addr
+elf_machine_load_address (void)
+{
+	Elf32_Addr gotaddr_diff;
+	__asm__ ("sub.d [$r0+_dl_boot:GOT16],$r0,%0\n\t"
+		 "add.d _dl_boot:GOTOFF,%0" : "=r" (gotaddr_diff));
+	return gotaddr_diff;
+}
+
+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);
+}

Modified: trunk/uClibc/ldso/ldso/dl-elf.c
===================================================================
--- trunk/uClibc/ldso/ldso/dl-elf.c	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/dl-elf.c	2005-03-14 13:25:07 UTC (rev 9999)
@@ -726,7 +726,7 @@
 {
 	int goof = 0;
 	struct elf_resolve *tpnt;
-	unsigned long reloc_size;
+	Elf32_Word reloc_size, reloc_addr, relative_count;
 
 	if (rpnt->next)
 		goof += _dl_fixup(rpnt->next, now_flag);
@@ -757,8 +757,15 @@
 	if (tpnt->dynamic_info[DT_RELOC_TABLE_ADDR] &&
 	    !(tpnt->init_flag & RELOCS_DONE)) {
 		tpnt->init_flag |= RELOCS_DONE;
+		reloc_addr = tpnt->dynamic_info[DT_RELOC_TABLE_ADDR];
+		relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
+		if (relative_count) { /* Optimize the XX_RELATIVE relocations if possible */
+			reloc_size -= relative_count * sizeof(ELF_RELOC);
+			elf_machine_relative (tpnt->loadaddr, reloc_addr, relative_count);
+			reloc_addr += relative_count * sizeof(ELF_RELOC);
+		}
 		goof += _dl_parse_relocation_information(rpnt,
-				tpnt->dynamic_info[DT_RELOC_TABLE_ADDR],
+				reloc_addr,
 				reloc_size);
 	}
 	if (tpnt->dynamic_info[DT_BIND_NOW])

Modified: trunk/uClibc/ldso/ldso/dl-startup.c
===================================================================
--- trunk/uClibc/ldso/ldso/dl-startup.c	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/dl-startup.c	2005-03-14 13:25:07 UTC (rev 9999)
@@ -114,7 +114,7 @@
 	unsigned int argc;
 	char **argv, **envp;
 	unsigned long load_addr;
-	unsigned long *got;
+	Elf32_Addr got;
 	unsigned long *aux_dat;
 	int goof = 0;
 	ElfW(Ehdr) *header;
@@ -167,6 +167,8 @@
 
 	/* locate the ELF header.   We need this done as soon as possible
 	 * (esp since SEND_STDERR() needs this on some platforms... */
+	if (!auxvt[AT_BASE].a_un.a_val)
+		auxvt[AT_BASE].a_un.a_val = elf_machine_load_address();
 	load_addr = auxvt[AT_BASE].a_un.a_val;
 	header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
 
@@ -194,6 +196,7 @@
 	 * we can take advantage of the magic offset register, if we
 	 * happen to know what that is for this architecture.  If not,
 	 * we can always read stuff out of the ELF file to find it... */
+#if 0 /* to be deleted */
 #if defined(__i386__)
 	__asm__("\tmovl %%ebx,%0\n\t":"=a"(got));
 #elif defined(__m68k__)
@@ -270,12 +273,15 @@
 
 	/* Now, finally, fix up the location of the dynamic stuff */
 	dpnt = (Elf32_Dyn *) (*got + load_addr);
+#endif
+	got = elf_machine_dynamic();
+	dpnt = (Elf32_Dyn *) (got + load_addr);
 #ifdef __SUPPORT_LD_DEBUG_EARLY__
 	SEND_STDERR("First Dynamic section entry=");
 	SEND_ADDRESS_STDERR(dpnt, 1);
 #endif
 	_dl_memset(tpnt, 0, sizeof(struct elf_resolve));
-
+	tpnt->loadaddr = load_addr;
 	/* OK, that was easy.  Next scan the DYNAMIC section of the image.
 	   We are only doing ourself right now - we will have to do the rest later */
 #ifdef __SUPPORT_LD_DEBUG_EARLY__
@@ -342,12 +348,13 @@
 	goof = 0;
 	for (indx = 0; indx < INDX_MAX; indx++) {
 		unsigned int i;
-		ELF_RELOC *rpnt;
 		unsigned long *reloc_addr;
 		unsigned long symbol_addr;
 		int symtab_index;
+		Elf32_Sym *sym;
+		ELF_RELOC *rpnt;
 		unsigned long rel_addr, rel_size;
-		Elf32_Sym *sym;
+		Elf32_Word relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
 
 		rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
 				dynamic_info[DT_RELOC_TABLE_ADDR]);
@@ -358,6 +365,15 @@
 			continue;
 
 		/* Now parse the relocation information */
+		/* Since ldso is linked with -Bsymbolic, all relocs will be RELATIVE(for those archs that have
+		   RELATIVE relocs) which means that the for(..) loop below has noting to do and can be deleted.
+		   Possibly one should add a HAVE_RELATIVE_RELOCS directive and #ifdef away some code. */
+		if (!indx && relative_count) {
+			rel_size -= relative_count * sizeof(ELF_RELOC);
+			elf_machine_relative (load_addr, rel_addr, relative_count);
+			rel_addr += relative_count * sizeof(ELF_RELOC);;
+		}
+
 		rpnt = (ELF_RELOC *) (rel_addr + load_addr);
 		for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
 			reloc_addr = (unsigned long *) (load_addr + (unsigned long) rpnt->r_offset);

Modified: trunk/uClibc/ldso/ldso/i386/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/i386/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/i386/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -7,7 +7,7 @@
 
 /* Define this if the system uses RELOCA.  */
 #undef ELF_USES_RELOCA
-
+#include <elf.h>
 /* Initialization sequence for the GOT.  */
 #define INIT_GOT(GOT_BASE,MODULE)							\
 do {														\
@@ -40,3 +40,42 @@
 #define elf_machine_type_class(type) \
   ((((type) == R_386_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)			      \
    | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* 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 __attribute__ ((unused))
+elf_machine_dynamic (void)
+{
+	register Elf32_Addr *got asm ("%ebx");
+	return *got;
+}
+
+
+/* Return the run-time load address of the shared object.  */
+static inline Elf32_Addr __attribute__ ((unused))
+elf_machine_load_address (void)
+{
+	/* It doesn't matter what variable this is, the reference never makes
+	   it to assembly.  We need a dummy reference to some global variable
+	   via the GOT to make sure the compiler initialized %ebx in time.  */
+	extern int _dl_argc;
+	Elf32_Addr addr;
+	asm ("leal _dl_boot at GOTOFF(%%ebx), %0\n"
+	     "subl _dl_boot at GOT(%%ebx), %0"
+	     : "=r" (addr) : "m" (_dl_argc) : "cc");
+	return addr;
+}
+
+static inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+		      Elf32_Word relative_count)
+{
+	Elf32_Rel * rpnt = (void *) (rel_addr + load_off);
+	--rpnt;
+	do {
+		Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
+
+		*reloc_addr =  load_off;
+	} while (--relative_count);
+}

Modified: trunk/uClibc/ldso/ldso/m68k/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/m68k/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/m68k/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -4,7 +4,7 @@
 
 /* Define this if the system uses RELOCA.  */
 #define ELF_USES_RELOCA
-
+#include <elf.h>
 /* Initialization sequence for a GOT.  */
 #define INIT_GOT(GOT_BASE,MODULE)		\
 {						\
@@ -37,3 +37,38 @@
 #define elf_machine_type_class(type) \
   ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* 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 ("%a5");
+	return *got;
+}
+
+
+/* Return the run-time load address of the shared object.  */
+static inline Elf32_Addr
+elf_machine_load_address (void)
+{
+	Elf32_Addr addr;
+	asm ("lea _dl_boot(%%pc), %0\n\t"
+	     "sub.l _dl_boot at GOT.w(%%a5), %0"
+	     : "=a" (addr));
+	return addr;
+}
+
+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);
+}

Modified: trunk/uClibc/ldso/ldso/mips/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/mips/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/mips/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -7,7 +7,7 @@
 
 /* Define this if the system uses RELOCA.  */
 #undef ELF_USES_RELOCA
-
+#include <elf.h>
 #define ARCH_NUM 3
 #define DT_MIPS_GOTSYM_IDX	(DT_NUM + OS_NUM)
 #define DT_MIPS_LOCAL_GOTNO_IDX	(DT_NUM + OS_NUM +1)
@@ -71,3 +71,52 @@
 #define elf_machine_type_class(type)		ELF_RTYPE_CLASS_PLT
 /* MIPS does not have COPY relocs */
 #define DL_NO_COPY_RELOCS
+
+#define OFFSET_GP_GOT 0x7ff0
+
+static inline ElfW(Addr) *
+elf_mips_got_from_gpreg (ElfW(Addr) gpreg)
+{
+	/* FIXME: the offset of gp from GOT may be system-dependent. */
+	return (ElfW(Addr) *) (gpreg - OFFSET_GP_GOT);
+}
+
+/* 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.  We assume its $gp points to the primary GOT.  */
+static inline ElfW(Addr)
+elf_machine_dynamic (void)
+{
+	register ElfW(Addr) gp __asm__ ("$28");
+	return *elf_mips_got_from_gpreg (gp);
+}
+
+#define STRINGXP(X) __STRING(X)
+#define STRINGXV(X) STRINGV_(X)
+#define STRINGV_(...) # __VA_ARGS__
+#define PTR_LA               la
+#define PTR_SUBU     subu
+
+/* Return the run-time load address of the shared object.  */
+static inline ElfW(Addr)
+elf_machine_load_address (void)
+{
+	ElfW(Addr) addr;
+	asm ("        .set noreorder\n"
+	     "        " STRINGXP (PTR_LA) " %0, 0f\n"
+	     "        bltzal $0, 0f\n"
+	     "        nop\n"
+	     "0:      " STRINGXP (PTR_SUBU) " %0, $31, %0\n"
+	     "        .set reorder\n"
+	     :        "=r" (addr)
+	     :        /* No inputs */
+	     :        "$31");
+	return addr;
+}
+
+static inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+		      Elf32_Word relative_count)
+{
+	/* No REALTIVE relocs in MIPS? */
+}

Modified: trunk/uClibc/ldso/ldso/powerpc/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/powerpc/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/powerpc/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -7,7 +7,7 @@
  * Define this if the system uses RELOCA.
  */
 #define ELF_USES_RELOCA
-
+#include <elf.h>
 /*
  * Initialization sequence for a GOT.
  */
@@ -91,3 +91,78 @@
 /* The SVR4 ABI specifies that the JMPREL relocs must be inside the
    DT_RELA table.  */
 #define ELF_MACHINE_PLTREL_OVERLAP 1
+
+/* Return the link-time address of _DYNAMIC, stored as
+   the first value in the GOT. */
+static inline Elf32_Addr
+elf_machine_dynamic (void)
+{
+  Elf32_Addr *got;
+  asm (" bl _GLOBAL_OFFSET_TABLE_-4 at local"
+       : "=l"(got));
+  return *got;
+}
+
+/* Return the run-time load address of the shared object.  */
+static inline Elf32_Addr
+elf_machine_load_address (void)
+{
+  unsigned int *got;
+  unsigned int *branchaddr;
+
+  /* This is much harder than you'd expect.  Possibly I'm missing something.
+     The 'obvious' way:
+
+       Apparently, "bcl 20,31,$+4" is what should be used to load LR
+       with the address of the next instruction.
+       I think this is so that machines that do bl/blr pairing don't
+       get confused.
+
+     asm ("bcl 20,31,0f ;"
+	  "0: mflr 0 ;"
+	  "lis %0,0b at ha;"
+	  "addi %0,%0,0b at l;"
+	  "subf %0,%0,0"
+	  : "=b" (addr) : : "r0", "lr");
+
+     doesn't work, because the linker doesn't have to (and in fact doesn't)
+     update the @ha and @l references; the loader (which runs after this
+     code) will do that.
+
+     Instead, we use the following trick:
+
+     The linker puts the _link-time_ address of _DYNAMIC at the first
+     word in the GOT. We could branch to that address, if we wanted,
+     by using an @local reloc; the linker works this out, so it's safe
+     to use now. We can't, of course, actually branch there, because
+     we'd cause an illegal instruction exception; so we need to compute
+     the address ourselves. That gives us the following code: */
+
+  /* Get address of the 'b _DYNAMIC at local'...  */
+  asm ("bl 0f ;"
+       "b _DYNAMIC at local;"
+       "0:"
+       : "=l"(branchaddr));
+
+  /* ... and the address of the GOT.  */
+  asm (" bl _GLOBAL_OFFSET_TABLE_-4 at local"
+       : "=l"(got));
+
+  /* So now work out the difference between where the branch actually points,
+     and the offset of that location in memory from the start of the file.  */
+  return ((Elf32_Addr)branchaddr - *got
+	  + ((int)(*branchaddr << 6 & 0xffffff00) >> 6));
+}
+
+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 {     /* PowerPC handles pre increment/decrement better */ 
+		Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
+
+		*reloc_addr = load_off + rpnt->r_addend;
+	} while (--relative_count);
+}

Modified: trunk/uClibc/ldso/ldso/powerpc/elfinterp.c
===================================================================
--- trunk/uClibc/ldso/ldso/powerpc/elfinterp.c	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/powerpc/elfinterp.c	2005-03-14 13:25:07 UTC (rev 9999)
@@ -421,7 +421,7 @@
 	  int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
 			    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
 {
-	unsigned int i, relative_count;
+	unsigned int i;
 	char *strtab;
 	Elf32_Sym *symtab;
 	ELF_RELOC *rpnt;
@@ -434,18 +434,6 @@
 	symtab = (Elf32_Sym *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
 	strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
 	
-	relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
-	if (relative_count) { /* Optimize the  R_PPC_RELATIVE relocations if possible */
-		Elf32_Addr loadaddr = tpnt->loadaddr;
-		rel_size -= relative_count;
-		--rpnt;
-		do {     /* PowerPC handles pre increment/decrement better */ 
-			Elf32_Addr *const reloc_addr = (void *) (loadaddr + (++rpnt)->r_offset);
-
-			*reloc_addr =  loadaddr + rpnt->r_addend;
-		} while (--relative_count);
-	}
-
 	  for (i = 0; i < rel_size; i++, rpnt++) {
 	        int res;
 

Modified: trunk/uClibc/ldso/ldso/sh/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/sh/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/sh/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -5,7 +5,7 @@
 
 /* Define this if the system uses RELOCA.  */
 #define ELF_USES_RELOCA
-
+#include <elf.h>
 /*
  * Initialization sequence for a GOT.
  */
@@ -96,3 +96,79 @@
 #define elf_machine_type_class(type) \
   ((((type) == R_SH_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* 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 __attribute__ ((unused))
+elf_machine_dynamic (void)
+{
+	register Elf32_Addr *got;
+	asm ("mov r12,%0" :"=r" (got));
+	return *got;
+}
+
+/* Return the run-time load address of the shared object.  */
+static inline Elf32_Addr __attribute__ ((unused))
+elf_machine_load_address (void)
+{
+	Elf32_Addr addr;
+	asm ("mov.l 1f,r0\n\
+        mov.l 3f,r2\n\
+        add r12,r2\n\
+        mov.l @(r0,r12),r0\n\
+        bra 2f\n\
+         sub r0,r2\n\
+        .align 2\n\
+        1: .long _dl_boot at GOT\n\
+        3: .long _dl_boot at GOTOFF\n\
+        2: mov r2,%0"
+	     : "=r" (addr) : : "r0", "r1", "r2");
+	return addr;
+}
+
+#define COPY_UNALIGNED_WORD(swp, twp, align) \
+  { \
+    void *__s = (swp), *__t = (twp); \
+    unsigned char *__s1 = __s, *__t1 = __t; \
+    unsigned short *__s2 = __s, *__t2 = __t; \
+    unsigned long *__s4 = __s, *__t4 = __t; \
+    switch ((align)) \
+    { \
+    case 0: \
+      *__t4 = *__s4; \
+      break; \
+    case 2: \
+      *__t2++ = *__s2++; \
+      *__t2 = *__s2; \
+      break; \
+    default: \
+      *__t1++ = *__s1++; \
+      *__t1++ = *__s1++; \
+      *__t1++ = *__s1++; \
+      *__t1 = *__s1; \
+      break; \
+    } \
+  }
+
+static inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+		      Elf32_Word relative_count)
+{
+	Elf32_Addr value;
+	Elf32_Rela * rpnt = (void *) (rel_addr + load_off);
+
+	do {
+		Elf32_Addr *const reloc_addr = (void *) (load_off + rpnt->r_offset);
+
+		if (rpnt->r_addend)
+			value = load_off + rpnt->r_addend;
+		else {
+			COPY_UNALIGNED_WORD (reloc_addr, &value, (int) reloc_addr & 3);
+			value += load_off;
+		}
+		COPY_UNALIGNED_WORD (&value, reloc_addr, (int) reloc_addr & 3);
+		rpnt++;
+	} while (--relative_count);
+#undef COPY_UNALIGNED_WORD
+}

Modified: trunk/uClibc/ldso/ldso/sh64/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/sh64/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/sh64/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -6,7 +6,7 @@
 
 /* Define this if the system uses RELOCA.  */
 #define ELF_USES_RELOCA
-
+#include <elf.h>
 /*
  * Initialization sequence for a GOT.
  */
@@ -40,3 +40,79 @@
 #define elf_machine_type_class(type) \
   ((((type) == R_SH_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
    | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* 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 __attribute__ ((unused))
+elf_machine_dynamic (void)
+{
+	register Elf32_Addr *got;
+	asm ("mov r12,%0" :"=r" (got));
+	return *got;
+}
+
+/* Return the run-time load address of the shared object.  */
+static inline Elf32_Addr __attribute__ ((unused))
+elf_machine_load_address (void)
+{
+	Elf32_Addr addr;
+	asm ("mov.l 1f,r0\n\
+        mov.l 3f,r2\n\
+        add r12,r2\n\
+        mov.l @(r0,r12),r0\n\
+        bra 2f\n\
+         sub r0,r2\n\
+        .align 2\n\
+        1: .long _dl_boot at GOT\n\
+        3: .long _dl_boot at GOTOFF\n\
+        2: mov r2,%0"
+	     : "=r" (addr) : : "r0", "r1", "r2");
+	return addr;
+}
+
+#define COPY_UNALIGNED_WORD(swp, twp, align) \
+  { \
+    void *__s = (swp), *__t = (twp); \
+    unsigned char *__s1 = __s, *__t1 = __t; \
+    unsigned short *__s2 = __s, *__t2 = __t; \
+    unsigned long *__s4 = __s, *__t4 = __t; \
+    switch ((align)) \
+    { \
+    case 0: \
+      *__t4 = *__s4; \
+      break; \
+    case 2: \
+      *__t2++ = *__s2++; \
+      *__t2 = *__s2; \
+      break; \
+    default: \
+      *__t1++ = *__s1++; \
+      *__t1++ = *__s1++; \
+      *__t1++ = *__s1++; \
+      *__t1 = *__s1; \
+      break; \
+    } \
+  }
+
+static inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+		      Elf32_Word relative_count)
+{
+	Elf32_Addr value;
+	Elf32_Rela * rpnt = (void *) (rel_addr + load_off);
+
+	do {
+		Elf32_Addr *const reloc_addr = (void *) (load_off + rpnt->r_offset);
+
+		if (rpnt->r_addend)
+			value = load_off + rpnt->r_addend;
+		else {
+			COPY_UNALIGNED_WORD (reloc_addr, &value, (int) reloc_addr & 3);
+			value += load_off;
+		}
+		COPY_UNALIGNED_WORD (&value, reloc_addr, (int) reloc_addr & 3);
+		rpnt++;
+	} while (--relative_count);
+#undef COPY_UNALIGNED_WORD
+}

Modified: trunk/uClibc/ldso/ldso/sparc/dl-sysdep.h
===================================================================
--- trunk/uClibc/ldso/ldso/sparc/dl-sysdep.h	2005-03-14 08:48:42 UTC (rev 9998)
+++ trunk/uClibc/ldso/ldso/sparc/dl-sysdep.h	2005-03-14 13:25:07 UTC (rev 9999)
@@ -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 @@
 
 /* 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);
+}




More information about the uClibc-cvs mailing list