svn commit: r204211 - head/libexec/rtld-elf/powerpc

Nathan Whitehorn nwhitehorn at FreeBSD.org
Mon Feb 22 16:49:45 UTC 2010


Author: nwhitehorn
Date: Mon Feb 22 16:49:45 2010
New Revision: 204211
URL: http://svn.freebsd.org/changeset/base/204211

Log:
  Support the extended PLT format used when objects have more than 8192
  PLT relocations on PPC32.

Modified:
  head/libexec/rtld-elf/powerpc/reloc.c
  head/libexec/rtld-elf/powerpc/rtld_machdep.h
  head/libexec/rtld-elf/powerpc/rtld_start.S

Modified: head/libexec/rtld-elf/powerpc/reloc.c
==============================================================================
--- head/libexec/rtld-elf/powerpc/reloc.c	Mon Feb 22 16:27:47 2010	(r204210)
+++ head/libexec/rtld-elf/powerpc/reloc.c	Mon Feb 22 16:49:45 2010	(r204211)
@@ -47,6 +47,13 @@
                         ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
 #define _ppc_la(x) ((u_int32_t)(x) & 0xffff)
 
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+#define PLT_EXTENDED_BEGIN	(1 << 13)
+#define JMPTAB_BASE(N)		(18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \
+				    (N - PLT_EXTENDED_BEGIN)*2 : 0))
+
 /*
  * Process the R_PPC_COPY relocations
  */
@@ -313,7 +320,6 @@ done:
 	return (r);
 }
 
-
 /*
  * Initialise a PLT slot to the resolving trampoline
  */
@@ -321,27 +327,43 @@ static int
 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
 {
 	Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
-	Elf_Addr *pltresolve;
+	Elf_Addr *pltresolve, *pltlongresolve, *jmptab;
 	Elf_Addr distance;
+	int N = obj->pltrelasize / sizeof(Elf_Rela);
 	int reloff;
 
 	reloff = rela - obj->pltrela;
 
-	if ((reloff < 0) || (reloff >= 0x8000)) {
+	if (reloff < 0)
 		return (-1);
-	}
 
-	pltresolve = obj->pltgot + 8;
+	pltlongresolve = obj->pltgot + 5;
+	pltresolve = pltlongresolve + 5;
 
 	distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
 
 	dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
 	    (void *)where, (void *)pltresolve, reloff, distance);
 
-	/* li   r11,reloff  */
-	/* b    pltresolve  */
-	where[0] = 0x39600000 | reloff;
-	where[1] = 0x48000000 | (distance & 0x03fffffc);
+	if (reloff < PLT_EXTENDED_BEGIN) {
+		/* li   r11,reloff  */
+		/* b    pltresolve  */
+		where[0] = 0x39600000 | reloff;
+		where[1] = 0x48000000 | (distance & 0x03fffffc);
+	} else {
+		jmptab = obj->pltgot + JMPTAB_BASE(N);
+		jmptab[reloff] = (u_int)pltlongresolve;
+
+		/* lis	r11,jmptab[reloff]@ha */
+		/* lwzu	r12,jmptab[reloff]@l(r11) */
+		/* mtctr r12 */
+		/* bctr */
+		where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]);
+		where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]);
+		where[2] = 0x7d8903a6;
+		where[3] = 0x4e800420;
+	}
+		
 
 	/*
 	 * The icache will be sync'd in init_pltgot, which is called
@@ -453,25 +475,28 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr
 		int N = obj->pltrelasize / sizeof(Elf_Rela);
 		int reloff = rela - obj->pltrela;
 
-		if ((reloff < 0) || (reloff >= 0x8000)) {
+		if (reloff < 0)
 			return (-1);
-		}
 
 		pltcall = obj->pltgot;
 
-		dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n",
+		dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n",
 		    reloff, N);
 
-		jmptab = obj->pltgot + 18 + N * 2;
+		jmptab = obj->pltgot + JMPTAB_BASE(N);
 		jmptab[reloff] = target;
 
-		distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
+		if (reloff < PLT_EXTENDED_BEGIN) {
+			/* for extended PLT entries, we keep the old code */
+
+			distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
 
-		/* li   r11,reloff */
-		/* b    pltcall  # use indirect pltcall routine */
-		wherep[0] = 0x39600000 | reloff;
-		wherep[1] = 0x48000000 | (distance & 0x03fffffc);
-		__syncicache(wherep, 8);
+			/* li   r11,reloff */
+			/* b    pltcall  # use indirect pltcall routine */
+			wherep[0] = 0x39600000 | reloff;
+			wherep[1] = 0x48000000 | (distance & 0x03fffffc);
+			__syncicache(wherep, 8);
+		}
 	}
 
 	return (target);
