Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 17 Mar 2007 12:42:23 GMT
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 116023 for review
Message-ID:  <200703171242.l2HCgNVc026664@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=116023

Change 116023 by gonzo@gonzo_jeeves on 2007/03/17 12:42:06

	o Put together rtld magic both low-level and high-level. 
	Obtained from: NetBSD	

Affected files ...

.. //depot/projects/mips2/src/libexec/rtld-elf/mips/reloc.c#2 edit
.. //depot/projects/mips2/src/libexec/rtld-elf/mips/rtld_start.S#2 edit

Differences ...

==== //depot/projects/mips2/src/libexec/rtld-elf/mips/reloc.c#2 (text+ko) ====

@@ -17,56 +17,15 @@
 init_pltgot(Obj_Entry *obj)
 {       
 	if (obj->pltgot != NULL) {
-		obj->pltgot[1] = (Elf_Addr) obj;
-		obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
+		obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
+		obj->pltgot[1] |= (Elf_Addr) obj;
 	}
 }
 
 int             
 do_copy_relocations(Obj_Entry *dstobj)
 {
-	assert(NULL);
-#if 0
-	const Elf_Rel *rellim;
-	const Elf_Rel *rel;
-
-	assert(dstobj->mainprog);	/* COPY relocations are invalid elsewhere */
-
-   	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_ARM_COPY) {
-	    		void *dstaddr;
-			const Elf_Sym *dstsym;
-			const char *name;
-			unsigned long hash;
-			size_t size;
-			const void *srcaddr;
-			const Elf_Sym *srcsym;
-			Obj_Entry *srcobj;
-			const Ver_Entry *ve;
-			
-			dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
-			dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
-			name = dstobj->strtab + dstsym->st_name;
-			hash = elf_hash(name);
-			size = dstsym->st_size;
-			ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
-			
-			for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-				if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
-					break;
-			
-			if (srcobj == NULL) {
-				_rtld_error("Undefined symbol \"%s\" referenced from COPY"
-				    " relocation in %s", name, dstobj->path);
-				return -1;
-			}
-			
-			srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
-			memcpy(dstaddr, srcaddr, size);
-		}
-	}
-#endif
+	/* Do nothing */
 	return 0;			     
 }
 
@@ -75,13 +34,34 @@
 
 int open();
 int _open();
+
+static __inline Elf_Addr
+load_ptr(void *where)
+{
+	Elf_Addr res;
+
+	memcpy(&res, where, sizeof(res));
+
+	return (res);
+}
+
+void
+store_ptr(void *where, Elf_Addr val)
+{
+
+	memcpy(where, &val, sizeof(val));
+}
+
 void
 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
 {
 	const Elf_Rel *rel = 0, *rellim;
 	Elf_Addr relsz = 0;
+	const Elf_Sym *symtab = NULL, *sym;
 	Elf_Addr *where;
-	uint32_t size;
+	Elf_Addr *got = NULL;
+	Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
+	int i;
 
 	for (; dynp->d_tag != DT_NULL; dynp++) {
 		switch (dynp->d_tag) {
@@ -91,16 +71,87 @@
 		case DT_RELSZ:
 			relsz = dynp->d_un.d_val;
 			break;
+		case DT_SYMTAB:
+			symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
+			break;
+		case DT_PLTGOT:
+			got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
+			break;
+		case DT_MIPS_LOCAL_GOTNO:
+			local_gotno = dynp->d_un.d_val;
+			break;
+		case DT_MIPS_SYMTABNO:
+			symtabno = dynp->d_un.d_val;
+			break;
+		case DT_MIPS_GOTSYM:
+			gotsym = dynp->d_un.d_val;
+			break;
 		}
 	}
+
+	i = (got[1] & 0x80000000) ? 2 : 1;
+	/* Relocate the local GOT entries */
+	got += i;
+
+	for (; i < local_gotno; i++)
+		*got++ += relocbase;
+
+	sym = symtab + gotsym;
+
+	/* Now do the global GOT entries */
+	for (i = gotsym; i < symtabno; i++) {
+		*got = sym->st_value + relocbase;
+		++sym;
+		++got;
+	}
+
 	rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
-	size = (rellim - 1)->r_offset - rel->r_offset;
 	for (; rel < rellim; rel++) {
-		where = (Elf_Addr *)(relocbase + rel->r_offset);
-		
-		*where += (Elf_Addr)relocbase;
+		where = (void *)(relocbase + rel->r_offset);
+
+		switch (ELF_R_TYPE(rel->r_info)) {
+		case R_TYPE(NONE):
+			break;
+
+		case R_TYPE(REL32):
+			assert(ELF_R_SYM(rel->r_info) < gotsym);
+			sym = symtab + ELF_R_SYM(rel->r_info);
+			assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
+		if(load_ptr(where) + relocbase == 0x6008ed78) {
+			assert(where);
+		}
+			store_ptr(where, load_ptr(where) + relocbase);
+			break;
+
+		default:
+			abort();
+			break;
+		}
 	}
 }
