This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix objdump output of R_SPARC_OLO10


This bug in relocation reporting on sparc has bitten me at least
twice, and just recently has sent several folks on a wild goose chase
again.

R_SPARC_OLO10 relocations exist only on 64-bit sparc, and use the
extra bits in the R_INFO field of the relocation to store a second,
constant, 24-bit signed addend.

BFD internally does not have enough space to store two addends in
it's 'arelent' structure.

Therefore, the 64-bit ELF Sparc backend transforms every R_SPARC_OLO10
relocation into a sequence of two BFD internal relocs:

	R_SPARC_LO10
	R_SPARC_13

both pointing at the same address.

The primary addend of the R_SPARC_OLO10 relocation is stored in the
R_SPARC_LO10 reloc, and the second addend is stored in the R_SPARC_13
reloc.

This internal transformed form is therefore what 'objdump' ends up
reporting.  Being a full mis-representation of what's actually in the
binary, it will confuse and has confused developers trying to use
objdump to analyze binaries.

'readelf' handles it properly, by way of not using BFD along with some
sparc specific tests.

On the one hand the fix I'm proposing here is a bit of a hack, but on
the other hand it's the best thing I've been able to come up with and
this bug has wasted developer time unnecessarily.

Any better ideas?

binutils/

2011-01-18  David S. Miller  <davem@sunset.davemloft.net>

	* objdump.c (dump_reloc_set): Output R_SPARC_OLO10 relocations
	accurately, rather than how they are represented internally.

diff --git a/binutils/objdump.c b/binutils/objdump.c
index 0be662f..99d1279 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -2829,6 +2829,7 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount)
       unsigned int linenumber;
       const char *sym_name;
       const char *section_name;
+      bfd_vma addend2 = 0;
 
       if (start_address != (bfd_vma) -1
 	  && q->address < start_address)
@@ -2884,7 +2885,34 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount)
       if (q->howto == NULL)
 	printf (" *unknown*         ");
       else if (q->howto->name)
-	printf (" %-16s  ", q->howto->name);
+	{
+	  const char *name = q->howto->name;
+
+	  /* R_SPARC_OLO10 relocations contain two addends.
+	     But because 'arelent' lacks enough storage to
+	     store them both, the 64-bit ELF Sparc backend
+	     records this as two relocations.  One R_SPARC_LO10
+	     and one R_SPARC_13, both pointing to the same
+	     address.  This is merely so that we have some
+	     place to store both addend fields.
+
+	     Undo this transformation, otherwise the output
+	     will be confusing.  */
+	  if (relcount
+	      && !strcmp (q->howto->name, "R_SPARC_LO10"))
+	    {
+	      arelent *q2 = *(p + 1);
+	      if (q2->howto
+		  && q->address == q2->address
+		  && !strcmp (q2->howto->name, "R_SPARC_13"))
+		{
+		  name = "R_SPARC_OLO10";
+		  addend2 = q2->addend;
+		  p++;
+		}
+	    }
+	  printf (" %-16s  ", name);
+	}
       else
 	printf (" %-16d  ", q->howto->type);
 
@@ -2904,6 +2932,11 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount)
 	  printf ("+0x");
 	  bfd_printf_vma (abfd, q->addend);
 	}
+      if (addend2)
+	{
+	  printf ("+0x");
+	  bfd_printf_vma (abfd, addend2);
+	}
 
       printf ("\n");
     }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]