[PATCH] Fix objdump output of R_SPARC_OLO10

H.J. Lu hjl.tools@gmail.com
Wed Jan 19 04:57:00 GMT 2011


On Tue, Jan 18, 2011 at 8:51 PM, David Miller <davem@davemloft.net> wrote:
>
> 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");
>     }
>

Are you checking R_SPARC_LO10 even on x86 input?


-- 
H.J.



More information about the Binutils mailing list