+
+Elf_Addr
+_mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
+{
+        Elf_Addr *got = obj->pltgot;
+        const Elf_Sym *def;
+        const Obj_Entry *defobj;
+        Elf_Addr target;
+
+        def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
+        if (def == NULL)
+		_rtld_error("bind failed no symbol");
+
+        target = (Elf_Addr)(defobj->relocbase + def->st_value);
+        dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p",
+	    obj->path,
+	    reloff, defobj->strtab + def->st_name, 
+	    (void *)got[obj->local_gotno + reloff - obj->gotsym],
+	    (void *)target);
+        got[obj->local_gotno + reloff - obj->gotsym] = target;
+	return (Elf_Addr)target;
+}
+
 /*
  * It is possible for the compiler to emit relocations for unaligned data.
  * We handle this situation with these inlines.
@@ -108,122 +159,92 @@
 #define	RELOC_ALIGNED_P(x) \
 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
 
-static __inline Elf_Addr
-load_ptr(void *where)
+/*
+ * Process non-PLT relocations
+ */
+int
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
 {
-	Elf_Addr res;
+	const Elf_Rel *rel;
+	const Elf_Rel *rellim;
+	Elf_Addr *got = obj->pltgot;
+	const Elf_Sym *sym, *def;
+	const Obj_Entry *defobj;
+	int i;
 
-	memcpy(&res, where, sizeof(res));
+	/* The relocation for the dynamic loader has already been done. */
+	if (obj == obj_rtld)
+		return (0);
 
-	return (res);
-}
+	i = (got[1] & 0x80000000) ? 2 : 1;
 
-static __inline void
-store_ptr(void *where, Elf_Addr val)
-{
+	/* Relocate the local GOT entries */
+	got += i;
+	for (; i < obj->local_gotno; i++)
+		*got++ += (Elf_Addr)obj->relocbase;
+	sym = obj->symtab + obj->gotsym;
 
-	memcpy(where, &val, sizeof(val));
-}
+	/* Now do the global GOT entries */
+	for (i = obj->gotsym; i < obj->symtabno; i++) {
+		dbg(" doing got %d sym %p (%s, %x)", i - obj->gotsym, sym,
+		    sym->st_name + obj->strtab, *got);
 
-static int
-reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
-{
-	assert(NULL);
-#if 0 
-	Elf_Addr        *where;
-	const Elf_Sym   *def;
-	const Obj_Entry *defobj;
-	Elf_Addr         tmp;
-	unsigned long	 symnum;
+		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
+		    sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
+			/*
+			 * If there are non-PLT references to the function,
+			 * st_value should be 0, forcing us to resolve the
+			 * address immediately.
+			 *
+			 * XXX DANGER WILL ROBINSON!
+			 * The linker is not outputting PLT slots for calls to
+			 * functions that are defined in the same shared
+			 * library.  This is a bug, because it can screw up
+			 * link ordering rules if the symbol is defined in
+			 * more than one module.  For now, if there is a
+			 * definition, we fail the test above and force a full
+			 * symbol lookup.  This means that all intra-module
+			 * calls are bound immediately.  - mycroft, 2003/09/24
+			 */
+			*got = sym->st_value + (Elf_Addr)obj->relocbase;
+		} else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
+			/* Symbols with index SHN_ABS are not relocated. */
+			if (sym->st_shndx != SHN_ABS)
+				*got = sym->st_value +
+				    (Elf_Addr)obj->relocbase;
+		} else {
+			/* TODO: add cache here */
+			def = find_symdef(i, obj, &defobj, false, NULL);
+			if (def == NULL)
+				return -1;
+			*got = def->st_value + (Elf_Addr)defobj->relocbase;
+		}
 
-	where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
-	symnum = ELF_R_SYM(rel->r_info);
+		dbg("  --> now %x", *got);
+		++sym;
+		++got;
+	}
 
