*** ../binutils-2.21.53.0.1.orig/bfd/elf64-ppc.c 2011-08-05 12:43:25.596878997 +0100
--- bfd/elf64-ppc.c 2011-08-05 12:44:58.485878988 +0100
***************
*** 34,39 ****
--- 34,40 ----
#include "elf-bfd.h"
#include "elf/ppc64.h"
#include "elf64-ppc.h"
+ #include "dwarf2.h"
static bfd_reloc_status_type ppc64_elf_ha_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
*************** struct ppc_link_hash_table
*** 3720,3725 ****
--- 3721,3727 ----
asection *sfpr;
asection *brlt;
asection *relbrlt;
+ asection *glink_eh_frame;
/* Shortcut to .__tls_get_addr and __tls_get_addr. */
struct ppc_link_hash_entry *tls_get_addr;
*************** create_linkage_sections (bfd *dynobj, st
*** 4170,4175 ****
--- 4172,4189 ----
|| ! bfd_set_section_alignment (dynobj, htab->glink, 3))
return FALSE;
+ if (!info->no_ld_generated_unwind_info)
+ {
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
+ ".eh_frame",
+ flags);
+ if (htab->glink_eh_frame == NULL
+ || !bfd_set_section_alignment (abfd, htab->glink_eh_frame, 2))
+ return FALSE;
+ }
+
flags = SEC_ALLOC | SEC_LINKER_CREATED;
htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
if (htab->iplt == NULL
*************** ppc64_elf_size_dynamic_sections (bfd *ou
*** 9025,9030 ****
--- 9039,9050 ----
/* Strip this section if we don't need it; see the
comment below. */
}
+ else if (s == htab->glink_eh_frame)
+ {
+ if (!bfd_is_abs_section (s->output_section))
+ /* Not sized yet. */
+ continue;
+ }
else if (CONST_STRNEQ (s->name, ".rela"))
{
if (s->size != 0)
*************** build_plt_stub (bfd *obfd, bfd_byte *p,
*** 9271,9277 ****
r[1].r_offset = r[0].r_offset + 8;
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
r[1].r_addend = r[0].r_addend;
! if (PPC_HA (offset + 16) != PPC_HA (offset))
{
r[2].r_offset = r[1].r_offset + 4;
r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
--- 9291,9297 ----
r[1].r_offset = r[0].r_offset + 8;
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
r[1].r_addend = r[0].r_addend;
! if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
{
r[2].r_offset = r[1].r_offset + 4;
r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
*************** build_plt_stub (bfd *obfd, bfd_byte *p,
*** 9282,9290 ****
r[2].r_offset = r[1].r_offset + 8;
r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
r[2].r_addend = r[0].r_addend + 8;
! r[3].r_offset = r[2].r_offset + 4;
! r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
! r[3].r_addend = r[0].r_addend + 16;
}
}
bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4;
--- 9302,9313 ----
r[2].r_offset = r[1].r_offset + 8;
r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
r[2].r_addend = r[0].r_addend + 8;
! if (plt_static_chain)
! {
! r[3].r_offset = r[2].r_offset + 4;
! r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
! r[3].r_addend = r[0].r_addend + 16;
! }
}
}
bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4;
*************** build_plt_stub (bfd *obfd, bfd_byte *p,
*** 9307,9313 ****
{
r[0].r_offset += 4;
r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! if (PPC_HA (offset + 16) != PPC_HA (offset))
{
r[1].r_offset = r[0].r_offset + 4;
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
--- 9330,9336 ----
{
r[0].r_offset += 4;
r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
{
r[1].r_offset = r[0].r_offset + 4;
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
*************** build_plt_stub (bfd *obfd, bfd_byte *p,
*** 9317,9326 ****
{
r[1].r_offset = r[0].r_offset + 8;
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! r[1].r_addend = r[0].r_addend + 16;
! r[2].r_offset = r[1].r_offset + 4;
! r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! r[2].r_addend = r[0].r_addend + 8;
}
}
bfd_put_32 (obfd, STD_R2_40R1, p), p += 4;
--- 9340,9352 ----
{
r[1].r_offset = r[0].r_offset + 8;
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
! if (plt_static_chain)
! {
! r[2].r_offset = r[1].r_offset + 4;
! r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
! r[2].r_addend = r[0].r_addend + 8;
! }
}
}
bfd_put_32 (obfd, STD_R2_40R1, p), p += 4;
*************** ppc_build_one_stub (struct bfd_hash_entr
*** 9788,9795 ****
if (info->emitrelocations)
{
r = get_relocs (stub_entry->stub_sec,
! (2 + (PPC_HA (off) != 0)
! + (PPC_HA (off + 16) == PPC_HA (off))));
if (r == NULL)
return FALSE;
r[0].r_offset = loc - stub_entry->stub_sec->contents;
--- 9814,9823 ----
if (info->emitrelocations)
{
r = get_relocs (stub_entry->stub_sec,
! (2
! + (PPC_HA (off) != 0)
! + (htab->plt_static_chain
! && PPC_HA (off + 16) == PPC_HA (off))));
if (r == NULL)
return FALSE;
r[0].r_offset = loc - stub_entry->stub_sec->contents;
*************** ppc_size_one_stub (struct bfd_hash_entry
*** 9896,9902 ****
size -= 4;
if (PPC_HA (off) == 0)
size -= 4;
! if (PPC_HA (off + 16) != PPC_HA (off))
size += 4;
if (stub_entry->h != NULL
&& (stub_entry->h == htab->tls_get_addr_fd
--- 9924,9930 ----
size -= 4;
if (PPC_HA (off) == 0)
size -= 4;
! if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
size += 4;
if (stub_entry->h != NULL
&& (stub_entry->h == htab->tls_get_addr_fd
*************** ppc_size_one_stub (struct bfd_hash_entry
*** 9906,9912 ****
if (info->emitrelocations)
{
stub_entry->stub_sec->reloc_count
! += 2 + (PPC_HA (off) != 0) + (PPC_HA (off + 16) == PPC_HA (off));
stub_entry->stub_sec->flags |= SEC_RELOC;
}
}
--- 9934,9943 ----
if (info->emitrelocations)
{
stub_entry->stub_sec->reloc_count
! += (2
! + (PPC_HA (off) != 0)
! + (htab->plt_static_chain
! && PPC_HA (off + 16) == PPC_HA (off)));
stub_entry->stub_sec->flags |= SEC_RELOC;
}
}
*************** group_sections (struct ppc_link_hash_tab
*** 10826,10831 ****
--- 10857,10896 ----
#undef PREV_SEC
}
+ static const unsigned char glink_eh_frame_cie[] =
+ {
+ 0, 0, 0, 16, /* length. */
+ 0, 0, 0, 0, /* id. */
+ 1, /* CIE version. */
+ 'z', 'R', 0, /* Augmentation string. */
+ 4, /* Code alignment. */
+ 0x78, /* Data alignment. */
+ 65, /* RA reg. */
+ 1, /* Augmentation size. */
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */
+ DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */
+ };
+
+ /* Stripping output sections is normally done before dynamic section
+ symbols have been allocated. This function is called later, and
+ handles cases like htab->brlt which is mapped to its own output
+ section. */
+
+ static void
+ maybe_strip_output (struct bfd_link_info *info, asection *isec)
+ {
+ if (isec->size == 0
+ && isec->output_section->size == 0
+ && !bfd_section_removed_from_list (info->output_bfd,
+ isec->output_section)
+ && elf_section_data (isec->output_section)->dynindx == 0)
+ {
+ isec->output_section->flags |= SEC_EXCLUDE;
+ bfd_section_list_remove (info->output_bfd, isec->output_section);
+ info->output_bfd->section_count--;
+ }
+ }
+
/* Determine and set the size of the stub section for a final link.
The basic idea here is to examine all the relocations looking for
*************** ppc64_elf_size_stubs (struct bfd_link_in
*** 11169,11174 ****
--- 11234,11258 ----
htab->glink->flags |= SEC_RELOC;
}
+ if (htab->glink_eh_frame != NULL
+ && !bfd_is_abs_section (htab->glink_eh_frame->output_section)
+ && (htab->glink_eh_frame->flags & SEC_EXCLUDE) == 0)
+ {
+ bfd_size_type size = 0;
+
+ for (stub_sec = htab->stub_bfd->sections;
+ stub_sec != NULL;
+ stub_sec = stub_sec->next)
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+ size += 20;
+ if (htab->glink != NULL && htab->glink->size != 0)
+ size += 24;
+ if (size != 0)
+ size += sizeof (glink_eh_frame_cie);
+ htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
+ htab->glink_eh_frame->size = size;
+ }
+
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
*************** ppc64_elf_size_stubs (struct bfd_link_in
*** 11178,11194 ****
/* Exit from this loop when no stubs have been added, and no stubs
have changed size. */
! if (stub_sec == NULL)
break;
/* Ask the linker to do its stuff. */
(*htab->layout_sections_again) ();
}
! /* It would be nice to strip htab->brlt from the output if the
! section is empty, but it's too late. If we strip sections here,
! the dynamic symbol table is corrupted since the section symbol
! for the stripped section isn't written. */
return TRUE;
}
--- 11262,11279 ----
/* Exit from this loop when no stubs have been added, and no stubs
have changed size. */
! if (stub_sec == NULL
! && (htab->glink_eh_frame == NULL
! || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
break;
/* Ask the linker to do its stuff. */
(*htab->layout_sections_again) ();
}
! maybe_strip_output (info, htab->brlt);
! if (htab->glink_eh_frame != NULL)
! maybe_strip_output (info, htab->glink_eh_frame);
return TRUE;
}
*************** ppc64_elf_build_stubs (bfd_boolean emit_
*** 11393,11398 ****
--- 11478,11577 ----
return FALSE;
}
+ if (htab->glink_eh_frame != NULL
+ && htab->glink_eh_frame->size != 0)
+ {
+ bfd_vma val;
+
+ p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
+ if (p == NULL)
+ return FALSE;
+ htab->glink_eh_frame->contents = p;
+
+ htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
+
+ memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
+ /* CIE length (rewrite in case little-endian). */
+ bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p);
+ p += sizeof (glink_eh_frame_cie);
+
+ for (stub_sec = htab->stub_bfd->sections;
+ stub_sec != NULL;
+ stub_sec = stub_sec->next)
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+ {
+ /* FDE length. */
+ bfd_put_32 (htab->elf.dynobj, 16, p);
+ p += 4;
+ /* CIE pointer. */
+ val = p - htab->glink_eh_frame->contents;
+ bfd_put_32 (htab->elf.dynobj, val, p);
+ p += 4;
+ /* Offset to stub section. */
+ val = (stub_sec->output_section->vma
+ + stub_sec->output_offset);
+ val -= (htab->glink_eh_frame->output_section->vma
+ + htab->glink_eh_frame->output_offset);
+ val -= p - htab->glink_eh_frame->contents;
+ if (val + 0x80000000 > 0xffffffff)
+ {
+ info->callbacks->einfo
+ (_("%s offset too large for .eh_frame sdata4 encoding"),
+ stub_sec->name);
+ return FALSE;
+ }
+ bfd_put_32 (htab->elf.dynobj, val, p);
+ p += 4;
+ /* stub section size. */
+ bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p);
+ p += 4;
+ /* Augmentation. */
+ p += 1;
+ /* Pad. */
+ p += 3;
+ }
+ if (htab->glink != NULL && htab->glink->size != 0)
+ {
+ /* FDE length. */
+ bfd_put_32 (htab->elf.dynobj, 20, p);
+ p += 4;
+ /* CIE pointer. */
+ val = p - htab->glink_eh_frame->contents;
+ bfd_put_32 (htab->elf.dynobj, val, p);
+ p += 4;
+ /* Offset to .glink. */
+ val = (htab->glink->output_section->vma
+ + htab->glink->output_offset
+ + 8);
+ val -= (htab->glink_eh_frame->output_section->vma
+ + htab->glink_eh_frame->output_offset);
+ val -= p - htab->glink_eh_frame->contents;
+ if (val + 0x80000000 > 0xffffffff)
+ {
+ info->callbacks->einfo
+ (_("%s offset too large for .eh_frame sdata4 encoding"),
+ htab->glink->name);
+ return FALSE;
+ }
+ bfd_put_32 (htab->elf.dynobj, val, p);
+ p += 4;
+ /* .glink size. */
+ bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p);
+ p += 4;
+ /* Augmentation. */
+ p += 1;
+
+ *p++ = DW_CFA_advance_loc + 1;
+ *p++ = DW_CFA_register;
+ *p++ = 65;
+ *p++ = 12;
+ *p++ = DW_CFA_advance_loc + 4;
+ *p++ = DW_CFA_restore_extended;
+ *p++ = 65;
+ }
+ htab->glink_eh_frame->size = p - htab->glink_eh_frame->contents;
+ }
+
/* Build the stubs as directed by the stub hash table. */
bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
*************** ppc64_elf_build_stubs (bfd_boolean emit_
*** 11410,11416 ****
}
if (stub_sec != NULL
! || htab->glink->rawsize != htab->glink->size)
{
htab->stub_error = TRUE;
info->callbacks->einfo (_("stubs don't match calculated size\n"));
--- 11589,11597 ----
}
if (stub_sec != NULL
! || htab->glink->rawsize != htab->glink->size
! || (htab->glink_eh_frame != NULL
! && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
{
htab->stub_error = TRUE;
info->callbacks->einfo (_("stubs don't match calculated size\n"));
*************** ppc64_elf_relocate_section (bfd *output_
*** 12842,12853 ****
else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
&& !is_opd
&& r_type != R_PPC64_TOC)
! {
! outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
! if (h->elf.dynindx == -1
! && h->elf.root.type == bfd_link_hash_undefweak)
! memset (&outrel, 0, sizeof outrel);
! }
else
{
/* This symbol is local, or marked to become local,
--- 13021,13027 ----
else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
&& !is_opd
&& r_type != R_PPC64_TOC)
! outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
else
{
/* This symbol is local, or marked to become local,
*************** ppc64_elf_finish_dynamic_sections (bfd *
*** 13566,13571 ****
--- 13740,13753 ----
NULL))
return FALSE;
+
+ if (htab->glink_eh_frame != NULL
+ && htab->glink_eh_frame->sec_info_type == ELF_INFO_TYPE_EH_FRAME
+ && !_bfd_elf_write_section_eh_frame (output_bfd, info,
+ htab->glink_eh_frame,
+ htab->glink_eh_frame->contents))
+ return FALSE;
+
/* We need to handle writing out multiple GOT sections ourselves,
since we didn't add them to DYNOBJ. We know dynobj is the first
bfd. */