Browse Source

* 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.
cgen-1_1-branch
Alan Modra 18 years ago
parent
commit
3a71aa26df
  1. 21
      bfd/ChangeLog
  2. 82
      bfd/elf32-ppc.c
  3. 247
      bfd/elf64-ppc.c

21
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> 2009-02-12 Nick Clifton <nickc@redhat.com>
PR 9827 PR 9827

82
bfd/elf32-ppc.c

@ -1,6 +1,6 @@
/* PowerPC-specific support for 32-bit ELF /* PowerPC-specific support for 32-bit ELF
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 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. Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library. This file is part of BFD, the Binary File Descriptor library.
@ -4301,7 +4301,8 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
return TRUE; 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 * asection *
ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) 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 _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 /* Run through all the TLS relocs looking for optimization
opportunities. */ opportunities. */
@ -4449,35 +4487,10 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
if (!expecting_tls_get_addr) if (!expecting_tls_get_addr)
continue; continue;
if (rel + 1 < relend) if (rel + 1 < relend
{ && branch_reloc_hash_match (ibfd, rel + 1,
enum elf_ppc_reloc_type r_type2; htab->tls_get_addr))
unsigned long r_symndx2; continue;
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;
}
}
/* Uh oh, we didn't find the expected call. We /* Uh oh, we didn't find the expected call. We
could just mark this symbol to exclude it 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: case R_PPC_GOT_TLSLD16_LO:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
{ {
bfd_vma insn1, insn2; unsigned int insn1, insn2;
bfd_vma offset; bfd_vma offset;
tls_ldgd_opt: tls_ldgd_opt:
offset = rel[1].r_offset; offset = rel[1].r_offset;
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0) if ((tls_mask & tls_gd) != 0)
{ {
/* IE */ /* IE */
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
insn1 &= (1 << 26) - 1; insn1 &= (1 << 26) - 1;
insn1 |= 32 << 26; /* lwz */ insn1 |= 32 << 26; /* lwz */
insn2 = 0x7c631214; /* add 3,3,2 */ insn2 = 0x7c631214; /* add 3,3,2 */
rel[1].r_info rel[1].r_info
= ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), R_PPC_NONE); = 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_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
+ R_PPC_GOT_TPREL16); + R_PPC_GOT_TPREL16);
rel->r_info = ELF32_R_INFO (r_symndx, r_type); rel->r_info = ELF32_R_INFO (r_symndx, r_type);

247
bfd/elf64-ppc.c