-	assert(NULL);
-	switch (ELF_R_TYPE(rel->r_info)) {
-	case R_MIPS_NONE:
-		break;
-		
-	case R_ARM_PC24: {	/* word32 S - P + A */
-		Elf32_Sword addend;
-		
-		/*
-		 * Extract addend and sign-extend if needed.
-		 */
-		addend = *where;
-		if (addend & 0x00800000)
-			addend |= 0xff000000;
-		
-		def = find_symdef(symnum, obj, &defobj, false, cache);
-		if (def == NULL)
-				return -1;
-			tmp = (Elf_Addr)obj->relocbase + def->st_value
-			    - (Elf_Addr)where + (addend << 2);
-			if ((tmp & 0xfe000000) != 0xfe000000 &&
-			    (tmp & 0xfe000000) != 0) {
-				_rtld_error(
-				"%s: R_ARM_PC24 relocation @ %p to %s failed "
-				"(displacement %ld (%#lx) out of range)",
-				    obj->path, where,
-				    obj->strtab + obj->symtab[symnum].st_name,
-				    (long) tmp, (long) tmp);
-				return -1;
-			}
-			tmp >>= 2;
-			*where = (*where & 0xff000000) | (tmp & 0x00ffffff);
-			dbg("PC24 %s in %s --> %p @ %p in %s",
-			    obj->strtab + obj->symtab[symnum].st_name,
-			    obj->path, (void *)*where, where, defobj->path);
-			break;
-		}
+	got = obj->pltgot;
+	rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
+	for (rel = obj->rel; rel < rellim; rel++) {
+		void		*where;
+		Elf_Addr	 tmp;
+		unsigned long	 symnum;
 
-		case R_ARM_ABS32:	/* word32 B + S + A */
-		case R_ARM_GLOB_DAT:	/* word32 B + S */
-			def = find_symdef(symnum, obj, &defobj, false, cache);
-			if (def == NULL)
-				return -1;
-			if (__predict_true(RELOC_ALIGNED_P(where))) {
-				tmp =  *where + (Elf_Addr)defobj->relocbase +
-				    def->st_value;
-				*where = tmp;
-			} else {
-				tmp = load_ptr(where) +
-				    (Elf_Addr)defobj->relocbase +
-				    def->st_value;
-				store_ptr(where, tmp);
-			}
-			dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
-			    obj->strtab + obj->symtab[symnum].st_name,
-			    obj->path, (void *)tmp, where, defobj->path);
-			break;
+		where = obj->relocbase + rel->r_offset;
+		symnum = ELF_R_SYM(rel->r_info);
 
-		case R_ARM_RELATIVE:	/* word32 B + A */
-			if (__predict_true(RELOC_ALIGNED_P(where))) {
-				tmp = *where + (Elf_Addr)obj->relocbase;
-				*where = tmp;
-			} else {
-				tmp = load_ptr(where) +
-				    (Elf_Addr)obj->relocbase;
-				store_ptr(where, tmp);
-			}
-			dbg("RELATIVE in %s --> %p", obj->path,
-			    (void *)tmp);
+		switch (ELF_R_TYPE(rel->r_info)) {
+		case R_TYPE(NONE):
 			break;
 
-		case R_ARM_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_COPY relocation in shared library",
-				    obj->path);
-				return -1;
-			}
-			dbg("COPY (avoid in main)");
+		case R_TYPE(REL32):
+			/* 32-bit PC-relative reference */
+			def = obj->symtab + symnum;
+			tmp = load_ptr(where);
+			tmp += (Elf_Addr)obj->relocbase;
+			store_ptr(where, tmp);
 			break;
 
 		default:
@@ -236,52 +257,16 @@
 			    "in non-PLT relocations\n",
 			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
 			return -1;
-		default:
+		}
 	}
-#endif
+
 	return 0;
 }
 
 /*
- *  * Process non-PLT relocations
- *   */
+ *  Process the PLT relocations.
+ */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
-{
-	const Elf_Rel *rellim;
-	const Elf_Rel *rel;
-	SymCache *cache;
-	int bytes = obj->nchains * sizeof(SymCache);
-	int r = -1;
-	
-	/* The relocation for the dynamic loader has already been done. */
-	if (obj == obj_rtld)
-		return (0);
-	/*
- 	 * The dynamic loader may be called from a thread, we have
-	 * limited amounts of stack available so we cannot use alloca().
-	 */
-	cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
-	if (cache == MAP_FAILED)
-		cache = NULL;
-	
-	rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
-	for (rel = obj->rel; rel < rellim; rel++) {
-		if (reloc_nonplt_object(obj, rel, cache) < 0)
-			goto done;
-	}
-	r = 0;
-done:
-	if (cache) {
-		munmap(cache, bytes);
-	}
-	return (r);
-}
-
-/*
- *  * Process the PLT relocations.
- *   */
-int
 reloc_plt(Obj_Entry *obj)
 {
 	const Elf_Rel *rellim;
@@ -291,10 +276,6 @@
 	    obj->pltrelsize);
 	for (rel = obj->pltrel;  rel < rellim;  rel++) {
 		Elf_Addr *where;
-
-		assert(NULL);
-		/* assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); */
-		
 		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
 		*where += (Elf_Addr )obj->relocbase;
 	}