@@ -481,13 +506,14 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr
 /*
  * Setup the plt glue routines.
  */
-#define PLTCALL_SIZE    20
-#define PLTRESOLVE_SIZE 24
+#define PLTCALL_SIZE	   	20
+#define PLTLONGRESOLVE_SIZE	20
+#define PLTRESOLVE_SIZE		24
 
 void
 init_pltgot(Obj_Entry *obj)
 {
-	Elf_Word *pltcall, *pltresolve;
+	Elf_Word *pltcall, *pltresolve, *pltlongresolve;
 	Elf_Word *jmptab;
 	int N = obj->pltrelasize / sizeof(Elf_Rela);
 
@@ -524,18 +550,27 @@ init_pltgot(Obj_Entry *obj)
 	 * of the jumptable into the absolute-call assembler code so it
 	 * can determine this address.
 	 */
-	jmptab = pltcall + 18 + N * 2;
+	jmptab = obj->pltgot + JMPTAB_BASE(N);
 	pltcall[1] |= _ppc_ha(jmptab);	   /* addis 11,11,jmptab at ha */
 	pltcall[2] |= _ppc_la(jmptab);     /* lwz   11,jmptab at l(11) */
 
 	/*
-	 * Skip down 32 bytes into the initial reserved area and copy
+	 * Skip down 20 bytes into the initial reserved area and copy
 	 * in the standard resolving assembler call. Into this assembler,
 	 * insert the absolute address of the _rtld_bind_start routine
 	 * and the address of the relocation object.
+	 *
+	 * We place pltlongresolve first, so it can fix up its arguments
+	 * and then fall through to the regular PLT resolver.
 	 */
-	pltresolve = obj->pltgot + 8;
+	pltlongresolve = obj->pltgot + 5;
+
+	memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve,
+	    PLTLONGRESOLVE_SIZE);
+	pltlongresolve[0] |= _ppc_ha(jmptab);	/* lis	12,jmptab at ha	*/
+	pltlongresolve[1] |= _ppc_la(jmptab);	/* addi	12,12,jmptab at l	*/
 
+	pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t);
 	memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
 	pltresolve[0] |= _ppc_ha(_rtld_bind_start);
 	pltresolve[1] |= _ppc_la(_rtld_bind_start);

Modified: head/libexec/rtld-elf/powerpc/rtld_machdep.h
==============================================================================
--- head/libexec/rtld-elf/powerpc/rtld_machdep.h	Mon Feb 22 16:27:47 2010	(r204210)
+++ head/libexec/rtld-elf/powerpc/rtld_machdep.h	Mon Feb 22 16:49:45 2010	(r204211)
@@ -57,6 +57,7 @@ void _rtld_bind_start(void);
  * PLT functions. Not really correct prototypes, but the
  * symbol values are needed.
  */
+void _rtld_powerpc_pltlongresolve(void);
 void _rtld_powerpc_pltresolve(void);
 void _rtld_powerpc_pltcall(void);
 

Modified: head/libexec/rtld-elf/powerpc/rtld_start.S
==============================================================================
--- head/libexec/rtld-elf/powerpc/rtld_start.S	Mon Feb 22 16:27:47 2010	(r204210)
+++ head/libexec/rtld-elf/powerpc/rtld_start.S	Mon Feb 22 16:49:45 2010	(r204211)
@@ -163,6 +163,12 @@ _ENTRY(_rtld_bind_start)
  * The ELF object is shifted into %r11, and _rtld_bind_start is called
  * to complete the binding.
  */
+_ENTRY(_rtld_powerpc_pltlongresolve)
+	lis	%r12,0			# lis	12,jmptab at ha
+	addi    %r12,%r12,0		# addi  12,12,jmptab at l
+	subf	%r11,%r12,%r11		# reloff
+	li	%r12,2
+	srw	%r11,%r11,%r12		# index = reloff/sizeof(Elf_Addr)
 _ENTRY(_rtld_powerpc_pltresolve)
         lis     %r12,0			# lis   12,_rtld_bind_start at ha
         addi    %r12,%r12,0		# addi  12,12,_rtld_bind_start at l


More information about the svn-src-head mailing list