Subject: BFD/ld lossage on MIPS with NEW_TOOLCHAIN
To: None <>
From: Rafal Boni <>
List: tech-toolchain
Date: 10/03/2001 22:51:19
	I seem to be tripping over a nasty ld (actually, BFD) bug on my SGI
	(mips) box with the new toolchain.

	The short of the story is that ld generates seemingly incorrect MIPS
	REL32 relocations for local symbols in shared libraries.  Using a 
	small example, take the following snippet of assembly:

        .globl  ptr
ptr:    .word   other_func

	instead of emitting (address of other_func), the new ld emits sth.
	like 0x90 instead.  When the run-time linker gets this symbol to 
	relocate, it ends up relocating it to somewhere in timbuktoo as it
	expected it to be an address based at the load address of the shared
	object, not based at zero.

	This had been hashed out on the binutils list a while back, and even
	fixed as well, but later changes either undid or broke the fix (I'm 
	not sure if the intent was to undo the fix or not).  Looks like a 
	fix was applied in rev 1.78 -> 1.79 of elf32-mips.c in the bintuils
	cvs, but was then undone in changes from rev. 1.87 -> 1.88, which
	where later pulled up to the binutils 2.11 branch.

	See for
	some background.

	It turns out the behaviour on NetBSD is slightly different than Ralf
	Baechle details in his post referenced above: the old (binutils 2.9.1
	based) actually generates the expected relocations; the new binutils
	2.11.2 based one does not.

	I've got a candidate fix, but being a GNU toolchain newbie, thought
	I'd pass it by folks here... I'll also send this off to the binutils
	folks assuming I can make it happen with a cleanly-configured set of
	binutils sources without any of the NetBSD make machinery (I'd like
	to make sure none of that needs to be considered before sending off
	a bug report to them).

	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.

		(2) A slightly modified test case (stolen from Ralf's post,
		    modified to build on NetBSD and with added output from
		    both the new and old toolchains).  I've uuencoded the
		    tar.gz file for ease of transmission, since it's quite

		    In the tarball, there are new-toolchain.out and old-
		    toolchain.out files, which correspond to the 2.11.2
		    based bintuils and the old 2.9.1 based binutils.

	I'd appreciate any feedback on this, as well as testing on mipsel,
	if anyone could do that (I only have BE systems available).


Index: elf32-mips.c
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/bfd/elf32-mips.c,v
retrieving revision 1.4
diff -u -r1.4 elf32-mips.c
--- elf32-mips.c	2001/08/14 04:43:06	1.4
+++ elf32-mips.c	2001/10/04 01:49:12
@@ -199,7 +199,7 @@
 static boolean mips_elf_create_dynamic_relocation
   PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
 	   struct mips_elf_link_hash_entry *, asection *,
-	   bfd_vma, bfd_vma *, asection *));
+	   bfd_vma, bfd_vma *, asection *, boolean));
 static void mips_elf_allocate_dynamic_relocations
   PARAMS ((bfd *, unsigned int));
 static boolean mips_elf_stub_section_p
@@ -5790,7 +5790,8 @@
 static boolean
 mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
-				    symbol, addendp, input_section)
+				    symbol, addendp, input_section,
+				    local_p)
      bfd *output_bfd;
      struct bfd_link_info *info;
      const Elf_Internal_Rela *rel;
@@ -5799,6 +5800,7 @@
      bfd_vma symbol;
      bfd_vma *addendp;
      asection *input_section;
+     boolean local_p;
   Elf_Internal_Rel outrel;
   boolean skip;
@@ -5886,14 +5888,23 @@
 	  *addendp += section_offset;
 	  /* Now, the relocation is just against the section.  */
 	  symbol = sec->output_section->vma;
+	  if (indx && local_p) {
+	      printf("mips_elf_create_dynamic_relocation(1): old type %d, "
+		     "adjusting addend %x by %x\n", r_type, *addendp, symbol);
+	      *addendp += symbol;
+	  }
       /* If the relocation was previously an absolute relocation and
 	 this symbol will not be referred to by the relocation, we must
 	 adjust it by the value we give it in the dynamic symbol table.
 	 Otherwise leave the job up to the dynamic linker.  */
-      if (!indx && r_type != R_MIPS_REL32)
+      if (!indx && r_type != R_MIPS_REL32) {
+        printf("mips_elf_create_dynamic_relocation(2): old type %d, adjusting "
+	       "addend %x by %x\n", r_type, *addendp, symbol);
 	*addendp += symbol;
+      }
       /* The relocation is always an REL32 relocation because we don't
 	 know where the shared library will wind up at load-time.  */
@@ -6330,7 +6351,8 @@
-						   input_section))
+						   input_section,
+						   local_p))
 	    return false;

begin 640 nuke-ld-13.tar.gz

Rafal Boni