Add new PowerPC relocations to binutils
Summary: LLVM/Clang generates relocations that our binutils doesn't understand, but newer binutils does. I got permission from the author of a series of patches to relicense them as GPLv2 for use in FreeBSD. The upstream git hashes are: ac2df442ac7901f00af15b272fc48b594b433713 2b95367962dc14f69d3c338c4d54195266e2e169 102890f04c44b64cf5cef4588267dd9f24086ac7 b7fcf6f6bb53b5027e111107f5416769cb9a5798 1d483afedd5a628dc84fb58d1d570f79fdfbfa7b 90aecf7a80c1cefeb45fc10a6cd02c8338e34b4c 3a71aa26df2a372a58e9c11ef9ba51fd0e83320a 727fc41e077139570ea8b8ddfd6c546b2a55627c With the import of clang 3.5, and a few backported patches, we should be able to move powerpc and powerpc64 to clang-as-cc soon. Test Plan: Passes make tinderbox, so no regressions. Binaries built with clang run on powerpc64. Reviewers: #committers, dim Reviewed By: dim Differential Revision: https://reviews.freebsd.org/D1297 Obtained from: Alan Modra, upstream binutils-gdb git MFC after: 3 weeks Relnotes: yes
This commit is contained in:
parent
44eb8bbe7b
commit
ff0bab9760
@ -1,3 +1,49 @@
|
||||
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.
|
||||
|
||||
2008-08-11 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf64-ppc.c (toc_adjusting_stub_needed): Any call via the plt
|
||||
needs r2 valid, not just those to external syms.
|
||||
|
||||
2007-11-06 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf32-ppc.c (ppc_elf_check_relocs): Don't refcount tlsld_got here..
|
||||
(ppc_elf_gc_sweep_hook): ..or here..
|
||||
(ppc_elf_tls_optimize): ..or here. Make two passes through the
|
||||
relocs, ensuring that tls_get_addr calls follow gd and ld relocs.
|
||||
(allocate_dynrelocs): Refcount tlsld_got here.
|
||||
(ppc_elf_size_dynamic_sections): Call allocate_dynrelocs before
|
||||
allocating tlsld_got.
|
||||
(ppc_elf_relocate_section): Remove check that a tls_get_addr
|
||||
call follows gd and ld relocs.
|
||||
|
||||
2007-08-13 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* elf64-ppc.c (ADDI_R12_R12, LD_R11_0R2, LD_R2_0R2): Define.
|
||||
Update stub comments.
|
||||
(build_plt_stub): Build two variants, one without "addis".
|
||||
(ppc_build_one_stub): Build stubs without "addis" if possible.
|
||||
(ppc_size_one_stub): Size new stubs.
|
||||
|
||||
2007-07-02 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* elfxx-mips.c (mips_elf_calculate_relocation): Handle
|
||||
|
@ -1380,6 +1380,9 @@ typedef struct bfd_section
|
||||
/* Nonzero if this section has TLS related relocations. */
|
||||
unsigned int has_tls_reloc:1;
|
||||
|
||||
/* Nonzero if this section has a call to __tls_get_addr. */
|
||||
unsigned int has_tls_get_addr_call:1;
|
||||
|
||||
/* Nonzero if this section has a gp reloc. */
|
||||
unsigned int has_gp_reloc:1;
|
||||
|
||||
@ -1640,11 +1643,11 @@ extern asection bfd_ind_section;
|
||||
/* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */ \
|
||||
0, 0, 0, 0, \
|
||||
\
|
||||
/* has_gp_reloc, need_finalize_relax, reloc_done, */ \
|
||||
0, 0, 0, \
|
||||
/* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax, */ \
|
||||
0, 0, 0, \
|
||||
\
|
||||
/* vma, lma, size, rawsize */ \
|
||||
0, 0, 0, 0, \
|
||||
/* reloc_done, vma, lma, size, rawsize */ \
|
||||
0, 0, 0, 0, 0, \
|
||||
\
|
||||
/* output_offset, output_section, alignment_power, */ \
|
||||
0, (struct bfd_section *) &SEC, 0, \
|
||||
@ -2896,6 +2899,8 @@ in the instruction. */
|
||||
|
||||
/* PowerPC and PowerPC64 thread-local storage relocations. */
|
||||
BFD_RELOC_PPC_TLS,
|
||||
BFD_RELOC_PPC_TLSGD,
|
||||
BFD_RELOC_PPC_TLSLD,
|
||||
BFD_RELOC_PPC_DTPMOD,
|
||||
BFD_RELOC_PPC_TPREL16,
|
||||
BFD_RELOC_PPC_TPREL16_LO,
|
||||
|
@ -58,10 +58,10 @@ static asection bfd_debug_section =
|
||||
0, 0, 1, 0,
|
||||
/* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */
|
||||
0, 0, 0, 0,
|
||||
/* has_gp_reloc, need_finalize_relax, reloc_done, */
|
||||
0, 0, 0,
|
||||
/* vma, lma, size, rawsize, */
|
||||
0, 0, 0, 0,
|
||||
/* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax, */
|
||||
0, 0, 0,
|
||||
/* reloc_done, vma, lma, size, rawsize, */
|
||||
0, 0, 0, 0, 0,
|
||||
/* output_offset, output_section, alignment_power, */
|
||||
0, NULL, 0,
|
||||
/* relocation, orelocation, reloc_count, filepos, rel_filepos, */
|
||||
|
@ -746,7 +746,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
|
||||
0xffff, /* dst_mask */
|
||||
FALSE), /* pcrel_offset */
|
||||
|
||||
/* Marker reloc for TLS. */
|
||||
/* Marker relocs for TLS. */
|
||||
HOWTO (R_PPC_TLS,
|
||||
0, /* rightshift */
|
||||
2, /* size (0 = byte, 1 = short, 2 = long) */
|
||||
@ -761,6 +761,34 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
|
||||
0, /* dst_mask */
|
||||
FALSE), /* pcrel_offset */
|
||||
|
||||
HOWTO (R_PPC_TLSGD,
|
||||
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_PPC_TLSGD", /* name */
|
||||
FALSE, /* partial_inplace */
|
||||
0, /* src_mask */
|
||||
0, /* dst_mask */
|
||||
FALSE), /* pcrel_offset */
|
||||
|
||||
HOWTO (R_PPC_TLSLD,
|
||||
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_PPC_TLSLD", /* 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_PPC_DTPMOD32,
|
||||
@ -1524,6 +1552,8 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
|
||||
case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break;
|
||||
case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break;
|
||||
case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break;
|
||||
case BFD_RELOC_PPC_TLSGD: r = R_PPC_TLSGD; break;
|
||||
case BFD_RELOC_PPC_TLSLD: r = R_PPC_TLSLD; break;
|
||||
case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break;
|
||||
case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break;
|
||||
case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break;
|
||||
@ -2345,16 +2375,34 @@ struct plt_entry
|
||||
bfd_vma glink_offset;
|
||||
};
|
||||
|
||||
/* Of those relocs that might be copied as dynamic relocs, this macro
|
||||
/* Of those relocs that might be copied as dynamic relocs, this function
|
||||
selects those that must be copied when linking a shared library,
|
||||
even when the symbol is local. */
|
||||
|
||||
#define MUST_BE_DYN_RELOC(RTYPE) \
|
||||
((RTYPE) != R_PPC_REL24 \
|
||||
&& (RTYPE) != R_PPC_REL14 \
|
||||
&& (RTYPE) != R_PPC_REL14_BRTAKEN \
|
||||
&& (RTYPE) != R_PPC_REL14_BRNTAKEN \
|
||||
&& (RTYPE) != R_PPC_REL32)
|
||||
static int
|
||||
must_be_dyn_reloc (struct bfd_link_info *info,
|
||||
enum elf_ppc_reloc_type r_type)
|
||||
{
|
||||
switch (r_type)
|
||||
{
|
||||
default:
|
||||
return 1;
|
||||
|
||||
case R_PPC_REL24:
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL14_BRTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN:
|
||||
case R_PPC_REL32:
|
||||
return 0;
|
||||
|
||||
case R_PPC_TPREL32:
|
||||
case R_PPC_TPREL16:
|
||||
case R_PPC_TPREL16_LO:
|
||||
case R_PPC_TPREL16_HI:
|
||||
case R_PPC_TPREL16_HA:
|
||||
return !info->executable;
|
||||
}
|
||||
}
|
||||
|
||||
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
|
||||
copying dynamic variables from a shared lib into an app's dynbss
|
||||
@ -2421,7 +2469,7 @@ struct ppc_elf_link_hash_table
|
||||
/* The .got.plt section (VxWorks only)*/
|
||||
asection *sgotplt;
|
||||
|
||||
/* Shortcut to .__tls_get_addr. */
|
||||
/* Shortcut to __tls_get_addr. */
|
||||
struct elf_link_hash_entry *tls_get_addr;
|
||||
|
||||
/* The bfd that forced an old-style PLT. */
|
||||
@ -3040,6 +3088,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
const Elf_Internal_Rela *rel;
|
||||
const Elf_Internal_Rela *rel_end;
|
||||
asection *got2, *sreloc;
|
||||
struct elf_link_hash_entry *tga;
|
||||
|
||||
if (info->relocatable)
|
||||
return TRUE;
|
||||
@ -3063,6 +3112,8 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
ppc_elf_howto_init ();
|
||||
|
||||
htab = ppc_elf_hash_table (info);
|
||||
tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
|
||||
FALSE, FALSE, TRUE);
|
||||
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
|
||||
sym_hashes = elf_sym_hashes (abfd);
|
||||
got2 = bfd_get_section_by_name (abfd, ".got2");
|
||||
@ -3074,7 +3125,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
unsigned long r_symndx;
|
||||
enum elf_ppc_reloc_type r_type;
|
||||
struct elf_link_hash_entry *h;
|
||||
int tls_type = 0;
|
||||
int tls_type;
|
||||
|
||||
r_symndx = ELF32_R_SYM (rel->r_info);
|
||||
if (r_symndx < symtab_hdr->sh_info)
|
||||
@ -3101,14 +3152,48 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
BFD_ASSERT (h == htab->elf.hgot);
|
||||
}
|
||||
|
||||
tls_type = 0;
|
||||
r_type = ELF32_R_TYPE (rel->r_info);
|
||||
if (h != NULL && h == tga)
|
||||
switch (r_type)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case R_PPC_PLTREL24:
|
||||
case R_PPC_LOCAL24PC:
|
||||
case R_PPC_REL24:
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL14_BRTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN:
|
||||
case R_PPC_ADDR24:
|
||||
case R_PPC_ADDR14:
|
||||
case R_PPC_ADDR14_BRTAKEN:
|
||||
case R_PPC_ADDR14_BRNTAKEN:
|
||||
if (rel != relocs
|
||||
&& (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
|
||||
|| ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
|
||||
/* We have a new-style __tls_get_addr call with a marker
|
||||
reloc. */
|
||||
;
|
||||
else
|
||||
/* Mark this section as having an old-style call. */
|
||||
sec->has_tls_get_addr_call = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (r_type)
|
||||
{
|
||||
case R_PPC_TLSGD:
|
||||
case R_PPC_TLSLD:
|
||||
/* These special tls relocs tie a call to __tls_get_addr with
|
||||
its parameter symbol. */
|
||||
break;
|
||||
|
||||
case R_PPC_GOT_TLSLD16:
|
||||
case R_PPC_GOT_TLSLD16_LO:
|
||||
case R_PPC_GOT_TLSLD16_HI:
|
||||
case R_PPC_GOT_TLSLD16_HA:
|
||||
htab->tlsld_got.refcount += 1;
|
||||
tls_type = TLS_TLS | TLS_LD;
|
||||
goto dogottls;
|
||||
|
||||
@ -3123,7 +3208,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
case R_PPC_GOT_TPREL16_LO:
|
||||
case R_PPC_GOT_TPREL16_HI:
|
||||
case R_PPC_GOT_TPREL16_HA:
|
||||
if (info->shared)
|
||||
if (!info->executable)
|
||||
info->flags |= DF_STATIC_TLS;
|
||||
tls_type = TLS_TLS | TLS_TPREL;
|
||||
goto dogottls;
|
||||
@ -3358,7 +3443,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
|
||||
/* This refers only to functions defined in the shared library. */
|
||||
case R_PPC_LOCAL24PC:
|
||||
if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
|
||||
if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
|
||||
{
|
||||
htab->plt_type = PLT_OLD;
|
||||
htab->old_bfd = abfd;
|
||||
@ -3381,7 +3466,11 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
|
||||
/* We shouldn't really be seeing these. */
|
||||
case R_PPC_TPREL32:
|
||||
if (info->shared)
|
||||
case R_PPC_TPREL16:
|
||||
case R_PPC_TPREL16_LO:
|
||||
case R_PPC_TPREL16_HI:
|
||||
case R_PPC_TPREL16_HA:
|
||||
if (!info->executable)
|
||||
info->flags |= DF_STATIC_TLS;
|
||||
goto dodyn;
|
||||
|
||||
@ -3390,14 +3479,6 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
case R_PPC_DTPREL32:
|
||||
goto dodyn;
|
||||
|
||||
case R_PPC_TPREL16:
|
||||
case R_PPC_TPREL16_LO:
|
||||
case R_PPC_TPREL16_HI:
|
||||
case R_PPC_TPREL16_HA:
|
||||
if (info->shared)
|
||||
info->flags |= DF_STATIC_TLS;
|
||||
goto dodyn;
|
||||
|
||||
case R_PPC_REL32:
|
||||
if (h == NULL
|
||||
&& got2 != NULL
|
||||
@ -3488,7 +3569,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
dynamic library if we manage to avoid copy relocs for the
|
||||
symbol. */
|
||||
if ((info->shared
|
||||
&& (MUST_BE_DYN_RELOC (r_type)
|
||||
&& (must_be_dyn_reloc (info, r_type)
|
||||
|| (h != NULL
|
||||
&& (! info->symbolic
|
||||
|| h->root.type == bfd_link_hash_defweak
|
||||
@ -3583,7 +3664,7 @@ ppc_elf_check_relocs (bfd *abfd,
|
||||
}
|
||||
|
||||
p->count += 1;
|
||||
if (!MUST_BE_DYN_RELOC (r_type))
|
||||
if (!must_be_dyn_reloc (info, r_type))
|
||||
p->pc_count += 1;
|
||||
}
|
||||
|
||||
@ -3903,9 +3984,6 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
|
||||
case R_PPC_GOT_TLSLD16_LO:
|
||||
case R_PPC_GOT_TLSLD16_HI:
|
||||
case R_PPC_GOT_TLSLD16_HA:
|
||||
htab->tlsld_got.refcount -= 1;
|
||||
/* Fall thru */
|
||||
|
||||
case R_PPC_GOT_TLSGD16:
|
||||
case R_PPC_GOT_TLSGD16_LO:
|
||||
case R_PPC_GOT_TLSGD16_HI:
|
||||
@ -3979,7 +4057,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)
|
||||
@ -4000,6 +4079,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_tdata (ibfd)->symtab_hdr;
|
||||
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. */
|
||||
|
||||
@ -4010,187 +4126,204 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
|
||||
bfd *ibfd;
|
||||
asection *sec;
|
||||
struct ppc_elf_link_hash_table *htab;
|
||||
int pass;
|
||||
|
||||
if (info->relocatable || info->shared)
|
||||
if (info->relocatable || !info->executable)
|
||||
return TRUE;
|
||||
|
||||
htab = ppc_elf_hash_table (info);
|
||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||
{
|
||||
Elf_Internal_Sym *locsyms = NULL;
|
||||
Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
|
||||
/* Make two passes through the relocs. First time check that tls
|
||||
relocs involved in setting up a tls_get_addr call are indeed
|
||||
followed by such a call. If they are not, exclude them from
|
||||
the optimizations done on the second pass. */
|
||||
for (pass = 0; pass < 2; ++pass)
|
||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||
{
|
||||
Elf_Internal_Sym *locsyms = NULL;
|
||||
Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
|
||||
|
||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
||||
if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
|
||||
{
|
||||
Elf_Internal_Rela *relstart, *rel, *relend;
|
||||
int expecting_tls_get_addr;
|
||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
||||
if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
|
||||
{
|
||||
Elf_Internal_Rela *relstart, *rel, *relend;
|
||||
|
||||
/* Read the relocations. */
|
||||
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
|
||||
info->keep_memory);
|
||||
if (relstart == NULL)
|
||||
return FALSE;
|
||||
/* Read the relocations. */
|
||||
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
|
||||
info->keep_memory);
|
||||
if (relstart == NULL)
|
||||
return FALSE;
|
||||
|
||||
expecting_tls_get_addr = 0;
|
||||
relend = relstart + sec->reloc_count;
|
||||
for (rel = relstart; rel < relend; rel++)
|
||||
{
|
||||
enum elf_ppc_reloc_type r_type;
|
||||
unsigned long r_symndx;
|
||||
struct elf_link_hash_entry *h = NULL;
|
||||
char *tls_mask;
|
||||
char tls_set, tls_clear;
|
||||
bfd_boolean is_local;
|
||||
relend = relstart + sec->reloc_count;
|
||||
for (rel = relstart; rel < relend; rel++)
|
||||
{
|
||||
enum elf_ppc_reloc_type r_type;
|
||||
unsigned long r_symndx;
|
||||
struct elf_link_hash_entry *h = NULL;
|
||||
char *tls_mask;
|
||||
char tls_set, tls_clear;
|
||||
bfd_boolean is_local;
|
||||
int expecting_tls_get_addr;
|
||||
bfd_signed_vma *got_count;
|
||||
|
||||
r_symndx = ELF32_R_SYM (rel->r_info);
|
||||
if (r_symndx >= symtab_hdr->sh_info)
|
||||
{
|
||||
struct elf_link_hash_entry **sym_hashes;
|
||||
r_symndx = ELF32_R_SYM (rel->r_info);
|
||||
if (r_symndx >= symtab_hdr->sh_info)
|
||||
{
|
||||
struct elf_link_hash_entry **sym_hashes;
|
||||
|
||||
sym_hashes = elf_sym_hashes (ibfd);
|
||||
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;
|
||||
}
|
||||
sym_hashes = elf_sym_hashes (ibfd);
|
||||
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;
|
||||
}
|
||||
|
||||
is_local = FALSE;
|
||||
if (h == NULL
|
||||
|| !h->def_dynamic)
|
||||
is_local = TRUE;
|
||||
expecting_tls_get_addr = 0;
|
||||
is_local = FALSE;
|
||||
if (h == NULL
|
||||
|| !h->def_dynamic)
|
||||
is_local = TRUE;
|
||||
|
||||
r_type = ELF32_R_TYPE (rel->r_info);
|
||||
switch (r_type)
|
||||
{
|
||||
case R_PPC_GOT_TLSLD16:
|
||||
case R_PPC_GOT_TLSLD16_LO:
|
||||
case R_PPC_GOT_TLSLD16_HI:
|
||||
case R_PPC_GOT_TLSLD16_HA:
|
||||
/* These relocs should never be against a symbol
|
||||
defined in a shared lib. Leave them alone if
|
||||
that turns out to be the case. */
|
||||
expecting_tls_get_addr = 0;
|
||||
htab->tlsld_got.refcount -= 1;
|
||||
if (!is_local)
|
||||
continue;
|
||||
r_type = ELF32_R_TYPE (rel->r_info);
|
||||
switch (r_type)
|
||||
{
|
||||
case R_PPC_GOT_TLSLD16:
|
||||
case R_PPC_GOT_TLSLD16_LO:
|
||||
expecting_tls_get_addr = 1;
|
||||
/* Fall thru */
|
||||
|
||||
/* LD -> LE */
|
||||
tls_set = 0;
|
||||
tls_clear = TLS_LD;
|
||||
expecting_tls_get_addr = 1;
|
||||
break;
|
||||
case R_PPC_GOT_TLSLD16_HI:
|
||||
case R_PPC_GOT_TLSLD16_HA:
|
||||
/* These relocs should never be against a symbol
|
||||
defined in a shared lib. Leave them alone if
|
||||
that turns out to be the case. */
|
||||
if (!is_local)
|
||||
continue;
|
||||
|
||||
case R_PPC_GOT_TLSGD16:
|
||||
case R_PPC_GOT_TLSGD16_LO:
|
||||
case R_PPC_GOT_TLSGD16_HI:
|
||||
case R_PPC_GOT_TLSGD16_HA:
|
||||
if (is_local)
|
||||
/* GD -> LE */
|
||||
/* LD -> LE */
|
||||
tls_set = 0;
|
||||
else
|
||||
/* GD -> IE */
|
||||
tls_set = TLS_TLS | TLS_TPRELGD;
|
||||
tls_clear = TLS_GD;
|
||||
expecting_tls_get_addr = 1;
|
||||
break;
|
||||
tls_clear = TLS_LD;
|
||||
break;
|
||||
|
||||
case R_PPC_GOT_TPREL16:
|
||||
case R_PPC_GOT_TPREL16_LO:
|
||||
case R_PPC_GOT_TPREL16_HI:
|
||||
case R_PPC_GOT_TPREL16_HA:
|
||||
expecting_tls_get_addr = 0;
|
||||
if (is_local)
|
||||
{
|
||||
/* IE -> LE */
|
||||
case R_PPC_GOT_TLSGD16:
|
||||
case R_PPC_GOT_TLSGD16_LO:
|
||||
expecting_tls_get_addr = 1;
|
||||
/* Fall thru */
|
||||
|
||||
case R_PPC_GOT_TLSGD16_HI:
|
||||
case R_PPC_GOT_TLSGD16_HA:
|
||||
if (is_local)
|
||||
/* GD -> LE */
|
||||
tls_set = 0;
|
||||
tls_clear = TLS_TPREL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
else
|
||||
/* GD -> IE */
|
||||
tls_set = TLS_TLS | TLS_TPRELGD;
|
||||
tls_clear = TLS_GD;
|
||||
break;
|
||||
|
||||
case R_PPC_GOT_TPREL16:
|
||||
case R_PPC_GOT_TPREL16_LO:
|
||||
case R_PPC_GOT_TPREL16_HI:
|
||||
case R_PPC_GOT_TPREL16_HA:
|
||||
if (is_local)
|
||||
{
|
||||
/* IE -> LE */
|
||||
tls_set = 0;
|
||||
tls_clear = TLS_TPREL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL14_BRTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN:
|
||||
case R_PPC_REL24:
|
||||
if (expecting_tls_get_addr
|
||||
&& h != NULL
|
||||
&& h == htab->tls_get_addr)
|
||||
{
|
||||
struct plt_entry *ent = find_plt_ent (h, NULL, 0);
|
||||
if (ent != NULL && ent->plt.refcount > 0)
|
||||
ent->plt.refcount -= 1;
|
||||
}
|
||||
expecting_tls_get_addr = 0;
|
||||
continue;
|
||||
if (pass == 0)
|
||||
{
|
||||
if (!expecting_tls_get_addr
|
||||
|| !sec->has_tls_get_addr_call)
|
||||
continue;
|
||||
|
||||
default:
|
||||
expecting_tls_get_addr = 0;
|
||||
continue;
|
||||
}
|
||||
if (rel + 1 < relend
|
||||
&& branch_reloc_hash_match (ibfd, rel + 1,
|
||||
htab->tls_get_addr))
|
||||
continue;
|
||||
|
||||
if (h != NULL)
|
||||
{
|
||||
if (tls_set == 0)
|
||||
{
|
||||
/* We managed to get rid of a got entry. */
|
||||
if (h->got.refcount > 0)
|
||||
h->got.refcount -= 1;
|
||||
}
|
||||
tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf_Internal_Sym *sym;
|
||||
bfd_signed_vma *lgot_refs;
|
||||
char *lgot_masks;
|
||||
/* Uh oh, we didn't find the expected call. We
|
||||
could just mark this symbol to exclude it
|
||||
from tls optimization but it's safer to skip
|
||||
the entire section. */
|
||||
sec->has_tls_reloc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (locsyms == NULL)
|
||||
{
|
||||
locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
|
||||
if (locsyms == NULL)
|
||||
locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
|
||||
symtab_hdr->sh_info,
|
||||
0, NULL, NULL, NULL);
|
||||
if (locsyms == NULL)
|
||||
{
|
||||
if (elf_section_data (sec)->relocs != relstart)
|
||||
free (relstart);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
sym = locsyms + r_symndx;
|
||||
lgot_refs = elf_local_got_refcounts (ibfd);
|
||||
if (lgot_refs == NULL)
|
||||
abort ();
|
||||
if (tls_set == 0)
|
||||
{
|
||||
/* We managed to get rid of a got entry. */
|
||||
if (lgot_refs[r_symndx] > 0)
|
||||
lgot_refs[r_symndx] -= 1;
|
||||
}
|
||||
lgot_masks = (char *) (lgot_refs + symtab_hdr->sh_info);
|
||||
tls_mask = &lgot_masks[r_symndx];
|
||||
}
|
||||
if (h != NULL)
|
||||
{
|
||||
tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
|
||||
got_count = &h->got.refcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf_Internal_Sym *sym;
|
||||
bfd_signed_vma *lgot_refs;
|
||||
char *lgot_masks;
|
||||
|
||||
*tls_mask |= tls_set;
|
||||
*tls_mask &= ~tls_clear;
|
||||
}
|
||||
if (locsyms == NULL)
|
||||
{
|
||||
locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
|
||||
if (locsyms == NULL)
|
||||
locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
|
||||
symtab_hdr->sh_info,
|
||||
0, NULL, NULL, NULL);
|
||||
if (locsyms == NULL)
|
||||
{
|
||||
if (elf_section_data (sec)->relocs != relstart)
|
||||
free (relstart);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
sym = locsyms + r_symndx;
|
||||
lgot_refs = elf_local_got_refcounts (ibfd);
|
||||
if (lgot_refs == NULL)
|
||||
abort ();
|
||||
lgot_masks = (char *) (lgot_refs + symtab_hdr->sh_info);
|
||||
tls_mask = &lgot_masks[r_symndx];
|
||||
got_count = &lgot_refs[r_symndx];
|
||||
}
|
||||
|
||||
if (elf_section_data (sec)->relocs != relstart)
|
||||
free (relstart);
|
||||
if (tls_set == 0)
|
||||
{
|
||||
/* We managed to get rid of a got entry. */
|
||||
if (*got_count > 0)
|
||||
*got_count -= 1;
|
||||
}
|
||||
|
||||
if (expecting_tls_get_addr)
|
||||
{
|
||||
struct plt_entry *ent;
|
||||
|
||||
ent = find_plt_ent (htab->tls_get_addr, NULL, 0);
|
||||
if (ent != NULL && ent->plt.refcount > 0)
|
||||
ent->plt.refcount -= 1;
|
||||
}
|
||||
|
||||
*tls_mask |= tls_set;
|
||||
*tls_mask &= ~tls_clear;
|
||||
}
|
||||
|
||||
if (elf_section_data (sec)->relocs != relstart)
|
||||
free (relstart);
|
||||
}
|
||||
|
||||
if (locsyms != NULL
|
||||
&& (symtab_hdr->contents != (unsigned char *) locsyms))
|
||||
{
|
||||
if (!info->keep_memory)
|
||||
free (locsyms);
|
||||
else
|
||||
symtab_hdr->contents = (unsigned char *) locsyms;
|
||||
}
|
||||
|
||||
if (locsyms != NULL
|
||||
&& (symtab_hdr->contents != (unsigned char *) locsyms))
|
||||
{
|
||||
if (!info->keep_memory)
|
||||
free (locsyms);
|
||||
else
|
||||
symtab_hdr->contents = (unsigned char *) locsyms;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -4615,8 +4748,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
|
||||
if (eh->tls_mask == (TLS_TLS | TLS_LD)
|
||||
&& !eh->elf.def_dynamic)
|
||||
/* If just an LD reloc, we'll just use htab->tlsld_got.offset. */
|
||||
eh->elf.got.offset = (bfd_vma) -1;
|
||||
{
|
||||
/* If just an LD reloc, we'll just use htab->tlsld_got.offset. */
|
||||
htab->tlsld_got.refcount += 1;
|
||||
eh->elf.got.offset = (bfd_vma) -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bfd_boolean dyn;
|
||||
@ -4664,7 +4800,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
if (info->shared)
|
||||
{
|
||||
/* Relocs that use pc_count are those that appear on a call insn,
|
||||
or certain REL relocs (see MUST_BE_DYN_RELOC) that can be
|
||||
or certain REL relocs (see must_be_dyn_reloc) that can be
|
||||
generated via assembly. We want calls to protected symbols to
|
||||
resolve directly to the function rather than going via the plt.
|
||||
If people want function pointer comparisons to work as expected
|
||||
@ -4891,6 +5027,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||
*local_got = (bfd_vma) -1;
|
||||
}
|
||||
|
||||
/* Allocate space for global sym dynamic relocs. */
|
||||
elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
|
||||
|
||||
if (htab->tlsld_got.refcount > 0)
|
||||
{
|
||||
htab->tlsld_got.offset = allocate_got (htab, 8);
|
||||
@ -4900,9 +5039,6 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||
else
|
||||
htab->tlsld_got.offset = (bfd_vma) -1;
|
||||
|
||||
/* Allocate space for global sym dynamic relocs. */
|
||||
elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
|
||||
|
||||
if (htab->got != NULL && htab->plt_type != PLT_VXWORKS)
|
||||
{
|
||||
unsigned int g_o_t = 32768;
|
||||
@ -5754,16 +5890,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
for the final instruction stream. */
|
||||
tls_mask = 0;
|
||||
tls_gd = 0;
|
||||
if (IS_PPC_TLS_RELOC (r_type))
|
||||
if (h != NULL)
|
||||
tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
|
||||
else if (local_got_offsets != NULL)
|
||||
{
|
||||
if (h != NULL)
|
||||
tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
|
||||
else if (local_got_offsets != NULL)
|
||||
{
|
||||
char *lgot_masks;
|
||||
lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
|
||||
tls_mask = lgot_masks[r_symndx];
|
||||
}
|
||||
char *lgot_masks;
|
||||
lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
|
||||
tls_mask = lgot_masks[r_symndx];
|
||||
}
|
||||
|
||||
/* Ensure reloc mapping code below stays sane. */
|
||||
@ -5870,85 +6003,147 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
case R_PPC_GOT_TLSGD16_LO:
|
||||
tls_gd = TLS_TPRELGD;
|
||||
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
|
||||
goto tls_get_addr_check;
|
||||
goto tls_ldgd_opt;
|
||||
break;
|
||||
|
||||
case R_PPC_GOT_TLSLD16:
|
||||
case R_PPC_GOT_TLSLD16_LO:
|
||||
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
|
||||
{
|
||||
tls_get_addr_check:
|
||||
if (rel + 1 < relend)
|
||||
unsigned int insn1, insn2;
|
||||
bfd_vma offset;
|
||||
|
||||
tls_ldgd_opt:
|
||||
offset = (bfd_vma) -1;
|
||||
/* If not using the newer R_PPC_TLSGD/LD to mark
|
||||
__tls_get_addr calls, we must trust that the call
|
||||
stays with its arg setup insns, ie. that the next
|
||||
reloc is the __tls_get_addr call associated with
|
||||
the current reloc. Edit both insns. */
|
||||
if (input_section->has_tls_get_addr_call
|
||||
&& rel + 1 < relend
|
||||
&& branch_reloc_hash_match (input_bfd, rel + 1,
|
||||
htab->tls_get_addr))
|
||||
offset = rel[1].r_offset;
|
||||
if ((tls_mask & tls_gd) != 0)
|
||||
{
|
||||
enum elf_ppc_reloc_type r_type2;
|
||||
unsigned long r_symndx2;
|
||||
struct elf_link_hash_entry *h2;
|
||||
bfd_vma insn1, insn2;
|
||||
bfd_vma offset;
|
||||
|
||||
/* 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))
|
||||
break;
|
||||
|
||||
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)
|
||||
break;
|
||||
|
||||
/* OK, it checks out. Replace the call. */
|
||||
offset = rel[1].r_offset;
|
||||
/* IE */
|
||||
insn1 = bfd_get_32 (output_bfd,
|
||||
contents + rel->r_offset - d_offset);
|
||||
if ((tls_mask & tls_gd) != 0)
|
||||
insn1 &= (1 << 26) - 1;
|
||||
insn1 |= 32 << 26; /* lwz */
|
||||
if (offset != (bfd_vma) -1)
|
||||
{
|
||||
/* IE */
|
||||
insn1 &= (1 << 26) - 1;
|
||||
insn1 |= 32 << 26; /* lwz */
|
||||
rel[1].r_info
|
||||
= ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
|
||||
R_PPC_NONE);
|
||||
insn2 = 0x7c631214; /* add 3,3,2 */
|
||||
rel[1].r_info = ELF32_R_INFO (r_symndx2, 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);
|
||||
bfd_put_32 (output_bfd, insn2, contents + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* LE */
|
||||
insn1 = 0x3c620000; /* addis 3,2,0 */
|
||||
insn2 = 0x38630000; /* addi 3,3,0 */
|
||||
if (tls_gd == 0)
|
||||
{
|
||||
/* Was an LD reloc. */
|
||||
r_symndx = 0;
|
||||
rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
|
||||
}
|
||||
r_type = R_PPC_TPREL16_HA;
|
||||
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
|
||||
rel[1].r_info = ELF32_R_INFO (r_symndx,
|
||||
R_PPC_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);
|
||||
bfd_put_32 (output_bfd, insn2, contents + offset);
|
||||
r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
|
||||
+ R_PPC_GOT_TPREL16);
|
||||
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* LE */
|
||||
insn1 = 0x3c620000; /* addis 3,2,0 */
|
||||
if (tls_gd == 0)
|
||||
{
|
||||
/* We changed the symbol on an LD reloc. Start over
|
||||
in order to get h, sym, sec etc. right. */
|
||||
rel--;
|
||||
continue;
|
||||
/* Was an LD reloc. */
|
||||
for (r_symndx = 0;
|
||||
r_symndx < symtab_hdr->sh_info;
|
||||
r_symndx++)
|
||||
if (local_sections[r_symndx] == sec)
|
||||
break;
|
||||
if (r_symndx >= symtab_hdr->sh_info)
|
||||
r_symndx = 0;
|
||||
rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
|
||||
if (r_symndx != 0)
|
||||
rel->r_addend -= (local_syms[r_symndx].st_value
|
||||
+ sec->output_offset
|
||||
+ sec->output_section->vma);
|
||||
}
|
||||
r_type = R_PPC_TPREL16_HA;
|
||||
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
|
||||
if (offset != (bfd_vma) -1)
|
||||
{
|
||||
rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
|
||||
rel[1].r_offset = offset + d_offset;
|
||||
rel[1].r_addend = rel->r_addend;
|
||||
insn2 = 0x38630000; /* addi 3,3,0 */
|
||||
bfd_put_32 (output_bfd, insn2, contents + offset);
|
||||
}
|
||||
}
|
||||
bfd_put_32 (output_bfd, insn1,
|
||||
contents + rel->r_offset - d_offset);
|
||||
if (tls_gd == 0)
|
||||
{
|
||||
/* We changed the symbol on an LD reloc. Start over
|
||||
in order to get h, sym, sec etc. right. */
|
||||
rel--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case R_PPC_TLSGD:
|
||||
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
|
||||
{
|
||||
unsigned int insn2;
|
||||
bfd_vma offset = rel->r_offset;
|
||||
|
||||
if ((tls_mask & TLS_TPRELGD) != 0)
|
||||
{
|
||||
/* IE */
|
||||
r_type = R_PPC_NONE;
|
||||
insn2 = 0x7c631214; /* add 3,3,2 */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* LE */
|
||||
r_type = R_PPC_TPREL16_LO;
|
||||
rel->r_offset += d_offset;
|
||||
insn2 = 0x38630000; /* addi 3,3,0 */
|
||||
}
|
||||
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
|
||||
bfd_put_32 (output_bfd, insn2, contents + offset);
|
||||
/* Zap the reloc on the _tls_get_addr call too. */
|
||||
BFD_ASSERT (offset == rel[1].r_offset);
|
||||
rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
|
||||
R_PPC_NONE);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_PPC_TLSLD:
|
||||
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
|
||||
{
|
||||
unsigned int insn2;
|
||||
|
||||
for (r_symndx = 0;
|
||||
r_symndx < symtab_hdr->sh_info;
|
||||
r_symndx++)
|
||||
if (local_sections[r_symndx] == sec)
|
||||
break;
|
||||
if (r_symndx >= symtab_hdr->sh_info)
|
||||
r_symndx = 0;
|
||||
rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
|
||||
if (r_symndx != 0)
|
||||
rel->r_addend -= (local_syms[r_symndx].st_value
|
||||
+ sec->output_offset
|
||||
+ sec->output_section->vma);
|
||||
|
||||
rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
|
||||
rel->r_offset += d_offset;
|
||||
insn2 = 0x38630000; /* addi 3,3,0 */
|
||||
bfd_put_32 (output_bfd, insn2,
|
||||
contents + rel->r_offset - d_offset);
|
||||
/* Zap the reloc on the _tls_get_addr call too. */
|
||||
BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
|
||||
rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
|
||||
R_PPC_NONE);
|
||||
rel--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -6003,6 +6198,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
|
||||
case R_PPC_NONE:
|
||||
case R_PPC_TLS:
|
||||
case R_PPC_TLSGD:
|
||||
case R_PPC_TLSLD:
|
||||
case R_PPC_EMB_MRKREF:
|
||||
case R_PPC_GNU_VTINHERIT:
|
||||
case R_PPC_GNU_VTENTRY:
|
||||
@ -6044,6 +6241,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
case R_PPC_GOT16_LO:
|
||||
case R_PPC_GOT16_HI:
|
||||
case R_PPC_GOT16_HA:
|
||||
tls_mask = 0;
|
||||
dogot:
|
||||
{
|
||||
/* Relocation is to the entry for this symbol in the global
|
||||
@ -6342,7 +6540,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
&& (h == NULL
|
||||
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
||||
|| h->root.type != bfd_link_hash_undefweak)
|
||||
&& (MUST_BE_DYN_RELOC (r_type)
|
||||
&& (must_be_dyn_reloc (info, r_type)
|
||||
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
||||
|| (ELIMINATE_COPY_RELOCS
|
||||
&& !info->shared
|
||||
@ -6411,10 +6609,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||
outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
|
||||
else
|
||||
{
|
||||
long indx;
|
||||
long indx = 0;
|
||||
|
||||
if (bfd_is_abs_section (sec))
|
||||
indx = 0;
|
||||
if (r_symndx == 0 || bfd_is_abs_section (sec))
|
||||
;
|
||||
else if (sec == NULL || sec->owner == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1169,6 +1169,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
|
||||
"BFD_RELOC_PPC64_PLTGOT16_DS",
|
||||
"BFD_RELOC_PPC64_PLTGOT16_LO_DS",
|
||||
"BFD_RELOC_PPC_TLS",
|
||||
"BFD_RELOC_PPC_TLSGD",
|
||||
"BFD_RELOC_PPC_TLSLD",
|
||||
"BFD_RELOC_PPC_DTPMOD",
|
||||
"BFD_RELOC_PPC_TPREL16",
|
||||
"BFD_RELOC_PPC_TPREL16_LO",
|
||||
|
@ -2626,6 +2626,10 @@ ENUMDOC
|
||||
|
||||
ENUM
|
||||
BFD_RELOC_PPC_TLS
|
||||
ENUMX
|
||||
BFD_RELOC_PPC_TLSGD
|
||||
ENUMX
|
||||
BFD_RELOC_PPC_TLSLD
|
||||
ENUMX
|
||||
BFD_RELOC_PPC_DTPMOD
|
||||
ENUMX
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Object file "section" support for the BFD library.
|
||||
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
||||
Free Software Foundation, Inc.
|
||||
Written by Cygnus Support.
|
||||
|
||||
@ -382,6 +382,9 @@ CODE_FRAGMENT
|
||||
. {* Nonzero if this section has TLS related relocations. *}
|
||||
. unsigned int has_tls_reloc:1;
|
||||
.
|
||||
. {* Nonzero if this section has a call to __tls_get_addr. *}
|
||||
. unsigned int has_tls_get_addr_call:1;
|
||||
.
|
||||
. {* Nonzero if this section has a gp reloc. *}
|
||||
. unsigned int has_gp_reloc:1;
|
||||
.
|
||||
@ -642,11 +645,11 @@ CODE_FRAGMENT
|
||||
. {* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, *} \
|
||||
. 0, 0, 0, 0, \
|
||||
. \
|
||||
. {* has_gp_reloc, need_finalize_relax, reloc_done, *} \
|
||||
. 0, 0, 0, \
|
||||
. {* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax, *} \
|
||||
. 0, 0, 0, \
|
||||
. \
|
||||
. {* vma, lma, size, rawsize *} \
|
||||
. 0, 0, 0, 0, \
|
||||
. {* reloc_done, vma, lma, size, rawsize *} \
|
||||
. 0, 0, 0, 0, 0, \
|
||||
. \
|
||||
. {* output_offset, output_section, alignment_power, *} \
|
||||
. 0, (struct bfd_section *) &SEC, 0, \
|
||||
|
@ -1,3 +1,8 @@
|
||||
2009-03-04 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* ppc.h (R_PPC_TLSGD, R_PPC_TLSLD): Add new relocs.
|
||||
* ppc64.h (R_PPC64_TLSGD, R_PPC64_TLSLD): Add new relocs.
|
||||
|
||||
2007-06-29 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* ppc.h (Tag_GNU_Power_ABI_FP): Define.
|
||||
|
@ -100,6 +100,8 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
|
||||
RELOC_NUMBER (R_PPC_GOT_DTPREL16_LO, 92)
|
||||
RELOC_NUMBER (R_PPC_GOT_DTPREL16_HI, 93)
|
||||
RELOC_NUMBER (R_PPC_GOT_DTPREL16_HA, 94)
|
||||
RELOC_NUMBER (R_PPC_TLSGD, 95)
|
||||
RELOC_NUMBER (R_PPC_TLSLD, 96)
|
||||
|
||||
/* The remaining relocs are from the Embedded ELF ABI, and are not
|
||||
in the SVR4 ELF ABI. */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* PPC64 ELF support for BFD.
|
||||
Copyright 2003 Free Software Foundation, Inc.
|
||||
Copyright 2003, 2005, 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of BFD, the Binary File Descriptor library.
|
||||
|
||||
@ -136,6 +136,8 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_type)
|
||||
RELOC_NUMBER (R_PPC64_DTPREL16_HIGHERA, 104)
|
||||
RELOC_NUMBER (R_PPC64_DTPREL16_HIGHEST, 105)
|
||||
RELOC_NUMBER (R_PPC64_DTPREL16_HIGHESTA, 106)
|
||||
RELOC_NUMBER (R_PPC64_TLSGD, 107)
|
||||
RELOC_NUMBER (R_PPC64_TLSLD, 108)
|
||||
|
||||
/* These are GNU extensions to enable C++ vtable garbage collection. */
|
||||
RELOC_NUMBER (R_PPC64_GNU_VTINHERIT, 253)
|
||||
|
@ -1386,6 +1386,9 @@ typedef struct bfd_section
|
||||
/* Nonzero if this section has TLS related relocations. */
|
||||
unsigned int has_tls_reloc:1;
|
||||
|
||||
/* Nonzero if this section has a call to __tls_get_addr. */
|
||||
unsigned int has_tls_get_addr_call:1;
|
||||
|
||||
/* Nonzero if this section has a gp reloc. */
|
||||
unsigned int has_gp_reloc:1;
|
||||
|
||||
@ -1646,11 +1649,11 @@ extern asection bfd_ind_section;
|
||||
/* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */ \
|
||||
0, 0, 0, 0, \
|
||||
\
|
||||
/* has_gp_reloc, need_finalize_relax, reloc_done, */ \
|
||||
0, 0, 0, \
|
||||
/* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax, */ \
|
||||
0, 0, 0, \
|
||||
\
|
||||
/* vma, lma, size, rawsize */ \
|
||||
0, 0, 0, 0, \
|
||||
/* reloc_done, vma, lma, size, rawsize */ \
|
||||
0, 0, 0, 0, 0, \
|
||||
\
|
||||
/* output_offset, output_section, alignment_power, */ \
|
||||
0, (struct bfd_section *) &SEC, 0, \
|
||||
@ -2903,6 +2906,8 @@ in the instruction. */
|
||||
|
||||
/* PowerPC and PowerPC64 thread-local storage relocations. */
|
||||
BFD_RELOC_PPC_TLS,
|
||||
BFD_RELOC_PPC_TLSGD,
|
||||
BFD_RELOC_PPC_TLSLD,
|
||||
BFD_RELOC_PPC_DTPMOD,
|
||||
BFD_RELOC_PPC_TPREL16,
|
||||
BFD_RELOC_PPC_TPREL16_LO,
|
||||
|
Loading…
x
Reference in New Issue
Block a user