This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: Fw: Incorrect relocation info with -emit-relocs
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: Yaakov Yaari <YAARI at il dot ibm dot com>
- Cc: binutils at sources dot redhat dot com
- Date: Sat, 31 Dec 2005 22:53:41 +1030
- Subject: Re: Fw: Incorrect relocation info with -emit-relocs
- References: <OF911FEBE5.E0B6AA1D-ONC22570E6.00590FE7-C22570E6.0059300B@il.ibm.com>
On Thu, Dec 29, 2005 at 06:14:10PM +0200, Yaakov Yaari wrote:
> Hi Alan,
> The following mail was bounced back from binutils due to "552 spam score
> exceeded threshold"
Hmm, let's see if this reply makes it past the spam filters..
> ----- Forwarded by Yaakov Yaari/Haifa/IBM on 29/12/05 18:12 -----
> With GCC4.1/LD 2.16.91 20050923 for a C++ program I encountered mismatch
> between the an address stored in .ctors section and the relocation attached
> to that address.
>
> The location in the .ctors is 1007d2a0
>
> Relocation section '.rela.ctors' at offset 0xc8f20 contains 123 entries:
> Offset Info Type Symbol's Value
> Symbol's Name + Addend
> 000000001007d008 0000001e00000026 R_PPC64_ADDR64 000000001007edb8
> .opd + d8
> 000000001007d010 0000001e00000026 R_PPC64_ADDR64 000000001007edb8
> .opd + 138
> 000000001007d018 0000001e00000026 R_PPC64_ADDR64 000000001007edb8
> .opd + 210
> ....
> 000000001007d2a0 0000001e00000026 R_PPC64_ADDR64 000000001007edb8
> .opd + 5550
>
> Hex dump of section '.ctors':
> 0x1007d000 ffffffff ffffffff 00000000 1007ee90 ................
> 0x1007d010 00000000 1007eef0 00000000 1007efc8 ................
> ...
> 0x1007d2a0 00000000 100842d8 00000000 100843c8 ......B.......C.
>
> >From the relocation info, 1007d2a0 should contain 1007edb8 + 5550 =
> 10084308
> whereas the actual address there is 100842d8
>
> The symbol table for the above addresses shows:
> 1629: 00000000100842d8 56 FUNC LOCAL DEFAULT 30
> _GLOBAL__I__ZN9mrPolygonC2ERK9ggPolygon
> 3899: 0000000010084308 1500 FUNC GLOBAL DEFAULT 30
> _ZN9mrPolygonC2ERK9ggPolygon
This patch should fix the problem, and a similar serious bug with
powerpc64-linux ld -r. When editing .opd, relocs against the .opd
section symbol (such as for function pointers) did not have their
addends adjusted for any .opd deletions. When fixing this, I noticed
that some of the calculations involving branches were not keeping track
of addends properly. Not usually a problem, because the addends are
typically zero.
* elf64-ppc.c (ppc64_elf_relocate_section): Adjust relocs against
opd section sym when opd has been edited. Use correct addend
when determining branch 'y' bit and branch overflow. Adjust and
save opd relocs for ld -r too.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.228
diff -u -p -r1.228 elf64-ppc.c
--- bfd/elf64-ppc.c 13 Dec 2005 05:39:34 -0000 1.228
+++ bfd/elf64-ppc.c 31 Dec 2005 07:25:01 -0000
@@ -9550,9 +9550,6 @@ ppc64_elf_relocate_section (bfd *output_
/* Disabled until we sort out how ld should choose 'y' vs 'at'. */
bfd_boolean is_power4 = FALSE;
- if (info->relocatable)
- return TRUE;
-
/* Initialize howto table if needed. */
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
@@ -9574,7 +9571,7 @@ ppc64_elf_relocate_section (bfd *output_
for (; rel < relend; rel++)
{
enum elf_ppc64_reloc_type r_type;
- bfd_vma addend;
+ bfd_vma addend, orig_addend;
bfd_reloc_status_type r;
Elf_Internal_Sym *sym;
asection *sec;
@@ -9611,6 +9608,7 @@ ppc64_elf_relocate_section (bfd *output_
sym_name = NULL;
unresolved_reloc = FALSE;
warned = FALSE;
+ orig_addend = rel->r_addend;
if (r_symndx < symtab_hdr->sh_info)
{
@@ -9629,11 +9627,25 @@ ppc64_elf_relocate_section (bfd *output_
if (adjust == -1)
relocation = 0;
else
- relocation += adjust;
+ {
+ /* If this is a relocation against the opd section sym
+ and we have edited .opd, adjust the reloc addend so
+ that ld -r and ld --emit-relocs output is correct.
+ If it is a reloc against some other .opd symbol,
+ then the symbol value will be adjusted later. */
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ rel->r_addend += adjust;
+ else
+ relocation += adjust;
+ }
}
+ if (info->relocatable)
+ continue;
}
else
{
+ if (info->relocatable)
+ continue;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
h_elf, sec, relocation,
@@ -10126,8 +10138,9 @@ ppc64_elf_relocate_section (bfd *output_
&& get_opd_info (sec) != NULL)
{
/* The branch destination is the value of the opd entry. */
- bfd_vma off = (relocation - sec->output_section->vma
- - sec->output_offset + rel->r_addend);
+ bfd_vma off = (relocation + addend
+ - sec->output_section->vma
+ - sec->output_offset);
bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
if (dest != (bfd_vma) -1)
{
@@ -10143,7 +10156,7 @@ ppc64_elf_relocate_section (bfd *output_
+ input_section->output_section->vma);
if (stub_entry == NULL
- && (relocation + rel->r_addend - from + max_br_offset
+ && (relocation + addend - from + max_br_offset
>= 2 * max_br_offset)
&& r_type != R_PPC64_ADDR14_BRTAKEN
&& r_type != R_PPC64_ADDR14_BRNTAKEN)
@@ -10177,7 +10190,7 @@ ppc64_elf_relocate_section (bfd *output_
else
{
/* Invert 'y' bit if not the default. */
- if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
+ if ((bfd_signed_vma) (relocation + addend - from) < 0)
insn ^= 0x01 << 21;
}
@@ -10191,7 +10204,7 @@ ppc64_elf_relocate_section (bfd *output_
&& h->elf.root.type == bfd_link_hash_undefweak
&& r_type == R_PPC64_REL24
&& relocation == 0
- && rel->r_addend == 0)
+ && addend == 0)
{
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
continue;
@@ -10300,7 +10313,7 @@ ppc64_elf_relocate_section (bfd *output_
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend
+ if (ent->addend == orig_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
@@ -10335,7 +10348,7 @@ ppc64_elf_relocate_section (bfd *output_
outrel.r_offset = (got->output_section->vma
+ got->output_offset
+ off);
- outrel.r_addend = rel->r_addend;
+ outrel.r_addend = addend;
if (tls_type & (TLS_LD | TLS_GD))
{
outrel.r_addend = 0;
@@ -10348,7 +10361,7 @@ ppc64_elf_relocate_section (bfd *output_
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
outrel.r_offset += 8;
- outrel.r_addend = rel->r_addend;
+ outrel.r_addend = addend;
outrel.r_info
= ELF64_R_INFO (indx, R_PPC64_DTPREL64);
}
@@ -10386,7 +10399,7 @@ ppc64_elf_relocate_section (bfd *output_
emitting a reloc. */
else
{
- relocation += rel->r_addend;
+ relocation += addend;
if (tls_type == (TLS_TLS | TLS_LD))
relocation = 1;
else if (tls_type != 0)
@@ -10439,7 +10452,7 @@ ppc64_elf_relocate_section (bfd *output_
{
struct plt_entry *ent;
for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend
+ if (ent->addend == orig_addend
&& ent->plt.offset != (bfd_vma) -1)
{
relocation = (htab->plt->output_section->vma
@@ -10885,7 +10898,7 @@ ppc64_elf_relocate_section (bfd *output_
if (!((*info->callbacks->reloc_overflow)
(info, (h ? &h->elf.root : NULL), sym_name,
ppc64_elf_howto_table[r_type]->name,
- rel->r_addend, input_bfd, input_section, rel->r_offset)))
+ orig_addend, input_bfd, input_section, rel->r_offset)))
return FALSE;
}
else
@@ -10908,7 +10921,7 @@ ppc64_elf_relocate_section (bfd *output_
adjusted. Worse, reloc symbol indices will be for the output
file rather than the input. Save a copy of the relocs for
opd_entry_value. */
- if (is_opd && info->emitrelocations)
+ if (is_opd && (info->emitrelocations || info->relocatable))
{
bfd_size_type amt;
amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
--
Alan Modra
IBM OzLabs - Linux Technology Centre