diff options
author | Alan Modra <amodra@gmail.com> | 2009-02-15 12:14:14 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2009-02-15 12:14:14 +0000 |
commit | 3a71aa26df2a372a58e9c11ef9ba51fd0e83320a (patch) | |
tree | dabb80968494c1e18ec5fd2ac0fac8990ba82a40 | |
parent | f007ec5895011d3f7e39cf51f1d548303a7d15cf (diff) | |
download | gdb-3a71aa26df2a372a58e9c11ef9ba51fd0e83320a.zip gdb-3a71aa26df2a372a58e9c11ef9ba51fd0e83320a.tar.gz gdb-3a71aa26df2a372a58e9c11ef9ba51fd0e83320a.tar.bz2 |
* elf64-ppc.c (struct _ppc64_elf_section_data): Delete t_symndx,
add toc.symndx and toc.add.
(ppc64_elf_check_relocs): Don't set htab->tls_get_addr here.
Set up toc.add.
(get_tls_mask): Add toc_addend param, set from toc.add. Adjust all
callers.
(ppc64_elf_tls_setup): Set htab->tls_get_addr and tls_get_addr_fd.
(branch_reloc_hash_match): New function, extracted from..
(ppc64_elf_tls_optimize): ..here.
(ppc64_elf_relocate_section): Properly set addends when optimizing
tls sequences. Avoid unnecessary reading and writing of insns.
Only redo reloc when symbol changed. Bypass symbol checks when
using tlsld_got.
* elf32-ppc.c (ppc_elf_tls_setup): Correct comment.
(branch_reloc_hash_match): New function, extracted from..
(ppc_elf_tls_optimize): ..here.
(ppc_elf_relocate_section): Avoid unnecessary reading of insns.
Don't clear addend on zapped __tls_get_addr reloc.
-rw-r--r-- | bfd/ChangeLog | 21 | ||||
-rw-r--r-- | bfd/elf32-ppc.c | 82 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 247 |
3 files changed, 190 insertions, 160 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f0515a2..83d7d0b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,24 @@ +2009-02-15 Alan Modra <amodra@bigpond.net.au> + + * elf64-ppc.c (struct _ppc64_elf_section_data): Delete t_symndx, + add toc.symndx and toc.add. + (ppc64_elf_check_relocs): Don't set htab->tls_get_addr here. + Set up toc.add. + (get_tls_mask): Add toc_addend param, set from toc.add. Adjust all + callers. + (ppc64_elf_tls_setup): Set htab->tls_get_addr and tls_get_addr_fd. + (branch_reloc_hash_match): New function, extracted from.. + (ppc64_elf_tls_optimize): ..here. + (ppc64_elf_relocate_section): Properly set addends when optimizing + tls sequences. Avoid unnecessary reading and writing of insns. + Only redo reloc when symbol changed. Bypass symbol checks when + using tlsld_got. + * elf32-ppc.c (ppc_elf_tls_setup): Correct comment. + (branch_reloc_hash_match): New function, extracted from.. + (ppc_elf_tls_optimize): ..here. + (ppc_elf_relocate_section): Avoid unnecessary reading of insns. + Don't clear addend on zapped __tls_get_addr reloc. + 2009-02-12 Nick Clifton <nickc@redhat.com> PR 9827 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); diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 02a8632..703a2b3 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1,6 +1,6 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 - Free Software Foundation, Inc. + Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, + 2009 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB <info@swox.com>, based on elf32-ppc.c by Ian Lance Taylor. Largely rewritten by Alan Modra <amodra@bigpond.net.au> @@ -2608,9 +2608,15 @@ struct _ppc64_elf_section_data long *adjust; } opd; - /* An array for toc sections, indexed by offset/8. - Specifies the relocation symbol index used at a given toc offset. */ - unsigned *t_symndx; + /* An array for toc sections, indexed by offset/8. */ + struct _toc_sec_data + { + /* Specifies the relocation symbol index used at a given toc offset. */ + unsigned *symndx; + + /* And the relocation addend. */ + bfd_vma *add; + } toc; } u; enum _ppc64_sec_type sec_type:2; @@ -4578,6 +4584,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Rela *rel_end; asection *sreloc; asection **opd_sym_map; + struct elf_link_hash_entry *tga, *dottga; if (info->relocatable) return TRUE; @@ -4594,6 +4601,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, BFD_ASSERT (is_ppc64_elf (abfd)); htab = ppc_hash_table (info); + tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", + FALSE, FALSE, TRUE); + dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", + FALSE, FALSE, TRUE); symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); @@ -4829,25 +4840,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h, rel->r_addend)) return FALSE; - if (h == &htab->tls_get_addr->elf - || h == &htab->tls_get_addr_fd->elf) + if (h == tga || h == dottga) sec->has_tls_reloc = 1; - else if (htab->tls_get_addr == NULL - && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr") - && (h->root.root.string[15] == 0 - || h->root.root.string[15] == '@')) - { - htab->tls_get_addr = (struct ppc_link_hash_entry *) h; - sec->has_tls_reloc = 1; - } - else if (htab->tls_get_addr_fd == NULL - && CONST_STRNEQ (h->root.root.string, "__tls_get_addr") - && (h->root.root.string[14] == 0 - || h->root.root.string[14] == '@')) - { - htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h; - sec->has_tls_reloc = 1; - } } break; @@ -4891,23 +4885,30 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, ppc64_sec = ppc64_elf_section_data (sec); if (ppc64_sec->sec_type != sec_toc) { + bfd_size_type amt; + /* One extra to simplify get_tls_mask. */ - bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1; - ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt); - if (ppc64_sec->u.t_symndx == NULL) + amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned); + ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt); + if (ppc64_sec->u.toc.symndx == NULL) + return FALSE; + amt = sec->size * sizeof (bfd_vma) / 8; + ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt); + if (ppc64_sec->u.toc.add == NULL) return FALSE; BFD_ASSERT (ppc64_sec->sec_type == sec_normal); ppc64_sec->sec_type = sec_toc; } BFD_ASSERT (rel->r_offset % 8 == 0); - ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx; + ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx; + ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend; /* Mark the second slot of a GD or LD entry. -1 to indicate GD and -2 to indicate LD. */ if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD)) - ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1; + ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -1; else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD)) - ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2; + ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2; goto dodyn; case R_PPC64_TPREL16: @@ -6226,9 +6227,12 @@ get_sym_h (struct elf_link_hash_entry **hp, type suitable for optimization, and 1 otherwise. */ static int -get_tls_mask (char **tls_maskp, unsigned long *toc_symndx, +get_tls_mask (char **tls_maskp, + unsigned long *toc_symndx, + bfd_vma *toc_addend, Elf_Internal_Sym **locsymsp, - const Elf_Internal_Rela *rel, bfd *ibfd) + const Elf_Internal_Rela *rel, + bfd *ibfd) { unsigned long r_symndx; int next_r; @@ -6256,12 +6260,14 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx, off = sym->st_value; off += rel->r_addend; BFD_ASSERT (off % 8 == 0); - r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8]; - next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1]; - if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) - return 0; + r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8]; + next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1]; if (toc_symndx != NULL) *toc_symndx = r_symndx; + if (toc_addend != NULL) + *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8]; + if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) + return 0; if ((h == NULL || ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) @@ -6866,36 +6872,49 @@ ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) struct ppc_link_hash_table *htab; htab = ppc_hash_table (info); - if (htab->tls_get_addr != NULL) - { - struct ppc_link_hash_entry *h = htab->tls_get_addr; - - while (h->elf.root.type == bfd_link_hash_indirect - || h->elf.root.type == bfd_link_hash_warning) - h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link; - - htab->tls_get_addr = h; + htab->tls_get_addr = ((struct ppc_link_hash_entry *) + elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", + FALSE, FALSE, TRUE)); + htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *) + elf_link_hash_lookup (&htab->elf, "__tls_get_addr", + FALSE, FALSE, TRUE)); + return _bfd_elf_tls_setup (obfd, info); +} - if (htab->tls_get_addr_fd == NULL - && h->oh != NULL - && h->oh->is_func_descriptor - && (h->oh->elf.root.type == bfd_link_hash_defined - || h->oh->elf.root.type == bfd_link_hash_defweak)) - htab->tls_get_addr_fd = h->oh; - } +/* Return TRUE iff REL is a branch reloc with a global symbol matching + HASH1 or HASH2. */ - if (htab->tls_get_addr_fd != NULL) +static bfd_boolean +branch_reloc_hash_match (const bfd *ibfd, + const Elf_Internal_Rela *rel, + const struct ppc_link_hash_entry *hash1, + const struct ppc_link_hash_entry *hash2) +{ + Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); + enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info); + unsigned int r_symndx = ELF64_R_SYM (rel->r_info); + + if (r_symndx >= symtab_hdr->sh_info + && (r_type == R_PPC64_REL24 + || r_type == R_PPC64_REL14 + || r_type == R_PPC64_REL14_BRTAKEN + || r_type == R_PPC64_REL14_BRNTAKEN + || r_type == R_PPC64_ADDR24 + || r_type == R_PPC64_ADDR14 + || r_type == R_PPC64_ADDR14_BRTAKEN + || r_type == R_PPC64_ADDR14_BRNTAKEN)) { - struct ppc_link_hash_entry *h = htab->tls_get_addr_fd; - - while (h->elf.root.type == bfd_link_hash_indirect - || h->elf.root.type == bfd_link_hash_warning) - h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); + struct elf_link_hash_entry *h; - htab->tls_get_addr_fd = 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 == &hash1->elf || h == &hash2->elf) + return TRUE; } - - return _bfd_elf_tls_setup (obfd, info); + return FALSE; } /* Run through all the TLS relocs looking for optimization @@ -7141,55 +7160,26 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) if (!expecting_tls_get_addr) continue; - if (rel + 1 < relend) + if (rel + 1 < relend + && branch_reloc_hash_match (ibfd, rel + 1, + htab->tls_get_addr, + htab->tls_get_addr_fd)) { - Elf_Internal_Shdr *symtab_hdr; - enum elf_ppc64_reloc_type r_type2; - unsigned long r_symndx2; - struct elf_link_hash_entry *h2; - - symtab_hdr = &elf_symtab_hdr (ibfd); - - /* The next instruction should be a call to - __tls_get_addr. Peek at the reloc to be sure. */ - r_type2 = ELF64_R_TYPE (rel[1].r_info); - r_symndx2 = ELF64_R_SYM (rel[1].r_info); - if (r_symndx2 >= symtab_hdr->sh_info - && (r_type2 == R_PPC64_REL14 - || r_type2 == R_PPC64_REL14_BRTAKEN - || r_type2 == R_PPC64_REL14_BRNTAKEN - || r_type2 == R_PPC64_REL24)) + if (expecting_tls_get_addr == 2) { - 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 != NULL - && (h2 == &htab->tls_get_addr->elf - || h2 == &htab->tls_get_addr_fd->elf)) - { - if (expecting_tls_get_addr == 2) - { - /* Check for toc tls entries. */ - char *toc_tls; - int retval; - - retval = get_tls_mask (&toc_tls, NULL, - &locsyms, - rel, ibfd); - if (retval == 0) - goto err_free_rel; - if (retval > 1 && toc_tls != NULL) - toc_ref[toc_ref_index] = 1; - } - continue; - } + /* Check for toc tls entries. */ + char *toc_tls; + int retval; + + retval = get_tls_mask (&toc_tls, NULL, NULL, + &locsyms, + rel, ibfd); + if (retval == 0) + goto err_free_rel; + if (retval > 1 && toc_tls != NULL) + toc_ref[toc_ref_index] = 1; } + continue; } if (expecting_tls_get_addr != 1) @@ -9712,7 +9702,7 @@ ppc64_elf_size_stubs (bfd *output_bfd, /* Get tls info. */ char *tls_mask; - if (!get_tls_mask (&tls_mask, NULL, &local_syms, + if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms, irela - 1, input_bfd)) goto error_ret_free_internal; if (*tls_mask != 0) @@ -10204,6 +10194,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, struct ppc_link_hash_entry *fdh; const char *sym_name; unsigned long r_symndx, toc_symndx; + bfd_vma toc_addend; char tls_mask, tls_gd, tls_type; char sym_type; bfd_vma relocation; @@ -10312,8 +10303,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Check for toc tls entries. */ char *toc_tls; - if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms, - rel, input_bfd)) + if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend, + &local_syms, rel, input_bfd)) return FALSE; if (toc_tls) @@ -10375,8 +10366,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, char *toc_tls; int retval; - retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms, - rel, input_bfd); + retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend, + &local_syms, rel, input_bfd); if (retval == 0) return FALSE; @@ -10424,6 +10415,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (toc_symndx != 0) { rel->r_info = ELF64_R_INFO (toc_symndx, r_type); + rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ rel--; @@ -10477,6 +10469,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (toc_symndx != 0) { rel->r_info = ELF64_R_INFO (toc_symndx, r_type); + rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ rel--; @@ -10523,20 +10516,18 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TLSLD16_LO: if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) { - bfd_vma insn1, insn2, insn3; + unsigned int insn1, insn2, insn3; bfd_vma offset; tls_ldgd_opt: /* We know that the next reloc is on a tls_get_addr call, since ppc64_elf_tls_optimize checks this. */ offset = rel[1].r_offset; - insn1 = bfd_get_32 (output_bfd, - contents + rel->r_offset - d_offset); - insn3 = bfd_get_32 (output_bfd, - contents + offset + 4); if ((tls_mask & tls_gd) != 0) { /* IE */ + insn1 = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); insn1 &= (1 << 26) - (1 << 2); insn1 |= 58 << 26; /* ld */ insn2 = 0x7c636a14; /* add 3,3,13 */ @@ -10571,28 +10562,33 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend -= (local_syms[r_symndx].st_value + sec->output_offset + sec->output_section->vma); - rel[1].r_addend = rel->r_addend; } else if (toc_symndx != 0) - r_symndx = toc_symndx; + { + r_symndx = toc_symndx; + rel->r_addend = toc_addend; + } r_type = R_PPC64_TPREL16_HA; rel->r_info = ELF64_R_INFO (r_symndx, r_type); rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_LO); rel[1].r_offset += d_offset; + rel[1].r_addend = rel->r_addend; } + bfd_put_32 (output_bfd, insn1, + contents + rel->r_offset - d_offset); + insn3 = bfd_get_32 (output_bfd, + contents + offset + 4); if (insn3 == NOP || insn3 == CROR_151515 || insn3 == CROR_313131) { - insn3 = insn2; - insn2 = NOP; rel[1].r_offset += 4; + bfd_put_32 (output_bfd, insn2, contents + offset + 4); + insn2 = NOP; } - bfd_put_32 (output_bfd, insn1, - contents + rel->r_offset - d_offset); bfd_put_32 (output_bfd, insn2, contents + offset); - bfd_put_32 (output_bfd, insn3, contents + offset + 4); - if (tls_gd == 0 || toc_symndx != 0) + if ((tls_mask & tls_gd) == 0 + && (tls_gd == 0 || toc_symndx != 0)) { /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ @@ -10969,7 +10965,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, *offp = off | 1; if ((info->shared || indx != 0) - && (h == NULL + && (offp == &ppc64_tlsld_got (input_bfd)->offset + || h == NULL || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT || h->elf.root.type != bfd_link_hash_undefweak)) { |