Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Sep 2017 17:46:30 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r323501 - in head: libexec/rtld-elf libexec/rtld-elf/mips sys/sys
Message-ID:  <201709121746.v8CHkUdL041453@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Tue Sep 12 17:46:30 2017
New Revision: 323501
URL: https://svnweb.freebsd.org/changeset/base/323501

Log:
  Handle relocations for newer non-PIC MIPS ABI.
  
  Newer binutils supports extensions to the MIPS ABI for non-PIC code
  that is used when compiling O32 binaries with clang 5 (but not used
  for N64 oddly enough).  These extensions require support for
  R_MIPS_COPY relocations as well as a second PLT GOT using
  R_MIPS_JUMP_SLOT relocations.
  
  For R_MIPS_COPY, use the same approach as on other architectures where
  fixups are deferred to the MD do_copy_relocations.
  
  The additional PLT GOT for jump slots is located in a .got.plt section
  which is identified by a DT_MIPS_PLTGOT dynamic entry.  This GOT also
  requires fixups for the first two GOT entries just as the normal GOT.
  However, the entry point for this second GOT uses a different calling
  convention. Rather than passing an offset into the GOT, it passes an
  offset into the .rel.plt section.  This requires a second entry point
  (_rtld_pltbind_start) which calls the normal _rtld_bind() rather than
  _mips_rtld_bind().  This also means providing a real version of
  reloc_jmpslot() which is used by _rtld_bind().
  
  In addition, add real implementions of reloc_plt() and
  reloc_jmpslots() which walk .rel.plt handling R_MIPS_JUMP_SLOT
  relocations.
  
  Reviewed by:	kib
  Sponsored by:	DARPA / AFRL
  Differential Revision:	https://reviews.freebsd.org/D12326

Modified:
  head/libexec/rtld-elf/mips/reloc.c
  head/libexec/rtld-elf/mips/rtld_start.S
  head/libexec/rtld-elf/rtld.c
  head/libexec/rtld-elf/rtld.h
  head/sys/sys/elf_common.h

Modified: head/libexec/rtld-elf/mips/reloc.c
==============================================================================
--- head/libexec/rtld-elf/mips/reloc.c	Tue Sep 12 17:06:35 2017	(r323500)
+++ head/libexec/rtld-elf/mips/reloc.c	Tue Sep 12 17:46:30 2017	(r323501)
@@ -67,21 +67,98 @@ __FBSDID("$FreeBSD$");
 #define GOT1_RESERVED_FOR_RTLD(got)	((got)[1] & GOT1_MASK)
 #endif
 
+#ifdef __mips_n64
+/*
+ * ELF64 MIPS encodes the relocs uniquely.  The first 32-bits of info contain
+ * the symbol index.  The top 32-bits contain three relocation types encoded
+ * in big-endian integer with first relocation in LSB.  This means for little
+ * endian we have to byte swap that integer (r_type).
+ */
+#define	Elf_Sxword			Elf64_Sxword
+#define	ELF_R_NXTTYPE_64_P(r_type)	((((r_type) >> 8) & 0xff) == R_TYPE(64))
+#if BYTE_ORDER == LITTLE_ENDIAN
+#undef ELF_R_SYM
+#undef ELF_R_TYPE
+#define ELF_R_SYM(r_info)		((r_info) & 0xffffffff)
+#define ELF_R_TYPE(r_info)		bswap32((r_info) >> 32)
+#endif
+#else
+#define	ELF_R_NXTTYPE_64_P(r_type)	(0)
+#define	Elf_Sxword			Elf32_Sword
+#endif
+
+void _rtld_pltbind_start(void);
+
 void
 init_pltgot(Obj_Entry *obj)
 {
+
 	if (obj->pltgot != NULL) {
 		obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
 		if (GOT1_RESERVED_FOR_RTLD(obj->pltgot))
 			obj->pltgot[1] = (Elf_Addr) obj | GOT1_MASK;
 	}
+	if (obj->mips_pltgot != NULL) {
+		obj->mips_pltgot[0] = (Elf_Addr) &_rtld_pltbind_start;
+		obj->mips_pltgot[1] = (Elf_Addr) obj;
+	}
 }
 
 int
 do_copy_relocations(Obj_Entry *dstobj)
 {
-	/* Do nothing */
-	return 0;
+	const Obj_Entry *srcobj, *defobj;
+	const Elf_Rel *rellim;
+	const Elf_Rel *rel;
+	const Elf_Sym *srcsym;
+	const Elf_Sym *dstsym;
+	const void *srcaddr;
+	const char *name;
+	void *dstaddr;
+	SymLook req;
+	size_t size;
+	int res;
+
+	/*
+	 * COPY relocs are invalid outside of the main program
+	 */
+	assert(dstobj->mainprog);
+
+	rellim = (const Elf_Rel *)((caddr_t)dstobj->rel + dstobj->relsize);
+	for (rel = dstobj->rel; rel < rellim; rel++) {
+		if (ELF_R_TYPE(rel->r_info) != R_MIPS_COPY)
+			continue;
+
+		dstaddr = (void *)(dstobj->relocbase + rel->r_offset);
+		dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
+		name = dstobj->strtab + dstsym->st_name;
+		size = dstsym->st_size;
+
+		symlook_init(&req, name);
+		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
+		req.flags = SYMLOOK_EARLY;
+
+		for (srcobj = globallist_next(dstobj); srcobj != NULL;
+		     srcobj = globallist_next(srcobj)) {
+			res = symlook_obj(&req, srcobj);
+			if (res == 0) {
+				srcsym = req.sym_out;
+				defobj = req.defobj_out;
+				break;
+			}
+		}
+		if (srcobj == NULL) {
+			_rtld_error(
+"Undefined symbol \"%s\" referenced from COPY relocation in %s",
+			    name, dstobj->path);
+			return (-1);
+		}
+
+		srcaddr = (const void *)(defobj->relocbase + srcsym->st_value);
+		memcpy(dstaddr, srcaddr, size);
+	}
+
+	return (0);
 }
 
 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
