aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c82
1 files changed, 47 insertions, 35 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index b04bea4..ac416ba 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -1,6 +1,6 @@
/* PowerPC-specific support for 32-bit ELF
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
@@ -4301,7 +4301,8 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
return TRUE;
}
-/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */
+/* Set plt output section type, htab->tls_get_addr, and call the
+ generic ELF tls_setup function. */
asection *
ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
@@ -4322,6 +4323,43 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
return _bfd_elf_tls_setup (obfd, info);
}
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+ HASH. */
+
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+ const Elf_Internal_Rela *rel,
+ const struct elf_link_hash_entry *hash)
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+ enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
+ unsigned int r_symndx = ELF32_R_SYM (rel->r_info);
+
+ if (r_symndx >= symtab_hdr->sh_info
+ && (r_type == R_PPC_PLTREL24
+ || r_type == R_PPC_LOCAL24PC
+ || r_type == R_PPC_REL14
+ || r_type == R_PPC_REL14_BRTAKEN
+ || r_type == R_PPC_REL14_BRNTAKEN
+ || r_type == R_PPC_REL24
+ || r_type == R_PPC_ADDR24
+ || r_type == R_PPC_ADDR14
+ || r_type == R_PPC_ADDR14_BRTAKEN
+ || r_type == R_PPC_ADDR14_BRNTAKEN))
+ {
+ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+ struct elf_link_hash_entry *h;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ if (h == hash)
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* Run through all the TLS relocs looking for optimization
opportunities. */
@@ -4449,35 +4487,10 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
if (!expecting_tls_get_addr)
continue;
- if (rel + 1 < relend)
- {
- enum elf_ppc_reloc_type r_type2;
- unsigned long r_symndx2;
- struct elf_link_hash_entry *h2;
-
- /* The next instruction should be a call to
- __tls_get_addr. Peek at the reloc to be sure. */
- r_type2 = ELF32_R_TYPE (rel[1].r_info);
- r_symndx2 = ELF32_R_SYM (rel[1].r_info);
- if (r_symndx2 >= symtab_hdr->sh_info
- && (r_type2 == R_PPC_REL14
- || r_type2 == R_PPC_REL14_BRTAKEN
- || r_type2 == R_PPC_REL14_BRNTAKEN
- || r_type2 == R_PPC_REL24
- || r_type2 == R_PPC_PLTREL24))
- {
- struct elf_link_hash_entry **sym_hashes;
-
- sym_hashes = elf_sym_hashes (ibfd);
- h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info];
- while (h2->root.type == bfd_link_hash_indirect
- || h2->root.type == bfd_link_hash_warning)
- h2 = ((struct elf_link_hash_entry *)
- h2->root.u.i.link);
- if (h2 == htab->tls_get_addr)
- continue;
- }
- }
+ if (rel + 1 < relend
+ && branch_reloc_hash_match (ibfd, rel + 1,
+ htab->tls_get_addr))
+ continue;
/* Uh oh, we didn't find the expected call. We
could just mark this symbol to exclude it
@@ -6344,22 +6357,21 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_GOT_TLSLD16_LO:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
{
- bfd_vma insn1, insn2;
+ unsigned int insn1, insn2;
bfd_vma offset;
tls_ldgd_opt:
offset = rel[1].r_offset;
- insn1 = bfd_get_32 (output_bfd,
- contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
+ insn1 = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
insn1 &= (1 << 26) - 1;
insn1 |= 32 << 26; /* lwz */
insn2 = 0x7c631214; /* add 3,3,2 */
rel[1].r_info
= ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), R_PPC_NONE);
- rel[1].r_addend = 0;
r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
+ R_PPC_GOT_TPREL16);
rel->r_info = ELF32_R_INFO (r_symndx, r_type);