@@ -303,39 +284,13 @@
 }
 
 /*
- *  * LD_BIND_NOW was set - force relocation for all jump slots
- *   */
+ * LD_BIND_NOW was set - force relocation for all jump slots
+ */
 int
 reloc_jmpslots(Obj_Entry *obj)
 {
-	assert(NULL);
-#if 0
-	const Obj_Entry *defobj;
-	const Elf_Rel *rellim;
-	const Elf_Rel *rel;
-	const Elf_Sym *def;
-	Elf_Addr *where;
-	Elf_Addr target;
-	
-	rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
-	for (rel = obj->pltrel; rel < rellim; rel++) {
-		assert(NULL);
-		assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
-		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
-		def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		    true, NULL);
-		if (def == NULL) {
-			dbg("reloc_jmpslots: sym not found");
-			return (-1);
-		}
-		
-		target = (Elf_Addr)(defobj->relocbase + def->st_value);		
-		reloc_jmpslot(where, target, defobj, obj,
-		    (const Elf_Rel *) rel);
-	}
-	
+	/* Do nothing */
 	obj->jmpslots_done = true;
-#endif
 	
 	return (0);
 }
@@ -345,14 +300,8 @@
     		const Obj_Entry *obj, const Elf_Rel *rel)
 {
 
-	assert(NULL);
-#if 0
-	assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
-
-	if (*where != target)
-		*where = target;
+	/* Do nothing */
 
-#endif
 	return target;
 }
 

==== //depot/projects/mips2/src/libexec/rtld-elf/mips/rtld_start.S#2 (text+ko) ====

@@ -34,6 +34,7 @@
 .globl _C_LABEL(_rtld)
 
 LEAF(rtld_start)
+	.abicalls
 	.set	noreorder
 
 	.cpload t9
@@ -46,50 +47,66 @@
 
 	la	a1, 1f
 	bal	1f
+	nop
+1:	subu	a1, ra, a1		# relocbase
 	la	t9,_C_LABEL(_rtld_relocate_nonplt_self)
-1:	subu	a1, ra, a1		# relocbase
 	move	s2,a1
 	la	a0,_DYNAMIC
 	addu	t9, a1, t9
 	jalr	t9
-	 addu	a0, a1, a0		# &_DYNAMIC
+	addu	a0, a1, a0		# &_DYNAMIC
+
 
-	move	a1,s2			# relocbase
-	addu	a0, sp, 4		# sp
-	jal	_C_LABEL(_rtld)		# v0 = _rtld(sp, relocbase)
-	 nop
+	addu	a0, sp, 12		# sp
+	addu	a1, sp, 4		# &exit_proc
+	addu	a2, sp, 8		# &objp
+	addu	sp, sp, -16		# arguments slot
+	jal	_C_LABEL(_rtld)		# v0 = _rtld(sp, exit_proc, objp)
+	nop
+	addu	sp, sp, 16		# 
 
-	lw	a1, 4(sp)		# our atexit function
-	lw	a2, 8(sp)		# obj_main entry
+	lw	a0, 4(sp)		# our atexit function
+	lw	a1, 8(sp)		# obj_main entry
 	addu	sp, sp,12		# readjust stack
-	move	a0,s0			# stack pointer
 	move	t9,v0
+	move	a2,s1			# restore ps_strings
 	jr	t9			# _start(sp, cleanup, obj);
-	move	a3,s1			# restore ps_strings
+	nop
 
 END(rtld_start)
 
 	.globl	_rtld_bind_start
 	.ent	_rtld_bind_start
 _rtld_bind_start:
+	# ABI conventions for stubs
+	#   t8 contains symbol index
+	#   t7 contains return address
+	.frame sp, 0, ra		# satisfy compiler
 
 	move	v1,gp			# save old GP
 	add	t9,8			# modify T9 to point at .cpload
 	.cpload	t9
 	subu	sp,44			# save arguments and sp value in stack
 	.cprestore 36
-	sw	a7,40(sp)
 	sw	a0,16(sp)
 	sw	a1,20(sp)
 	sw	a2,24(sp)
 	sw	a3,28(sp)
 	sw	s0,32(sp)
+	sw	t7,40(sp)
 	move	s0,sp
-	move	a0,t8			# symbol index
-	move	a1,a7			# old RA
-	move	a2,v1			# old GP
-	move	a3,ra			# current RA
-	jal	_C_LABEL(_rtld_bind)
+	move	a0,v1			# old GP
+	subu	a0,a0,0x7ff0		# The offset of $gp from the 
+					# beginning of the .got section:
+					# $gp = .got + 0x7ff0, so 
+					# .got = $gp - 0x7ff0
+					# Simple math as you can see.
+
+	lw	a0,4(a0)		# object = pltgot[1] & 0x7fffffff
+	and	a0,a0,0x7fffffff
+	move	a1,t8			# symbol index
+					
+	jal	_C_LABEL(_mips_rtld_bind)
 	nop
 	move	sp,s0
 	lw	ra,40(sp)



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