@@ -90,26 +167,6 @@ void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
  * It is possible for the compiler to emit relocations for unaligned data.
  * We handle this situation with these inlines.
  */
-#ifdef __mips_n64
-/*
- * ELF64 MIPS encodes the relocs uniquely.  The first 32-bits of info contain
- * the symbol index.  The top 32-bits contain three relocation types encoded
- * in big-endian integer with first relocation in LSB.  This means for little
- * endian we have to byte swap that integer (r_type).
- */
-#define	Elf_Sxword			Elf64_Sxword
-#define	ELF_R_NXTTYPE_64_P(r_type)	((((r_type) >> 8) & 0xff) == R_TYPE(64))
-#if BYTE_ORDER == LITTLE_ENDIAN
-#undef ELF_R_SYM
-#undef ELF_R_TYPE
-#define ELF_R_SYM(r_info)		((r_info) & 0xffffffff)
-#define ELF_R_TYPE(r_info)		bswap32((r_info) >> 32)
-#endif
-#else
-#define	ELF_R_NXTTYPE_64_P(r_type)	(0)
-#define	Elf_Sxword			Elf32_Sword
-#endif
-
 static __inline Elf_Sxword
 load_ptr(void *where, size_t len)
 {
@@ -475,6 +532,20 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int
 			break;
 		}
 
+		case R_TYPE(COPY):
+			/*
+			 * These are deferred until all other relocations have
+			 * been done. All we do here is make sure that the
+			 * COPY relocation is not in a shared library. They
+			 * are allowed only in executable files.
+			 */
+			if (!obj->mainprog) {
+				_rtld_error("%s: Unexpected R_MIPS_COPY "
+				    "relocation in shared library", obj->path);
+				return (-1);
+			}
+			break;
+			
 #ifdef __mips_n64
 		case R_TYPE(TLS_DTPMOD64):
 #else
