aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog14
-rw-r--r--bfd/elf64-ppc.c136
-rw-r--r--include/elf/ChangeLog4
-rw-r--r--include/elf/ppc64.h3
4 files changed, 151 insertions, 6 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 05372bf..75dc59c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2011-10-10 Alan Modra <amodra@gmail.com>
+
+ * elf64-ppc.c (ppc64_elf_howto_table): Add R_PPC64_TOCSAVE entry.
+ (struct ppc_link_hash_table): Add tocsave_htab.
+ (struct tocsave_entry): New.
+ (tocsave_htab_hash, tocsave_htab_eq, tocsave_find): New functions.
+ (ppc64_elf_link_hash_table_create): Create tocsave_htab..
+ (ppc64_elf_link_hash_table_free): ..and delete it.
+ (build_plt_stub): Always put STD_R2_40R1 first.
+ (ppc64_elf_size_stubs): Check for R_PPC64_TOCSAVE following reloc
+ on plt call. If present add prologue nop location to tocsave_htab.
+ (ppc64_elf_relocate_section): Convert prologue nop to std. Skip
+ first insn of plt call stub when R_PPC64_TOCSAVE present.
+
2011-10-08 H.J. Lu <hongjiu.lu@intel.com>
PR ld/13250
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 2511aa8..5f5c811 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -1282,6 +1282,20 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
0, /* dst_mask */
FALSE), /* pcrel_offset */
+ HOWTO (R_PPC64_TOCSAVE,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC64_TOCSAVE", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* Computes the load module index of the load module that contains the
definition of its TLS sym. */
HOWTO (R_PPC64_DTPMOD64,
@@ -3677,6 +3691,9 @@ struct ppc_link_hash_table
/* Another hash table for plt_branch stubs. */
struct bfd_hash_table branch_hash_table;
+ /* Hash table for function prologue tocsave. */
+ htab_t tocsave_htab;
+
/* Linker stub bfd. */
bfd *stub_bfd;
@@ -3923,6 +3940,26 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
return entry;
}
+struct tocsave_entry {
+ asection *sec;
+ bfd_vma offset;
+};
+
+static hashval_t
+tocsave_htab_hash (const void *p)
+{
+ const struct tocsave_entry *e = (const struct tocsave_entry *) p;
+ return ((bfd_vma)(intptr_t) e->sec ^ e->offset) >> 3;
+}
+
+static int
+tocsave_htab_eq (const void *p1, const void *p2)
+{
+ const struct tocsave_entry *e1 = (const struct tocsave_entry *) p1;
+ const struct tocsave_entry *e2 = (const struct tocsave_entry *) p2;
+ return e1->sec == e2->sec && e1->offset == e2->offset;
+}
+
/* Create a ppc64 ELF linker hash table. */
static struct bfd_link_hash_table *
@@ -3953,6 +3990,13 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
sizeof (struct ppc_branch_hash_entry)))
return NULL;
+ htab->tocsave_htab = htab_try_create (1024,
+ tocsave_htab_hash,
+ tocsave_htab_eq,
+ NULL);
+ if (htab->tocsave_htab == NULL)
+ return NULL;
+
/* Initializing two fields of the union is just cosmetic. We really
only care about glist, but when compiled on a 32-bit host the
bfd_vma fields are larger. Setting the bfd_vma to zero makes
@@ -3974,10 +4018,12 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
static void
ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
{
- struct ppc_link_hash_table *ret = (struct ppc_link_hash_table *) hash;
+ struct ppc_link_hash_table *htab = (struct ppc_link_hash_table *) hash;
- bfd_hash_table_free (&ret->stub_hash_table);
- bfd_hash_table_free (&ret->branch_hash_table);
+ bfd_hash_table_free (&htab->stub_hash_table);
+ bfd_hash_table_free (&htab->branch_hash_table);
+ if (htab->tocsave_htab)
+ htab_delete (htab->tocsave_htab);
_bfd_generic_link_hash_table_free (hash);
}
@@ -6714,6 +6760,55 @@ get_tls_mask (unsigned char **tls_maskp,
return 1;
}
+/* Find (or create) an entry in the tocsave hash table. */
+
+static struct tocsave_entry *
+tocsave_find (struct ppc_link_hash_table *htab,
+ enum insert_option insert,
+ Elf_Internal_Sym **local_syms,
+ const Elf_Internal_Rela *irela,
+ bfd *ibfd)
+{
+ unsigned long r_indx;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ struct tocsave_entry ent, *p;
+ hashval_t hash;
+ struct tocsave_entry **slot;
+
+ r_indx = ELF64_R_SYM (irela->r_info);
+ if (!get_sym_h (&h, &sym, &ent.sec, NULL, local_syms, r_indx, ibfd))
+ return NULL;
+ if (ent.sec == NULL || ent.sec->output_section == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
+ return NULL;
+ }
+
+ if (h != NULL)
+ ent.offset = h->root.u.def.value;
+ else
+ ent.offset = sym->st_value;
+ ent.offset += irela->r_addend;
+
+ hash = tocsave_htab_hash (&ent);
+ slot = ((struct tocsave_entry **)
+ htab_find_slot_with_hash (htab->tocsave_htab, &ent, hash, insert));
+ if (slot == NULL)
+ return NULL;
+
+ if (*slot == NULL)
+ {
+ p = (struct tocsave_entry *) bfd_alloc (ibfd, sizeof (*p));
+ if (p == NULL)
+ return NULL;
+ *p = ent;
+ *slot = p;
+ }
+ return *slot;
+}
+
/* Adjust all global syms defined in opd sections. In gcc generated
code for the old ABI, these will already have been done. */
@@ -9327,8 +9422,9 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r,
{
if (r != NULL)
{
+ r[0].r_offset += 4;
r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
- r[1].r_offset = r[0].r_offset + 8;
+ r[1].r_offset = r[0].r_offset + 4;
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))
@@ -9350,8 +9446,8 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r,
}
}
}
- bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4;
bfd_put_32 (obfd, STD_R2_40R1, p), p += 4;
+ bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4;
bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4;
if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
{
@@ -11180,6 +11276,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
continue;
}
+ if (stub_type == ppc_stub_plt_call
+ && irela + 1 < irelaend
+ && irela[1].r_offset == irela->r_offset + 4
+ && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE
+ && !tocsave_find (htab, INSERT,
+ &local_syms, irela + 1, input_bfd))
+ goto error_ret_free_internal;
+
/* Support for grouping stub sections. */
id_sec = htab->stub_group[section->id].link_sec;
@@ -12344,6 +12448,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
default:
break;
+ case R_PPC64_TOCSAVE:
+ if (relocation + addend == (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma)
+ && tocsave_find (htab, NO_INSERT,
+ &local_syms, rel, input_bfd))
+ {
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ if (insn == NOP
+ || insn == CROR_151515 || insn == CROR_313131)
+ bfd_put_32 (input_bfd, STD_R2_40R1,
+ contents + rel->r_offset);
+ }
+ break;
+
/* Branch taken prediction relocations. */
case R_PPC64_ADDR14_BRTAKEN:
case R_PPC64_REL14_BRTAKEN:
@@ -12496,6 +12615,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
+ stub_entry->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma);
addend = 0;
+
+ if (stub_entry->stub_type == ppc_stub_plt_call
+ && rel + 1 < relend
+ && rel[1].r_offset == rel->r_offset + 4
+ && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
+ relocation += 4;
}
if (insn != 0)
@@ -12555,6 +12680,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_TLS:
case R_PPC64_TLSGD:
case R_PPC64_TLSLD:
+ case R_PPC64_TOCSAVE:
case R_PPC64_GNU_VTINHERIT:
case R_PPC64_GNU_VTENTRY:
continue;
diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog
index eece8a8..3696543 100644
--- a/include/elf/ChangeLog
+++ b/include/elf/ChangeLog
@@ -1,3 +1,7 @@
+2011-10-10 Alan Modra <amodra@gmail.com>
+
+ * ppc64.h (R_PPC64_TOCSAVE): Add.
+
2011-10-05 DJ Delorie <dj@redhat.com>
* rx.h (E_FLAG_RX_PID): New.
diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h
index a18edd6..f1c80f1 100644
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -1,5 +1,5 @@
/* PPC64 ELF support for BFD.
- Copyright 2003, 2005, 2009, 2010 Free Software Foundation, Inc.
+ Copyright 2003, 2005, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -139,6 +139,7 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
RELOC_NUMBER (R_PPC64_DTPREL16_HIGHESTA, 106)
RELOC_NUMBER (R_PPC64_TLSGD, 107)
RELOC_NUMBER (R_PPC64_TLSLD, 108)
+ RELOC_NUMBER (R_PPC64_TOCSAVE, 109)
#ifndef RELOC_MACROS_GEN_FUNC
/* Fake relocation only used internally by ld. */