diff options
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 82 |
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); |