@@ -581,23 +652,25 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int
 int
 reloc_plt(Obj_Entry *obj)
 {
-#if 0
 	const Elf_Rel *rellim;
 	const Elf_Rel *rel;
-		
-	dbg("reloc_plt obj:%p pltrel:%p sz:%s", obj, obj->pltrel, (int)obj->pltrelsize);
-	dbg("gottable %p num syms:%s", obj->pltgot, obj->symtabno );
-	dbg("*****************************************************");
-	rellim = (const Elf_Rel *)((char *)obj->pltrel +
-	    obj->pltrelsize);
-	for (rel = obj->pltrel;  rel < rellim;  rel++) {
+
+	rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
+	for (rel = obj->pltrel; rel < rellim; rel++) {
 		Elf_Addr *where;
-		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
-		*where += (Elf_Addr )obj->relocbase;
+
+		switch (ELF_R_TYPE(rel->r_info)) {
+		case R_MIPS_JUMP_SLOT:
+			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+			*where += (Elf_Addr )obj->relocbase;
+			break;
+		default:
+			_rtld_error("Unknown relocation type %u in PLT",
+			    (unsigned int)ELF_R_TYPE(rel->r_info));
+			return (-1);
+		}
 	}
 
-#endif
-	/* PLT fixups were done above in the GOT relocation. */
 	return (0);
 }
 
@@ -607,9 +680,34 @@ reloc_plt(Obj_Entry *obj)
 int
 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
 {
-	/* Do nothing */
-	obj->jmpslots_done = true;
-	
+	const Obj_Entry *defobj;
+	const Elf_Rel *rellim;
+	const Elf_Rel *rel;
+	const Elf_Sym *def;
+
+	rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
+	for (rel = obj->pltrel; rel < rellim; rel++) {
+		Elf_Addr *where;
+
+		switch (ELF_R_TYPE(rel->r_info)) {
+		case R_MIPS_JUMP_SLOT:
+			def = find_symdef(ELF_R_SYM(rel->r_info), obj,
+			    &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
+			if (def == NULL) {
+				dbg("reloc_jmpslots: sym not found");
+				return (-1);
+			}
+
+			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+			*where = (Elf_Addr)(defobj->relocbase + def->st_value);
+			break;
+		default:
+			_rtld_error("Unknown relocation type %u in PLT",
+			    (unsigned int)ELF_R_TYPE(rel->r_info));
+			return (-1);
+		}
+	}
+
 	return (0);
 }
 
@@ -635,9 +733,11 @@ reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const 
     		const Obj_Entry *obj, const Elf_Rel *rel)
 {
 
-	/* Do nothing */
+	assert(ELF_R_TYPE(rel->r_info) == R_MIPS_JUMP_SLOT);
 
-	return target;
+	if (*where != target && !ld_bind_not)
+		*where = target;
+	return (target);
 }
 
 void

Modified: head/libexec/rtld-elf/mips/rtld_start.S
==============================================================================
--- head/libexec/rtld-elf/mips/rtld_start.S	Tue Sep 12 17:06:35 2017	(r323500)
+++ head/libexec/rtld-elf/mips/rtld_start.S	Tue Sep 12 17:46:30 2017	(r323501)
@@ -100,6 +100,9 @@ END(rtld_start)
 #define	XCALLFRAME_A4		(0*SZREG)
 #endif
 
+/*
+ * Trampoline for "old" PLT stubs which use .got entries.
+ */
 	.globl	_rtld_bind_start
 	.ent	_rtld_bind_start
 _rtld_bind_start:
@@ -188,3 +191,94 @@ _rtld_bind_start:
 	nop
 	.cfi_endproc
 END(_rtld_bind_start)
+
+
+/*
+ * Trampoline for PLT stubs using .pltrel entries and .got.plt.
+ */
+	.globl	_rtld_pltbind_start
+	.ent	_rtld_pltbind_start
+_rtld_pltbind_start:
+	.frame	sp, XCALLFRAME_SIZ, $15
+	.cfi_startproc simple
+	.cfi_register ra, $15
+#if defined(__mips_o32)
+	move	v1, gp			/* save pointer to .got.plt */
+#else
+	move	v1, t2			/* save pointer to .got.plt */
+#endif
+#if defined(__mips_o32) || defined(__mips_o64)
+	PTR_ADDU t9, 8			/* modify T9 to point at .cpload */
+#endif
+	SETUP_GP
+	PTR_SUBU sp, XCALLFRAME_SIZ	/* save arguments and sp value in stack */
+	.cfi_def_cfa sp, XCALLFRAME_SIZ
+	SETUP_GP64(XCALLFRAME_GP, _rtld_pltbind_start)
+	SAVE_GP(XCALLFRAME_GP)
+#if defined(__mips_n32) || defined(__mips_n64)
+	REG_S	a4,  XCALLFRAME_A4(sp)
+	.cfi_rel_offset a4, XCALLFRAME_A4
+	REG_S	a5,  XCALLFRAME_A5(sp)
+	.cfi_rel_offset a5, XCALLFRAME_A5
+	REG_S	a6,  XCALLFRAME_A6(sp)
+	.cfi_rel_offset a6, XCALLFRAME_A6
+	REG_S	a7,  XCALLFRAME_A7(sp)
+	.cfi_rel_offset a7, XCALLFRAME_A7
+#endif
+	REG_S	a0,  XCALLFRAME_A0(sp)
+	.cfi_rel_offset a0, XCALLFRAME_A0
+	REG_S	a1,  XCALLFRAME_A1(sp)
+	.cfi_rel_offset a1, XCALLFRAME_A1
+	REG_S	a2,  XCALLFRAME_A2(sp)
+	.cfi_rel_offset a2, XCALLFRAME_A2
+	REG_S	a3,  XCALLFRAME_A3(sp)
+	.cfi_rel_offset a3, XCALLFRAME_A3
+	REG_S	$15,  XCALLFRAME_RA(sp)	/* ra is in t7/t3 */
+	.cfi_rel_offset ra, XCALLFRAME_RA
+	REG_S	s0,  XCALLFRAME_S0(sp)
+	.cfi_rel_offset s0, XCALLFRAME_S0
+	move	s0, sp
+
+	move	a0, v1			/* .got.plt */
+#if defined(__mips_n64)
+	ld	a0, 8(a0)		/* object = .got.plt[1] */
+	sll	a1, t8, 4		/* PLT entry index to .rel.plt offset */
+#else
+	lw	a0, 4(a0)		/* object = .got.plt[1] */
+	sll	a1, t8, 3		/* PLT entry index to .rel.plt offset */
+#endif
+
+	PTR_LA	t9, _C_LABEL(_rtld_bind)
+	jalr	t9
+	nop
+
+	move	sp, s0
+	REG_L	ra, XCALLFRAME_RA(sp)
+	.cfi_restore ra
+	REG_L	s0, XCALLFRAME_S0(sp)
+	.cfi_restore s0
+	REG_L	a0, XCALLFRAME_A0(sp)
+	.cfi_restore a0
+	REG_L	a1, XCALLFRAME_A1(sp)
+	.cfi_restore a1
+	REG_L	a2, XCALLFRAME_A2(sp)
+	.cfi_restore a2
+	REG_L	a3, XCALLFRAME_A3(sp)
+	.cfi_restore a3
+#if defined(__mips_n32) || defined(__mips_n64)
+	REG_L	a4, XCALLFRAME_A4(sp)
+	.cfi_restore a4
+	REG_L	a5, XCALLFRAME_A5(sp)
+	.cfi_restore a5
+	REG_L	a6, XCALLFRAME_A6(sp)
+	.cfi_restore a6
+	REG_L	a7, XCALLFRAME_A7(sp)
+	.cfi_restore a7
+#endif
+	RESTORE_GP64
+	PTR_ADDU sp, XCALLFRAME_SIZ
+	move	t9, v0
+	jr	t9
+	nop
+	.cfi_endproc
+END(_rtld_pltbind_start)

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c	Tue Sep 12 17:06:35 2017	(r323500)
+++ head/libexec/rtld-elf/rtld.c	Tue Sep 12 17:46:30 2017	(r323501)
@@ -1257,6 +1257,12 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_D
 	case DT_MIPS_RLD_MAP:
 		*((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr) &r_debug;
 		break;
+
+	case DT_MIPS_PLTGOT:
+		obj->mips_pltgot = (Elf_Addr *) (obj->relocbase +
+		    dynp->d_un.d_ptr);
+		break;
+		
 #endif
 
 #ifdef __powerpc64__

Modified: head/libexec/rtld-elf/rtld.h
==============================================================================
--- head/libexec/rtld-elf/rtld.h	Tue Sep 12 17:06:35 2017	(r323500)
+++ head/libexec/rtld-elf/rtld.h	Tue Sep 12 17:46:30 2017	(r323501)
@@ -187,6 +187,7 @@ typedef struct Struct_Obj_Entry {
     Elf_Word local_gotno;	/* Number of local GOT entries */
     Elf_Word symtabno;		/* Number of dynamic symbols */
     Elf_Word gotsym;		/* First dynamic symbol in GOT */
+    Elf_Addr *mips_pltgot;	/* Second PLT GOT */
 #endif
 #ifdef __powerpc64__
     Elf_Addr glink;		/* GLINK PLT call stub section */

Modified: head/sys/sys/elf_common.h
==============================================================================
--- head/sys/sys/elf_common.h	Tue Sep 12 17:06:35 2017	(r323500)
+++ head/sys/sys/elf_common.h	Tue Sep 12 17:46:30 2017	(r323501)
@@ -1059,6 +1059,8 @@ typedef struct {
 #define	R_MIPS_CALLLO16 31	/* lower 16 bit GOT entry for function */
 #define	R_MIPS_JALR	37
 #define	R_MIPS_TLS_GD	42
+#define	R_MIPS_COPY	126
+#define	R_MIPS_JUMP_SLOT	127
 
 #define	R_PPC_NONE		0	/* No relocation. */
 #define	R_PPC_ADDR32		1



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709121746.v8CHkUdL041453>