Subject: Re: BFD/ld lossage on MIPS with NEW_TOOLCHAIN
To: None <tech-toolchain@netbsd.org, tv@netbsd.org>
From: Rafal Boni <rafal@mediaone.net>
List: tech-toolchain
Date: 10/06/2001 23:58:13
In message <200110050132.VAA28062@doppelganger.waterside.net>, you write: 

-> In message <200110040251.WAA23590@doppelganger.waterside.net>, you write: 
-> 
-> -> Folks:
-> -> 	I seem to be tripping over a nasty ld (actually, BFD) bug on my SGI
-> -> 	(mips) box with the new toolchain.
-> [...]
-> -> 	So attached are two things:
-> -> 		(1) My patch, which is less than clean in that it still
-> -> 		    contains debug printf's strewn about, but has the gist
-> -> 		    of the proposed fix.  Line numbers may not match 100%
-> -> 		    vs. the in-tree files since I removed one or two bits
-> -> 		    of purely debugging additions by hand from the patch.
-> 
-> Though I'm not sure if this change is to blame, my build of the world on
-> sgimips with the new toolchain (with this patch) seems to have generated
-> stuffed-up crtstuff files (I think specifically crtbegin.o).
-> 
[...]
-> Along the way, I've also either confused the runtime linker or tripped
-> over a bug there that causes it to crash when faced with undefined weak
-> symbols.

With a clue from Jason, I went looking at the powerpc runtime linker, where
Charles had fixed a very similar bug -- it turns out that the MIPS runtime
linker just didn't deal real well with unresolved weak symbols.  This means
by BFD patch is (for now) exonarated -- I'm starting a complete build of
the NEW_TOOLCHAIN world on sgimips as I write this.

Attached is a patch that both works around the change in binutils behaviour
(the change to reloc.c with the big block comment) and fixes the unresolved-
weak-symbols issue (the changes in arch/mips/mips_reloc.c and symbol.c).

I'd like to commit at least the fix for the weak symbol foo soon (the other
one merits more discussion, I think), and I'm heading on the road most of 
next week, so quick feedback would be appreciated.

Thanks!
--rafal

Index: reloc.c
===================================================================
RCS file: /cvsroot/basesrc/libexec/ld.elf_so/reloc.c,v
retrieving revision 1.42
diff -b -u -r1.42 reloc.c
--- reloc.c	2001/09/10 06:09:41	1.42
+++ reloc.c	2001/10/07 03:22:47
@@ -337,9 +337,33 @@
 		if (ELFDEFNNAME(ST_BIND)(def->st_info) == STB_LOCAL &&
 		  (ELFDEFNNAME(ST_TYPE)(def->st_info) == STT_SECTION ||
 		   ELFDEFNNAME(ST_TYPE)(def->st_info) == STT_NOTYPE)) {
+			/*
+			 * XXX: ABI DIFFERENCE!
+			 * 
+			 * Old NetBSD binutils would generate shared libs
+			 * with section-relative relocations being already
+			 * adjusted for the start address of the section.
+			 * 
+			 * New binutils, OTOH, generate shared libs with
+			 * the same relocations being based at zero, so we
+			 * need to add in the start address of the section.  
+			 * 
+			 * We assume that all section-relative relocs with
+			 * contents less than the start of the section need 
+			 * to be adjusted; this should work with both old
+			 * and new shlibs.
+			 * 
+			 * --rkb, Oct 6, 2001
+			 */
+			if (def->st_info == STT_SECTION && 
+				    (*where < def->st_value))
+			    *where += (Elf_Addr) def->st_value;
+
 			*where += (Elf_Addr)obj->relocbase;
-			rdbg(dodebug, ("REL32 in %s --> %p", obj->path,
-			    (void *)*where));
+
+			rdbg(dodebug, ("REL32 %s in %s --> %p in %s",
+			    obj->strtab + def->st_name, obj->path,
+			    (void *)*where, obj->path));
 		} else {
 			/* XXX maybe do something re: bootstrapping? */
 			def = _rtld_find_symdef(_rtld_objlist, rela->r_info,
Index: symbol.c
===================================================================
RCS file: /cvsroot/basesrc/libexec/ld.elf_so/symbol.c,v
retrieving revision 1.10
diff -b -u -r1.10 symbol.c
--- symbol.c	2000/10/11 20:46:08	1.10
+++ symbol.c	2001/10/07 03:22:47
@@ -163,7 +163,7 @@
 	bool in_plt;
 {
 	Elf_Addr symnum = ELF_R_SYM(r_info);
-	const Elf_Sym  *ref = NULL;
+	const Elf_Sym  *ref;
 	const Elf_Sym  *def;
 	const Elf_Sym  *symp;
 	const Obj_Entry *obj;
@@ -171,10 +171,10 @@
 	const Objlist_Entry *elm;
 	unsigned long   hash;
 
-	if (name == NULL) {
 		ref = refobj->symtab + symnum;
+	if (name == NULL)
 		name = refobj->strtab + ref->st_name;
-	}
+
 	hash = _rtld_elf_hash(name);
 	def = NULL;
 	defobj = NULL;
@@ -227,6 +227,7 @@
 	 * symbol as having the value zero.
 	 */
 	if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) {
+		rdbg(1, ("  returning _rtld_sym_zero@_rtld_objmain"));
 		def = &_rtld_sym_zero;
 		defobj = _rtld_objmain;
 	}
Index: arch/mips/mips_reloc.c
===================================================================
RCS file: /cvsroot/basesrc/libexec/ld.elf_so/arch/mips/mips_reloc.c,v
retrieving revision 1.3
diff -b -u -r1.3 mips_reloc.c
--- arch/mips/mips_reloc.c	1999/11/07 08:01:51	1.3
+++ arch/mips/mips_reloc.c	2001/10/07 03:22:47
@@ -47,6 +47,7 @@
 	const Elf_Sym *sym = obj->symtab;
 	const Elf_Sym *def;
 	const Obj_Entry *defobj;
+	Elf_Word info;
 	int i;
 
 	i = (got[1] & 0x80000000) ? 2 : 1;
@@ -58,9 +59,21 @@
 	sym += obj->gotsym;
 	/* Now do the global GOT entries */
 	while (i--) {
-		def = _rtld_find_symdef(_rtld_objlist, 0,
-		    sym->st_name + obj->strtab, obj, &defobj, true);
-		if (def != NULL) {
+		rdbg(1, (" doing got %d sym %p (%s, %x)",  
+				obj->symtabno - obj->gotsym - i - 1, 
+				sym, sym->st_name + obj->strtab, *got));
+
+		info = ELF32_R_INFO(obj->symtabno - i - 1, sym->st_info);
+		def = _rtld_find_symdef(_rtld_objlist, info, NULL, obj, 
+					&defobj, true);
+
+		if (def == NULL)
+			_rtld_error(
+	    "%s: Undefined PLT symbol \"%s\" (reloc type = %ld, symnum = %ld)",
+			    obj->path, sym->st_name + obj->strtab,
+			    (u_long) ELF_R_TYPE(info), 
+			    (u_long) obj->symtabno - i - 1);
+
 			if (sym->st_shndx == SHN_UNDEF) {
 #if 0	/* These don't seem to work? */
 
@@ -93,7 +106,7 @@
 			} else
 				*got = def->st_value +
 				    (Elf_Word)defobj->relocbase;
-		}
+
 		++sym;
 		++got;
 	}
----
Rafal Boni                                                  rafal@mediaone.net