diff options
| -rw-r--r-- | ldso/ldso/arm/dl-sysdep.h | 37 | ||||
| -rw-r--r-- | ldso/ldso/cris/dl-sysdep.h | 46 | ||||
| -rw-r--r-- | ldso/ldso/dl-elf.c | 11 | ||||
| -rw-r--r-- | ldso/ldso/dl-startup.c | 24 | ||||
| -rw-r--r-- | ldso/ldso/i386/dl-sysdep.h | 41 | ||||
| -rw-r--r-- | ldso/ldso/m68k/dl-sysdep.h | 37 | ||||
| -rw-r--r-- | ldso/ldso/mips/dl-sysdep.h | 51 | ||||
| -rw-r--r-- | ldso/ldso/powerpc/dl-sysdep.h | 77 | ||||
| -rw-r--r-- | ldso/ldso/powerpc/elfinterp.c | 14 | ||||
| -rw-r--r-- | ldso/ldso/sh/dl-sysdep.h | 78 | ||||
| -rw-r--r-- | ldso/ldso/sh64/dl-sysdep.h | 78 | ||||
| -rw-r--r-- | ldso/ldso/sparc/dl-sysdep.h | 60 | 
12 files changed, 526 insertions, 28 deletions
| diff --git a/ldso/ldso/arm/dl-sysdep.h b/ldso/ldso/arm/dl-sysdep.h index 1c5c91ab0..773000f58 100644 --- a/ldso/ldso/arm/dl-sysdep.h +++ b/ldso/ldso/arm/dl-sysdep.h @@ -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 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);  #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); +} diff --git a/ldso/ldso/cris/dl-sysdep.h b/ldso/ldso/cris/dl-sysdep.h index ab089072f..d12644a2d 100644 --- a/ldso/ldso/cris/dl-sysdep.h +++ b/ldso/ldso/cris/dl-sysdep.h @@ -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 @@ cris_mod(unsigned long m, unsigned long p)    ((((((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); +} diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index e1cc005a0..bcf83346e 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -726,7 +726,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)  {  	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 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)  	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]) diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c index caff8d1a7..cdf9641b0 100644 --- a/ldso/ldso/dl-startup.c +++ b/ldso/ldso/dl-startup.c @@ -114,7 +114,7 @@ DL_BOOT(unsigned long args)  	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 @@ DL_BOOT(unsigned long args)  	/* 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 @@ DL_BOOT(unsigned long args)  	 * 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 @@ found_got:  	/* 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 @@ found_got:  	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; -		unsigned long rel_addr, rel_size;  		Elf32_Sym *sym; +		ELF_RELOC *rpnt; +		unsigned long rel_addr, rel_size; +		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 @@ found_got:  			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); diff --git a/ldso/ldso/i386/dl-sysdep.h b/ldso/ldso/i386/dl-sysdep.h index a534110e7..b0edee369 100644 --- a/ldso/ldso/i386/dl-sysdep.h +++ b/ldso/ldso/i386/dl-sysdep.h @@ -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 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent  #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@GOTOFF(%%ebx), %0\n" +	     "subl _dl_boot@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); +} diff --git a/ldso/ldso/m68k/dl-sysdep.h b/ldso/ldso/m68k/dl-sysdep.h index 1eff443e7..0670fd3d0 100644 --- a/ldso/ldso/m68k/dl-sysdep.h +++ b/ldso/ldso/m68k/dl-sysdep.h @@ -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 @@ extern unsigned int _dl_linux_resolver (int, int, struct elf_resolve *, int);  #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@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); +} diff --git a/ldso/ldso/mips/dl-sysdep.h b/ldso/ldso/mips/dl-sysdep.h index c3c5a6976..3f4672182 100644 --- a/ldso/ldso/mips/dl-sysdep.h +++ b/ldso/ldso/mips/dl-sysdep.h @@ -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 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy)  #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? */ +} diff --git a/ldso/ldso/powerpc/dl-sysdep.h b/ldso/ldso/powerpc/dl-sysdep.h index 6bbdb8c47..b09ada5c3 100644 --- a/ldso/ldso/powerpc/dl-sysdep.h +++ b/ldso/ldso/powerpc/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.   */ @@ -91,3 +91,78 @@ void _dl_init_got(unsigned long *lpnt,struct elf_resolve *tpnt);  /* 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@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@ha;" +	  "addi %0,%0,0b@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@local'...  */ +  asm ("bl 0f ;" +       "b _DYNAMIC@local;" +       "0:" +       : "=l"(branchaddr)); + +  /* ... and the address of the GOT.  */ +  asm (" bl _GLOBAL_OFFSET_TABLE_-4@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); +} diff --git a/ldso/ldso/powerpc/elfinterp.c b/ldso/ldso/powerpc/elfinterp.c index d3dd269fe..e156aa355 100644 --- a/ldso/ldso/powerpc/elfinterp.c +++ b/ldso/ldso/powerpc/elfinterp.c @@ -421,7 +421,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,  	  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 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,  	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; diff --git a/ldso/ldso/sh/dl-sysdep.h b/ldso/ldso/sh/dl-sysdep.h index 134e901c7..b332cc1ac 100644 --- a/ldso/ldso/sh/dl-sysdep.h +++ b/ldso/ldso/sh/dl-sysdep.h @@ -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 @@ _dl_urem(unsigned int n, unsigned int base)  #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@GOT\n\ +        3: .long _dl_boot@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 +} diff --git a/ldso/ldso/sh64/dl-sysdep.h b/ldso/ldso/sh64/dl-sysdep.h index 98a21aedb..9e35e6029 100644 --- a/ldso/ldso/sh64/dl-sysdep.h +++ b/ldso/ldso/sh64/dl-sysdep.h @@ -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 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent  #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@GOT\n\ +        3: .long _dl_boot@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 +} 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); +} | 