@ -1,6 +1,6 @@
/* PowerPC64-specific support for 64-bit ELF. /* PowerPC64-specific support for 64-bit ELF.
Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
Free Software Foundation, Inc. 2009 Free Software Foundation, Inc.
Written by Linus Nordberg, Swox AB <info@swox.com>, Written by Linus Nordberg, Swox AB <info@swox.com>,
based on elf32-ppc.c by Ian Lance Taylor. based on elf32-ppc.c by Ian Lance Taylor.
Largely rewritten by Alan Modra <amodra@bigpond.net.au> Largely rewritten by Alan Modra <amodra@bigpond.net.au>
@ -2608,9 +2608,15 @@ struct _ppc64_elf_section_data
long *adjust; long *adjust;
} opd; } opd;
/* An array for toc sections, indexed by offset/8. /* An array for toc sections, indexed by offset/8. */
Specifies the relocation symbol index used at a given toc offset. */ struct _toc_sec_data
unsigned *t_symndx; {
/* Specifies the relocation symbol index used at a given toc offset. */
unsigned *symndx;
/* And the relocation addend. */
bfd_vma *add;
} toc;
} u; } u;
enum _ppc64_sec_type sec_type:2; 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; const Elf_Internal_Rela *rel_end;
asection *sreloc; asection *sreloc;
asection **opd_sym_map; asection **opd_sym_map;
struct elf_link_hash_entry *tga, *dottga;
if (info->relocatable) if (info->relocatable)
return TRUE; return TRUE;
@ -4594,6 +4601,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
BFD_ASSERT (is_ppc64_elf (abfd)); BFD_ASSERT (is_ppc64_elf (abfd));
htab = ppc_hash_table (info); 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); symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (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, if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
rel->r_addend)) rel->r_addend))
return FALSE; return FALSE;
if (h == &htab->tls_get_addr->elf if (h == tga || h == dottga)
|| h == &htab->tls_get_addr_fd->elf)
sec->has_tls_reloc = 1; 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; break;
@ -4891,23 +4885,30 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
ppc64_sec = ppc64_elf_section_data (sec); ppc64_sec = ppc64_elf_section_data (sec);
if (ppc64_sec->sec_type != sec_toc) if (ppc64_sec->sec_type != sec_toc)
{ {
bfd_size_type amt;
/* One extra to simplify get_tls_mask. */ /* One extra to simplify get_tls_mask. */
bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1; amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned);
ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt); ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt);
if (ppc64_sec->u.t_symndx == NULL) 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; return FALSE;
BFD_ASSERT (ppc64_sec->sec_type == sec_normal); BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
ppc64_sec->sec_type = sec_toc; ppc64_sec->sec_type = sec_toc;
} }
BFD_ASSERT (rel->r_offset % 8 == 0); 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. /* Mark the second slot of a GD or LD entry.
-1 to indicate GD and -2 to indicate LD. */ -1 to indicate GD and -2 to indicate LD. */
if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD)) 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)) 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; goto dodyn;
case R_PPC64_TPREL16: case R_PPC64_TPREL16:
@ -6226,9 +6227,12 @@ get_sym_h (struct elf_link_hash_entry **hp,
type suitable for optimization, and 1 otherwise. */ type suitable for optimization, and 1 otherwise. */
static int 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, Elf_Internal_Sym **locsymsp,
const Elf_Internal_Rela *rel, bfd *ibfd) const Elf_Internal_Rela *rel,
bfd *ibfd)
{ {
unsigned long r_symndx; unsigned long r_symndx;
int next_r; int next_r;
@ -6256,12 +6260,14 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
off = sym->st_value; off = sym->st_value;
off += rel->r_addend; off += rel->r_addend;
BFD_ASSERT (off % 8 == 0); BFD_ASSERT (off % 8 == 0);
r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8]; r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8];
next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1]; next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1];
if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
return 0;
if (toc_symndx != NULL) if (toc_symndx != NULL)
*toc_symndx = r_symndx; *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 if ((h == NULL
|| ((h->root.type == bfd_link_hash_defined || ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak) || 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; struct ppc_link_hash_table *htab;
htab = ppc_hash_table (info); htab = ppc_hash_table (info);
if (htab->tls_get_addr != NULL) htab->tls_get_addr = ((struct ppc_link_hash_entry *)
{ elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
struct ppc_link_hash_entry *h = htab->tls_get_addr; FALSE, FALSE, TRUE));
htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
while (h->elf.root.type == bfd_link_hash_indirect elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
|| h->elf.root.type == bfd_link_hash_warning) FALSE, FALSE, TRUE));
h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link; return _bfd_elf_tls_setup (obfd, info);
}
htab->tls_get_addr = h;
if (htab->tls_get_addr_fd == NULL /* Return TRUE iff REL is a branch reloc with a global symbol matching
&& h->oh != NULL HASH1 or HASH2. */
&& 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;
}
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; struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
struct elf_link_hash_entry *h;
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_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 FALSE;
return _bfd_elf_tls_setup (obfd, info);
} }
/* Run through all the TLS relocs looking for optimization /* 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) if (!expecting_tls_get_addr)
continue; 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; if (expecting_tls_get_addr == 2)
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))
{ {
struct elf_link_hash_entry **sym_hashes; /* Check for toc tls entries. */
char *toc_tls;
sym_hashes = elf_sym_hashes (ibfd); int retval;
h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info]; retval = get_tls_mask (&toc_tls, NULL, NULL,
while (h2->root.type == bfd_link_hash_indirect &locsyms,
|| h2->root.type == bfd_link_hash_warning) rel, ibfd);
h2 = ((struct elf_link_hash_entry *) if (retval == 0)
h2->root.u.i.link); goto err_free_rel;
if (h2 != NULL if (retval > 1 && toc_tls != NULL)
&& (h2 == &htab->tls_get_addr->elf toc_ref[toc_ref_index] = 1;
|| 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;
}
} }
continue;
} }
if (expecting_tls_get_addr != 1) if (expecting_tls_get_addr != 1)
@ -9712,7 +9702,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
/* Get tls info. */ /* Get tls info. */
char *tls_mask; 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)) irela - 1, input_bfd))
goto error_ret_free_internal; goto error_ret_free_internal;
if (*tls_mask != 0) if (*tls_mask != 0)
@ -10204,6 +10194,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
struct ppc_link_hash_entry *fdh; struct ppc_link_hash_entry *fdh;
const char *sym_name; const char *sym_name;
unsigned long r_symndx, toc_symndx; unsigned long r_symndx, toc_symndx;
bfd_vma toc_addend;
char tls_mask, tls_gd, tls_type; char tls_mask, tls_gd, tls_type;
char sym_type; char sym_type;
bfd_vma relocation; bfd_vma relocation;
@ -10312,8 +10303,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Check for toc tls entries. */ /* Check for toc tls entries. */
char *toc_tls; char *toc_tls;
if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms, if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
rel, input_bfd)) &local_syms, rel, input_bfd))
return FALSE; return FALSE;
if (toc_tls) if (toc_tls)
@ -10375,8 +10366,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
char *toc_tls; char *toc_tls;
int retval; int retval;
retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms, retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
rel, input_bfd); &local_syms, rel, input_bfd);
if (retval == 0) if (retval == 0)
return FALSE; return FALSE;
@ -10424,6 +10415,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (toc_symndx != 0) if (toc_symndx != 0)
{ {
rel->r_info = ELF64_R_INFO (toc_symndx, r_type); rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
rel->r_addend = toc_addend;
/* We changed the symbol. Start over in order to /* We changed the symbol. Start over in order to
get h, sym, sec etc. right. */ get h, sym, sec etc. right. */
rel--; rel--;
@ -10477,6 +10469,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (toc_symndx != 0) if (toc_symndx != 0)
{ {
rel->r_info = ELF64_R_INFO (toc_symndx, r_type); rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
rel->r_addend = toc_addend;
/* We changed the symbol. Start over in order to /* We changed the symbol. Start over in order to
get h, sym, sec etc. right. */ get h, sym, sec etc. right. */
rel--; rel--;
@ -10523,20 +10516,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_LO:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
{ {
bfd_vma insn1, insn2, insn3; unsigned int insn1, insn2, insn3;
bfd_vma offset; bfd_vma offset;
tls_ldgd_opt: tls_ldgd_opt:
/* We know that the next reloc is on a tls_get_addr /* We know that the next reloc is on a tls_get_addr
call, since ppc64_elf_tls_optimize checks this. */ call, since ppc64_elf_tls_optimize checks this. */
offset = rel[1].r_offset; 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) if ((tls_mask & tls_gd) != 0)
{ {
/* IE */ /* IE */
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
insn1 &= (1 << 26) - (1 << 2); insn1 &= (1 << 26) - (1 << 2);
insn1 |= 58 << 26; /* ld */ insn1 |= 58 << 26; /* ld */
insn2 = 0x7c636a14; /* add 3,3,13 */ 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 rel->r_addend -= (local_syms[r_symndx].st_value
+ sec->output_offset + sec->output_offset
+ sec->output_section->vma); + sec->output_section->vma);
rel[1].r_addend = rel->r_addend;
} }
else if (toc_symndx != 0) else if (toc_symndx != 0)
r_symndx = toc_symndx; {
r_symndx = toc_symndx;
rel->r_addend = toc_addend;
}
r_type = R_PPC64_TPREL16_HA; r_type = R_PPC64_TPREL16_HA;
rel->r_info = ELF64_R_INFO (r_symndx, r_type); rel->r_info = ELF64_R_INFO (r_symndx, r_type);
rel[1].r_info = ELF64_R_INFO (r_symndx, rel[1].r_info = ELF64_R_INFO (r_symndx,
R_PPC64_TPREL16_LO); R_PPC64_TPREL16_LO);
rel[1].r_offset += d_offset; 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 if (insn3 == NOP
|| insn3 == CROR_151515 || insn3 == CROR_313131) || insn3 == CROR_151515 || insn3 == CROR_313131)
{ {
insn3 = insn2;
insn2 = NOP;
rel[1].r_offset += 4; 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, insn2, contents + offset);
bfd_put_32 (output_bfd, insn3, contents + offset + 4); if ((tls_mask & tls_gd) == 0
if (tls_gd == 0 || toc_symndx != 0) && (tls_gd == 0 || toc_symndx != 0))
{ {
/* We changed the symbol. Start over in order /* We changed the symbol. Start over in order
to get h, sym, sec etc. right. */ to get h, sym, sec etc. right. */
@ -10969,7 +10965,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
*offp = off | 1; *offp = off | 1;
if ((info->shared || indx != 0) if ((info->shared || indx != 0)
&& (h == NULL && (offp == &ppc64_tlsld_got (input_bfd)->offset
|| h == NULL
|| ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
|| h->elf.root.type != bfd_link_hash_undefweak)) || h->elf.root.type != bfd_link_hash_undefweak))
{ {

Loading…
Cancel
Save