From 3b421ab3bc02af734421775cbdbcfe98553c65a6 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 10 Oct 2011 13:21:07 +0000 Subject: [PATCH] include/elf/ * ppc64.h (R_PPC64_TOCSAVE): Add. bfd/ * 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. --- bfd/ChangeLog | 14 +++++ bfd/elf64-ppc.c | 136 ++++++++++++++++++++++++++++++++++++++++-- include/elf/ChangeLog | 4 ++ include/elf/ppc64.h | 3 +- 4 files changed, 151 insertions(+), 6 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 05372bf09b..75dc59c467 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2011-10-10 Alan Modra + + * 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 PR ld/13250 diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 2511aa8806..5f5c811160 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 eece8a8f1a..369654393e 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2011-10-10 Alan Modra + + * ppc64.h (R_PPC64_TOCSAVE): Add. + 2011-10-05 DJ Delorie * rx.h (E_FLAG_RX_PID): New. diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h index a18edd68fc..f1c80f1886 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. */ -- 2.34.1