/* PowerPC64-specific support for 64-bit ELF.
- Copyright (C) 1999-2019 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 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.
#include "elf64-ppc.h"
#include "dwarf2.h"
+/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */
+#define OCTETS_PER_BYTE(ABFD, SEC) 1
+
static bfd_reloc_status_type ppc64_elf_ha_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type ppc64_elf_branch_reloc
#define elf_backend_finish_dynamic_sections ppc64_elf_finish_dynamic_sections
#define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook
#define elf_backend_special_sections ppc64_elf_special_sections
+#define elf_backend_section_flags ppc64_elf_section_flags
#define elf_backend_merge_symbol_attribute ppc64_elf_merge_symbol_attribute
#define elf_backend_merge_symbol ppc64_elf_merge_symbol
#define elf_backend_get_reloc_section bfd_get_section_by_name
HOW (R_PPC64_PLT_PCREL34_NOTOC, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
ppc64_elf_unhandled_reloc),
+ HOW (R_PPC64_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_TLSGD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_TLSLD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
+ HOW (R_PPC64_GOT_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+ ppc64_elf_unhandled_reloc),
+
HOW (R_PPC64_ADDR16_HIGHER34, 1, 16, 0xffff, 34, FALSE, dont,
bfd_elf_generic_reloc),
break;
case BFD_RELOC_PPC64_PLTGOT16_LO_DS: r = R_PPC64_PLTGOT16_LO_DS;
break;
+ case BFD_RELOC_PPC64_TLS_PCREL:
case BFD_RELOC_PPC_TLS: r = R_PPC64_TLS;
break;
case BFD_RELOC_PPC_TLSGD: r = R_PPC64_TLSGD;
break;
case BFD_RELOC_PPC64_PLT_PCREL34: r = R_PPC64_PLT_PCREL34;
break;
+ case BFD_RELOC_PPC64_TPREL34: r = R_PPC64_TPREL34;
+ break;
+ case BFD_RELOC_PPC64_DTPREL34: r = R_PPC64_DTPREL34;
+ break;
+ case BFD_RELOC_PPC64_GOT_TLSGD34: r = R_PPC64_GOT_TLSGD34;
+ break;
+ case BFD_RELOC_PPC64_GOT_TLSLD34: r = R_PPC64_GOT_TLSLD34;
+ break;
+ case BFD_RELOC_PPC64_GOT_TPREL34: r = R_PPC64_GOT_TPREL34;
+ break;
+ case BFD_RELOC_PPC64_GOT_DTPREL34: r = R_PPC64_GOT_DTPREL34;
+ break;
case BFD_RELOC_PPC64_ADDR16_HIGHER34: r = R_PPC64_ADDR16_HIGHER34;
break;
case BFD_RELOC_PPC64_ADDR16_HIGHERA34: r = R_PPC64_ADDR16_HIGHERA34;
+ input_section->output_section->vma);
value = (bfd_signed_vma) value >> 16;
- octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
insn &= ~0x1fffc1;
insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
- octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
insn &= ~(0x01 << 21);
r_type = reloc_entry->howto->type;
if (TOCstart == 0)
TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
- octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
return bfd_reloc_ok;
}
instruction not one we handle. */
unsigned int unexpected_toc_insn : 1;
- /* Set if got relocs that can be optimised are present in this file. */
- unsigned int has_gotrel : 1;
+ /* Set if PLT/GOT/TOC relocs that can be optimised are present in
+ this file. */
+ unsigned int has_optrel : 1;
};
#define ppc64_elf_tdata(bfd) \
/* Flag set when PLTCALL relocs are detected. */
unsigned int has_pltcall:1;
- /* Flag set when section has GOT relocations that can be optimised. */
- unsigned int has_gotrel:1;
+ /* Flag set when section has PLT/GOT/TOC relocations that can be
+ optimised. */
+ unsigned int has_optrel:1;
};
#define ppc64_elf_section_data(sec) \
if (!sec->used_by_bfd)
{
struct _ppc64_elf_section_data *sdata;
- bfd_size_type amt = sizeof (*sdata);
+ size_t amt = sizeof (*sdata);
sdata = bfd_zalloc (abfd, amt);
if (sdata == NULL)
return _bfd_elf_new_section_hook (abfd, sec);
}
+static bfd_boolean
+ppc64_elf_section_flags (const Elf_Internal_Shdr *hdr)
+{
+ const char *name = hdr->bfd_section->name;
+
+ if (strncmp (name, ".sbss", 5) == 0
+ || strncmp (name, ".sdata", 6) == 0)
+ hdr->bfd_section->flags |= SEC_SMALL_DATA;
+
+ return TRUE;
+}
+
static struct _opd_sec_data *
get_opd_info (asection * sec)
{
if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
return 1;
- return a > b;
+ /* Finally, sort on where the symbol is in memory. The symbols will
+ be in at most two malloc'd blocks, one for static syms, one for
+ dynamic syms, and we distinguish the two blocks above by testing
+ BSF_DYNAMIC. Since we are sorting the symbol pointers which were
+ originally in the same order as the symbols (and we're not
+ sorting the symbols themselves), this ensures a stable sort. */
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
}
/* Search SYMS for a symbol of the given VALUE. */
static asymbol *
-sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value)
+sym_exists_at (asymbol **syms, size_t lo, size_t hi, unsigned int id,
+ bfd_vma value)
{
- long mid;
+ size_t mid;
if (id == (unsigned) -1)
{
free_contents_and_exit_err:
count = -1;
free_contents_and_exit:
- if (contents)
- free (contents);
+ free (contents);
goto done;
}
case R_PPC64_REL32:
case R_PPC64_REL64:
case R_PPC64_REL30:
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_LO_DS:
return 0;
case R_PPC64_TPREL16:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
case R_PPC64_TPREL64:
+ case R_PPC64_TPREL34:
/* These relocations are relative but in a shared library the
linker doesn't know the thread pointer base. */
return bfd_link_dll (info);
}
/* 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
+ copying dynamic variables from a shared lib into an app's .dynbss
section, and instead use a dynamic relocation to point into the
- shared lib. With code that gcc generates, it's vital that this be
- enabled; In the PowerPC64 ABI, the address of a function is actually
- the address of a function descriptor, which resides in the .opd
- section. gcc uses the descriptor directly rather than going via the
- GOT as some other ABI's do, which means that initialized function
- pointers must reference the descriptor. Thus, a function pointer
- initialized to the address of a function in a shared library will
- either require a copy reloc, or a dynamic reloc. Using a copy reloc
- redefines the function descriptor symbol to point to the copy. This
- presents a problem as a plt entry for that function is also
- initialized from the function descriptor symbol and the copy reloc
- may not be initialized first. */
+ shared lib. With code that gcc generates it is vital that this be
+ enabled; In the PowerPC64 ELFv1 ABI the address of a function is
+ actually the address of a function descriptor which resides in the
+ .opd section. gcc uses the descriptor directly rather than going
+ via the GOT as some other ABIs do, which means that initialized
+ function pointers reference the descriptor. Thus, a function
+ pointer initialized to the address of a function in a shared
+ library will either require a .dynbss copy and a copy reloc, or a
+ dynamic reloc. Using a .dynbss copy redefines the function
+ descriptor symbol to point to the copy. This presents a problem as
+ a PLT entry for that function is also initialized from the function
+ descriptor symbol and the copy may not be initialized first. */
#define ELIMINATE_COPY_RELOCS 1
/* Section name for stubs is the associated section name plus this
ppc_stub_plt_branch:
Similar to the above, but a 24 bit branch in the stub section won't
reach its destination.
- . addis %r11,%r2,xxx@toc@ha
- . ld %r12,xxx@toc@l(%r11)
+ . addis %r12,%r2,xxx@toc@ha
+ . ld %r12,xxx@toc@l(%r12)
. mtctr %r12
. bctr
A ppc_stub_plt_branch with an r2 offset looks like:
. std %r2,40(%r1)
- . addis %r11,%r2,xxx@toc@ha
- . ld %r12,xxx@toc@l(%r11)
+ . addis %r12,%r2,xxx@toc@ha
+ . ld %r12,xxx@toc@l(%r12)
. addis %r2,%r2,off@ha
. addi %r2,%r2,off@l
. mtctr %r12
. mtctr %r12
. bctr
- There are also ELFv1 powerxx variants of these stubs.
+ There are also ELFv1 power10 variants of these stubs.
ppc_stub_long_branch_notoc:
. pla %r12,dest@pcrel
. b dest
In cases where the high instructions would add zero, they are
omitted and following instructions modified in some cases.
- For example, a powerxx ppc_stub_plt_call_notoc might simplify down
+ For example, a power10 ppc_stub_plt_call_notoc might simplify down
to
. pld %r12,xxx@pcrel
. mtctr %r12
#define NON_GOT 256 /* local symbol plt, not stored. */
};
+static inline struct ppc_link_hash_entry *
+ppc_elf_hash_entry (struct elf_link_hash_entry *ent)
+{
+ return (struct ppc_link_hash_entry *) ent;
+}
+
/* ppc64 ELF linker hash table. */
struct ppc_link_hash_table
/* Shortcut to .__tls_get_addr and __tls_get_addr. */
struct ppc_link_hash_entry *tls_get_addr;
struct ppc_link_hash_entry *tls_get_addr_fd;
+ struct ppc_link_hash_entry *tga_desc;
+ struct ppc_link_hash_entry *tga_desc_fd;
+ struct map_stub *tga_group;
/* The size of reliplt used by got entry relocs. */
bfd_size_type got_reli_size;
/* Whether calls are made via the PLT from NOTOC functions. */
unsigned int notoc_plt:1;
- /* Whether to use powerxx instructions in linkage stubs. */
- unsigned int powerxx_stubs:1;
+ /* Whether to use power10 instructions in linkage stubs. */
+ unsigned int power10_stubs:1;
/* Incremented every time we size stubs. */
unsigned int stub_iteration;
/* Nonzero if this section has TLS related relocations. */
#define has_tls_reloc sec_flg0
-/* Nonzero if this section has an old-style call to __tls_get_addr. */
-#define has_tls_get_addr_call sec_flg1
+/* Nonzero if this section has a call to __tls_get_addr lacking marker
+ relocations. */
+#define nomark_tls_get_addr sec_flg1
/* Nonzero if this section has any toc or got relocs. */
#define has_toc_reloc sec_flg2
ppc64_elf_link_hash_table_create (bfd *abfd)
{
struct ppc_link_hash_table *htab;
- bfd_size_type amt = sizeof (struct ppc_link_hash_table);
+ size_t amt = sizeof (struct ppc_link_hash_table);
htab = bfd_zmalloc (amt);
if (htab == NULL)
htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
flags);
if (htab->sfpr == NULL
- || !bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+ || !bfd_set_section_alignment (htab->sfpr, 2))
return FALSE;
}
htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
flags);
if (htab->glink == NULL
- || !bfd_set_section_alignment (dynobj, htab->glink, 3))
+ || !bfd_set_section_alignment (htab->glink, 3))
return FALSE;
/* The part of .glink used by global entry stubs, separate so that
htab->global_entry = bfd_make_section_anyway_with_flags (dynobj, ".glink",
flags);
if (htab->global_entry == NULL
- || !bfd_set_section_alignment (dynobj, htab->global_entry, 2))
+ || !bfd_set_section_alignment (htab->global_entry, 2))
return FALSE;
if (!info->no_ld_generated_unwind_info)
".eh_frame",
flags);
if (htab->glink_eh_frame == NULL
- || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
+ || !bfd_set_section_alignment (htab->glink_eh_frame, 2))
return FALSE;
}
flags = SEC_ALLOC | SEC_LINKER_CREATED;
htab->elf.iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
if (htab->elf.iplt == NULL
- || !bfd_set_section_alignment (dynobj, htab->elf.iplt, 3))
+ || !bfd_set_section_alignment (htab->elf.iplt, 3))
return FALSE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
htab->elf.irelplt
= bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags);
if (htab->elf.irelplt == NULL
- || !bfd_set_section_alignment (dynobj, htab->elf.irelplt, 3))
+ || !bfd_set_section_alignment (htab->elf.irelplt, 3))
return FALSE;
/* Create branch lookup table for plt_branch stubs. */
htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
flags);
if (htab->brlt == NULL
- || !bfd_set_section_alignment (dynobj, htab->brlt, 3))
+ || !bfd_set_section_alignment (htab->brlt, 3))
return FALSE;
/* Local plt entries, put in .branch_lt but a separate section for
htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
flags);
if (htab->pltlocal == NULL
- || !bfd_set_section_alignment (dynobj, htab->pltlocal, 3))
+ || !bfd_set_section_alignment (htab->pltlocal, 3))
return FALSE;
if (!bfd_link_pic (info))
htab->relbrlt
= bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
if (htab->relbrlt == NULL
- || !bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
+ || !bfd_set_section_alignment (htab->relbrlt, 3))
return FALSE;
htab->relpltlocal
= bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
if (htab->relpltlocal == NULL
- || !bfd_set_section_alignment (dynobj, htab->relpltlocal, 3))
+ || !bfd_set_section_alignment (htab->relpltlocal, 3))
return FALSE;
return TRUE;
got = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (!got
- || !bfd_set_section_alignment (abfd, got, 3))
+ || !bfd_set_section_alignment (got, 3))
return FALSE;
relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got",
flags | SEC_READONLY);
if (!relgot
- || !bfd_set_section_alignment (abfd, relgot, 3))
+ || !bfd_set_section_alignment (relgot, 3))
return FALSE;
ppc64_elf_tdata (abfd)->got = got;
static inline struct ppc_link_hash_entry *
ppc_follow_link (struct ppc_link_hash_entry *h)
{
- return (struct ppc_link_hash_entry *) follow_link (&h->elf.root);
+ return ppc_elf_hash_entry (elf_follow_link (&h->elf));
}
/* Merge PLT info on FROM with that on TO. */
{
struct ppc_link_hash_entry *edir, *eind;
- edir = (struct ppc_link_hash_entry *) dir;
- eind = (struct ppc_link_hash_entry *) ind;
+ edir = ppc_elf_hash_entry (dir);
+ eind = ppc_elf_hash_entry (ind);
edir->is_func |= eind->is_func;
edir->is_func_descriptor |= eind->is_func_descriptor;
{
const char *fd_name = fh->elf.root.root.string + 1;
- fdh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
+ fdh = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, fd_name,
+ FALSE, FALSE, FALSE));
if (fdh == NULL)
return fdh;
bfd *oldbfd ATTRIBUTE_UNUSED,
const asection *oldsec ATTRIBUTE_UNUSED)
{
- ((struct ppc_link_hash_entry *) h)->fake = 0;
+ ppc_elf_hash_entry (h)->fake = 0;
if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0)
- ((struct ppc_link_hash_entry *) h)->non_zero_localentry = 1;
+ ppc_elf_hash_entry (h)->non_zero_localentry = 1;
return TRUE;
}
if (h != NULL
/* Don't return this sym if it is a fake function descriptor
created by add_symbol_adjust. */
- && !((struct ppc_link_hash_entry *) h)->fake)
+ && !ppc_elf_hash_entry (h)->fake)
return h;
if (name[0] == '.')
memcpy (dot_name + 1, name, len + 1);
h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name);
bfd_release (abfd, dot_name);
+ if (h != NULL)
+ return h;
+
+ if (strcmp (name, "__tls_get_addr_opt") == 0)
+ h = _bfd_elf_archive_symbol_lookup (abfd, info, "__tls_get_addr_desc");
return h;
}
break;
if (ent == NULL)
{
- bfd_size_type amt = sizeof (*ent);
+ size_t amt = sizeof (*ent);
ent = bfd_alloc (abfd, amt);
if (ent == NULL)
return FALSE;
break;
if (ent == NULL)
{
- bfd_size_type amt = sizeof (*ent);
+ size_t amt = sizeof (*ent);
ent = bfd_alloc (abfd, amt);
if (ent == NULL)
return FALSE;
int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
struct plt_entry **ifunc, **plt_list;
- bfd_vma sym_addend;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
sec->has_toc_reloc = 1;
}
- tls_type = 0;
- ifunc = NULL;
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
case R_PPC64_D34_HI30:
case R_PPC64_D34_HA30:
case R_PPC64_D28:
- htab->powerxx_stubs = 1;
- /* Fall through. */
- default:
- /* Somewhat foolishly, because the ABIs don't specifically
- allow it, ppc64 gas and ld support GOT and PLT relocs
- with non-zero addends where the addend results in
- sym+addend being stored in the GOT or PLT entry. This
- can't be supported for pcrel relocs because the addend is
- used to specify the pcrel offset. */
- sym_addend = rel->r_addend;
- break;
-
+ case R_PPC64_TPREL34:
+ case R_PPC64_DTPREL34:
case R_PPC64_PCREL34:
case R_PPC64_GOT_PCREL34:
+ case R_PPC64_GOT_TLSGD34:
+ case R_PPC64_GOT_TLSLD34:
+ case R_PPC64_GOT_TPREL34:
+ case R_PPC64_GOT_DTPREL34:
case R_PPC64_PLT_PCREL34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PCREL28:
- htab->powerxx_stubs = 1;
- sym_addend = 0;
+ htab->power10_stubs = 1;
+ break;
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case R_PPC64_PLT16_HA:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_PLT16_LO:
+ case R_PPC64_PLT16_LO_DS:
+ case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_GOT_PCREL34:
+ ppc64_elf_tdata (abfd)->has_optrel = 1;
+ ppc64_elf_section_data (sec)->has_optrel = 1;
+ break;
+ default:
break;
}
+
+ ifunc = NULL;
if (h != NULL)
{
if (h->type == STT_GNU_IFUNC)
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | PLT_IFUNC);
if (ifunc == NULL)
return FALSE;
}
}
+ tls_type = 0;
switch (r_type)
{
case R_PPC64_TLSGD:
/* These special tls relocs tie a call to __tls_get_addr with
its parameter symbol. */
if (h != NULL)
- ((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK;
+ ppc_elf_hash_entry (h)->tls_mask |= TLS_TLS | TLS_MARK;
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | TLS_TLS | TLS_MARK))
return FALSE;
sec->has_tls_reloc = 1;
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD34:
tls_type = TLS_TLS | TLS_LD;
goto dogottls;
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD34:
tls_type = TLS_TLS | TLS_GD;
goto dogottls;
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL34:
if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
tls_type = TLS_TLS | TLS_TPREL;
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL34:
tls_type = TLS_TLS | TLS_DTPREL;
dogottls:
sec->has_tls_reloc = 1;
goto dogot;
+ case R_PPC64_GOT16:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_HI:
case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT16_DS:
case R_PPC64_GOT16_LO_DS:
case R_PPC64_GOT_PCREL34:
- ppc64_elf_tdata (abfd)->has_gotrel = 1;
- ppc64_elf_section_data (sec)->has_gotrel = 1;
- /* Fall through. */
-
- case R_PPC64_GOT16_DS:
- case R_PPC64_GOT16:
- case R_PPC64_GOT16_HI:
- case R_PPC64_GOT16_LO:
dogot:
/* This symbol requires a global offset table entry. */
sec->has_toc_reloc = 1;
struct ppc_link_hash_entry *eh;
struct got_entry *ent;
- eh = (struct ppc_link_hash_entry *) h;
+ eh = ppc_elf_hash_entry (h);
for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == rel->r_addend
&& ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
{
- bfd_size_type amt = sizeof (*ent);
+ size_t amt = sizeof (*ent);
ent = bfd_alloc (abfd, amt);
if (ent == NULL)
return FALSE;
ent->next = eh->elf.got.glist;
- ent->addend = sym_addend;
+ ent->addend = rel->r_addend;
ent->owner = abfd;
ent->tls_type = tls_type;
ent->is_indirect = FALSE;
else
/* This is a global offset table entry for a local symbol. */
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend, tls_type))
+ rel->r_addend, tls_type))
return FALSE;
-
- /* We may also need a plt entry if the symbol turns out to be
- an ifunc. */
- if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
- {
- if (!update_plt_info (abfd, &h->plt.plist, sym_addend))
- return FALSE;
- }
break;
case R_PPC64_PLT16_HA:
h->needs_plt = 1;
if (h->root.root.string[0] == '.'
&& h->root.root.string[1] != '\0')
- ((struct ppc_link_hash_entry *) h)->is_func = 1;
- ((struct ppc_link_hash_entry *) h)->tls_mask |= PLT_KEEP;
+ ppc_elf_hash_entry (h)->is_func = 1;
+ ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP;
plt_list = &h->plt.plist;
}
if (plt_list == NULL)
plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | PLT_KEEP);
- if (!update_plt_info (abfd, plt_list, sym_addend))
+ if (!update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE;
break;
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_LO_DS:
sec->has_toc_reloc = 1;
+ if (h != NULL && bfd_link_executable (info))
+ {
+ /* We may need a copy reloc. */
+ h->non_got_ref = 1;
+ /* Strongly prefer a copy reloc over a dynamic reloc.
+ glibc ld.so as of 2019-08 will error out if one of
+ these relocations is emitted. */
+ h->needs_copy = 1;
+ goto dodyn;
+ }
break;
/* Marker reloc. */
h->needs_plt = 1;
if (h->root.root.string[0] == '.'
&& h->root.root.string[1] != '\0')
- ((struct ppc_link_hash_entry *) h)->is_func = 1;
+ ppc_elf_hash_entry (h)->is_func = 1;
if (h == tga || h == dottga)
{
;
else
/* Mark this section as having an old-style call. */
- sec->has_tls_get_addr_call = 1;
+ sec->nomark_tls_get_addr = 1;
}
plt_list = &h->plt.plist;
}
/* We may need a .plt entry if the function this reloc
refers to is in a shared lib. */
if (plt_list
- && !update_plt_info (abfd, plt_list, sym_addend))
+ && !update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE;
break;
dotlstoc:
sec->has_tls_reloc = 1;
if (h != NULL)
- {
- struct ppc_link_hash_entry *eh;
- eh = (struct ppc_link_hash_entry *) h;
- eh->tls_mask |= tls_type & 0xff;
- }
+ ppc_elf_hash_entry (h)->tls_mask |= tls_type & 0xff;
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend, tls_type))
+ rel->r_addend, tls_type))
return FALSE;
ppc64_sec = ppc64_elf_section_data (sec);
}
BFD_ASSERT (rel->r_offset % 8 == 0);
ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
- ppc64_sec->u.toc.add[rel->r_offset / 8] = sym_addend;
+ 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. */
case R_PPC64_TPREL16_HIGHERA:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
+ case R_PPC64_TPREL34:
if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
&& ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC)
{
if (h != NULL)
- ((struct ppc_link_hash_entry *) h)->is_func = 1;
+ ppc_elf_hash_entry (h)->is_func = 1;
}
/* Fall through. */
case R_PPC64_UADDR32:
case R_PPC64_UADDR64:
case R_PPC64_TOC:
- if (h != NULL && !bfd_link_pic (info))
+ if (h != NULL && bfd_link_executable (info))
/* We may need a copy reloc. */
h->non_got_ref = 1;
dynamic library if we manage to avoid copy relocs for the
symbol. */
dodyn:
- if ((bfd_link_pic (info)
- && (must_be_dyn_reloc (info, r_type)
- || (h != NULL
- && (!SYMBOLIC_BIND (info, h)
- || h->root.type == bfd_link_hash_defweak
- || !h->def_regular))))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && (h->root.type == bfd_link_hash_defweak
- || !h->def_regular))
+ if ((h != NULL
+ && (h->root.type == bfd_link_hash_defweak
+ || !h->def_regular))
+ || (h != NULL
+ && !bfd_link_executable (info)
+ && !SYMBOLIC_BIND (info, h))
+ || (bfd_link_pic (info)
+ && must_be_dyn_reloc (info, r_type))
|| (!bfd_link_pic (info)
&& ifunc != NULL))
{
struct elf_dyn_relocs *p;
struct elf_dyn_relocs **head;
- head = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+ head = &ppc_elf_hash_entry (h)->dyn_relocs;
p = *head;
if (p == NULL || p->sec != sec)
{
&& h->type == STT_FUNC
&& h->root.type == bfd_link_hash_defined
&& (STO_PPC64_LOCAL_MASK & h->other) == 0
- && !((struct ppc_link_hash_entry *) h)->non_zero_localentry
+ && !ppc_elf_hash_entry (h)->non_zero_localentry
&& is_ppc64_elf (h->root.u.def.section->owner)
&& abiversion (h->root.u.def.section->owner) >= 2);
}
return NULL;
}
+/* Given H is a symbol that satisfies is_static_defined, return the
+ value in the output file. */
+
+static bfd_vma
+defined_sym_val (struct elf_link_hash_entry *h)
+{
+ return (h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset
+ + h->root.u.def.value);
+}
+
+/* Return true if H matches __tls_get_addr or one of its variants. */
+
+static bfd_boolean
+is_tls_get_addr (struct elf_link_hash_entry *h,
+ struct ppc_link_hash_table *htab)
+{
+ return (h == &htab->tls_get_addr_fd->elf || h == &htab->tga_desc_fd->elf
+ || h == &htab->tls_get_addr->elf || h == &htab->tga_desc->elf);
+}
+
static bfd_boolean func_desc_adjust (struct elf_link_hash_entry *, void *);
/* Garbage collect sections, after first dealing with dot-symbols. */
struct ppc_link_hash_entry *eh, *fh;
asection *sec;
- eh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, TRUE);
+ eh = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, sym->name,
+ FALSE, FALSE, TRUE));
if (eh == NULL)
continue;
if (eh->elf.root.type != bfd_link_hash_defined
ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
- struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
+ struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h);
struct ppc_link_hash_entry *fdh;
struct bfd_elf_dynamic_list *d = info->dynamic_list;
{
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
- eh = (struct ppc_link_hash_entry *) h;
+ eh = ppc_elf_hash_entry (h);
fdh = defined_func_desc (eh);
if (fdh != NULL)
{
sym[len + 0] = i / 10 + '0';
sym[len + 1] = i % 10 + '0';
- h = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, sym, writing, TRUE, TRUE);
+ h = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, sym,
+ writing, TRUE, TRUE));
if (stub_sec != NULL)
{
if (h != NULL
s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE);
if (s == NULL)
return FALSE;
- if (s->root.type == bfd_link_hash_new
- || (s->root.type = bfd_link_hash_defined
- && s->root.u.def.section == stub_sec))
+ if (s->root.type == bfd_link_hash_new)
{
s->root.type = bfd_link_hash_defined;
s->root.u.def.section = stub_sec;
return p + 4;
}
+#define STDU_R1_0R1 0xf8210001
+#define ADDI_R1_R1 0x38210000
+
+/* Emit prologue of wrapper preserving regs around a call to
+ __tls_get_addr_opt. */
+
+static bfd_byte *
+tls_get_addr_prologue (bfd *obfd, bfd_byte *p, struct ppc_link_hash_table *htab)
+{
+ unsigned int i;
+
+ bfd_put_32 (obfd, MFLR_R0, p);
+ p += 4;
+ bfd_put_32 (obfd, STD_R0_0R1 + 16, p);
+ p += 4;
+
+ if (htab->opd_abi)
+ {
+ for (i = 4; i < 12; i++)
+ {
+ bfd_put_32 (obfd,
+ STD_R0_0R1 | i << 21 | (-(13 - i) * 8 & 0xffff), p);
+ p += 4;
+ }
+ bfd_put_32 (obfd, STDU_R1_0R1 | (-128 & 0xffff), p);
+ p += 4;
+ }
+ else
+ {
+ for (i = 4; i < 12; i++)
+ {
+ bfd_put_32 (obfd,
+ STD_R0_0R1 | i << 21 | (-(12 - i) * 8 & 0xffff), p);
+ p += 4;
+ }
+ bfd_put_32 (obfd, STDU_R1_0R1 | (-96 & 0xffff), p);
+ p += 4;
+ }
+ return p;
+}
+
+/* Emit epilogue of wrapper preserving regs around a call to
+ __tls_get_addr_opt. */
+
+static bfd_byte *
+tls_get_addr_epilogue (bfd *obfd, bfd_byte *p, struct ppc_link_hash_table *htab)
+{
+ unsigned int i;
+
+ if (htab->opd_abi)
+ {
+ for (i = 4; i < 12; i++)
+ {
+ bfd_put_32 (obfd, LD_R0_0R1 | i << 21 | (128 - (13 - i) * 8), p);
+ p += 4;
+ }
+ bfd_put_32 (obfd, ADDI_R1_R1 | 128, p);
+ p += 4;
+ }
+ else
+ {
+ for (i = 4; i < 12; i++)
+ {
+ bfd_put_32 (obfd, LD_R0_0R1 | i << 21 | (96 - (12 - i) * 8), p);
+ p += 4;
+ }
+ bfd_put_32 (obfd, ADDI_R1_R1 | 96, p);
+ p += 4;
+ }
+ bfd_put_32 (obfd, LD_R0_0R1 | 16, p);
+ p += 4;
+ bfd_put_32 (obfd, MTLR_R0, p);
+ p += 4;
+ bfd_put_32 (obfd, BLR, p);
+ p += 4;
+ return p;
+}
+
/* Called via elf_link_hash_traverse to transfer dynamic linking
information on function code symbol entries to their corresponding
function descriptor symbol entries. */
struct ppc_link_hash_entry *fdh;
bfd_boolean force_local;
- fh = (struct ppc_link_hash_entry *) h;
+ fh = ppc_elf_hash_entry (h);
if (fh->elf.root.type == bfd_link_hash_indirect)
return TRUE;
static asection *
readonly_dynrelocs (struct elf_link_hash_entry *h)
{
- struct ppc_link_hash_entry *eh;
+ struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h);
struct elf_dyn_relocs *p;
- eh = (struct ppc_link_hash_entry *) h;
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
asection *s = p->sec->output_section;
static bfd_boolean
alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
{
- struct ppc_link_hash_entry *eh;
-
- eh = (struct ppc_link_hash_entry *) h;
+ struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h);
do
{
if (readonly_dynrelocs (&eh->elf))
return TRUE;
- eh = (struct ppc_link_hash_entry *) eh->elf.u.alias;
+ eh = ppc_elf_hash_entry (eh->elf.u.alias);
}
while (eh != NULL && &eh->elf != h);
|| h->type == STT_GNU_IFUNC
|| h->needs_plt)
{
- bfd_boolean local = (((struct ppc_link_hash_entry *) h)->save_res
+ bfd_boolean local = (ppc_elf_hash_entry (h)->save_res
|| SYMBOL_CALLS_LOCAL (info, h)
|| UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
/* Discard dyn_relocs when non-pic if we've decided that a
if (!bfd_link_pic (info)
&& h->type != STT_GNU_IFUNC
&& local)
- ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL;
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
/* Clear procedure linkage table information for any symbol that
won't need a .plt entry. */
|| (h->type != STT_GNU_IFUNC
&& local
&& (htab->can_convert_all_inline_plt
- || (((struct ppc_link_hash_entry *) h)->tls_mask
+ || (ppc_elf_hash_entry (h)->tls_mask
& (TLS_TLS | PLT_KEEP)) != PLT_KEEP)))
{
h->plt.plist = NULL;
else if (!bfd_link_pic (info))
/* We are going to be defining the function symbol on the
plt stub, so no dyn_relocs needed when non-pic. */
- ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL;
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
}
/* ELFv2 function symbols can't have copy relocs. */
h->root.u.def.value = def->root.u.def.value;
if (def->root.u.def.section == htab->elf.sdynbss
|| def->root.u.def.section == htab->elf.sdynrelro)
- ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL;
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
return TRUE;
}
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
- if (bfd_link_pic (info))
+ if (!bfd_link_executable (info))
return TRUE;
/* If there are no references to this symbol that do not use the
/* If we don't find any dynamic relocs in read-only sections, then
we'll be keeping the dynamic relocs and avoiding the copy reloc. */
- || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h))
+ || (ELIMINATE_COPY_RELOCS
+ && !h->needs_copy
+ && !alias_readonly_dynrelocs (h))
/* Protected variables do not work with .dynbss. The copy in
.dynbss won't be used by the shared library with the protected
|| h->protected_def)
return TRUE;
- if (h->plt.plist != NULL)
+ if (h->type == STT_FUNC
+ || h->type == STT_GNU_IFUNC)
{
- /* We should never get here, but unfortunately there are versions
- of gcc out there that improperly (for this ABI) put initialized
- function pointers, vtable refs and suchlike in read-only
- sections. Allow them to proceed, but warn that this might
- break at runtime. */
+ /* .dynbss copies of function symbols only work if we have
+ ELFv1 dot-symbols. ELFv1 compilers since 2004 default to not
+ use dot-symbols and set the function symbol size to the text
+ size of the function rather than the size of the descriptor.
+ That's wrong for copying a descriptor. */
+ if (ppc_elf_hash_entry (h)->oh == NULL
+ || !(h->size == 24 || h->size == 16))
+ return TRUE;
+
+ /* We should never get here, but unfortunately there are old
+ versions of gcc (circa gcc-3.2) that improperly for the
+ ELFv1 ABI put initialized function pointers, vtable refs and
+ suchlike in read-only sections. Allow them to proceed, but
+ warn that this might break at runtime. */
info->callbacks->einfo
(_("%P: copy reloc against `%pT' requires lazy plt linking; "
"avoid setting LD_BIND_NOW=1 or upgrade gcc\n"),
}
/* We no longer want dyn_relocs. */
- ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL;
+ ppc_elf_hash_entry (h)->dyn_relocs = NULL;
return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
if (ppc_hash_table (info) == NULL)
return;
- eh = (struct ppc_link_hash_entry *) h;
+ eh = ppc_elf_hash_entry (h);
if (eh->is_func_descriptor)
{
struct ppc_link_hash_entry *fh = eh->oh;
p = eh->elf.root.root.string - 1;
save = *p;
*(char *) p = '.';
- fh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE);
+ fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, FALSE,
+ FALSE, FALSE));
*(char *) p = save;
/* Unfortunately, if it so happens that the string we were
while (q >= eh->elf.root.root.string && *q == *p)
--q, --p;
if (q < eh->elf.root.root.string && *p == '.')
- fh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE);
+ fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, FALSE,
+ FALSE, FALSE));
}
if (fh != NULL)
{
}
if (tls_maskp != NULL)
- {
- struct ppc_link_hash_entry *eh;
-
- eh = (struct ppc_link_hash_entry *) h;
- *tls_maskp = &eh->tls_mask;
- }
+ *tls_maskp = &ppc_elf_hash_entry (h)->tls_mask;
}
else
{
&& h->root.type != bfd_link_hash_defweak)
return TRUE;
- eh = (struct ppc_link_hash_entry *) h;
+ eh = ppc_elf_hash_entry (h);
if (eh->adjust_done)
return TRUE;
default:
return TRUE;
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_LO_DS:
+ if (h == NULL)
+ return TRUE;
+ break;
+
case R_PPC64_TPREL16:
case R_PPC64_TPREL16_LO:
case R_PPC64_TPREL16_HI:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
case R_PPC64_TPREL64:
+ case R_PPC64_TPREL34:
case R_PPC64_DTPMOD64:
case R_PPC64_DTPREL64:
case R_PPC64_ADDR64:
return FALSE;
}
- if ((bfd_link_pic (info)
- && (must_be_dyn_reloc (info, r_type)
- || (h != NULL
- && (!SYMBOLIC_BIND (info, h)
- || h->root.type == bfd_link_hash_defweak
- || !h->def_regular))))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && (h->root.type == bfd_link_hash_defweak
- || !h->def_regular)))
+ if ((h != NULL
+ && (h->root.type == bfd_link_hash_defweak
+ || !h->def_regular))
+ || (h != NULL
+ && !bfd_link_executable (info)
+ && !SYMBOLIC_BIND (info, h))
+ || (bfd_link_pic (info)
+ && must_be_dyn_reloc (info, r_type))
+ || (!bfd_link_pic (info)
+ && (h != NULL
+ ? h->type == STT_GNU_IFUNC
+ : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
;
else
return TRUE;
{
struct elf_dyn_relocs *p;
struct elf_dyn_relocs **pp;
- pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+ pp = &ppc_elf_hash_entry (h)->dyn_relocs;
/* elf_gc_sweep may have already removed all dyn relocs associated
with local syms for a given section. Also, symbol flags are
bfd_byte *loc;
if (!bfd_malloc_and_get_section (ibfd, sec, &loc))
{
- if (loc != NULL)
- free (loc);
+ free (loc);
error_ret:
- if (local_syms != NULL
- && symtab_hdr->contents != (unsigned char *) local_syms)
+ if (symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
if (elf_section_data (sec)->relocs != relstart)
free (relstart);
if (h != NULL
&& h->root.root.string[0] == '.')
{
- fdh = ((struct ppc_link_hash_entry *) h)->oh;
+ fdh = ppc_elf_hash_entry (h)->oh;
if (fdh != NULL)
{
fdh = ppc_follow_link (fdh);
return FALSE;
relend = relstart + sec->reloc_count;
- for (rel = relstart; rel < relend; )
+ for (rel = relstart; rel < relend; rel++)
{
enum elf_ppc64_reloc_type r_type;
unsigned long r_symndx;
{
if (elf_section_data (sec)->relocs != relstart)
free (relstart);
- if (local_syms != NULL
- && symtab_hdr->contents != (bfd_byte *) local_syms)
+ if (symtab_hdr->contents != (bfd_byte *) local_syms)
free (local_syms);
return FALSE;
}
ppc64_elf_tls_setup (struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
+ struct elf_link_hash_entry *tga, *tga_fd, *desc, *desc_fd;
htab = ppc_hash_table (info);
if (htab == NULL)
(_("warning: --plt-localentry is especially dangerous without "
"ld.so support to detect ABI violations"));
- htab->tls_get_addr = ((struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
- FALSE, FALSE, TRUE));
+ tga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+ FALSE, FALSE, TRUE);
+ htab->tls_get_addr = ppc_elf_hash_entry (tga);
+
/* Move dynamic linking info to the function descriptor sym. */
- if (htab->tls_get_addr != NULL)
- func_desc_adjust (&htab->tls_get_addr->elf, info);
- htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
- FALSE, FALSE, TRUE));
+ if (tga != NULL)
+ func_desc_adjust (tga, info);
+ tga_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+ FALSE, FALSE, TRUE);
+ htab->tls_get_addr_fd = ppc_elf_hash_entry (tga_fd);
+
+ desc = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_desc",
+ FALSE, FALSE, TRUE);
+ htab->tga_desc = ppc_elf_hash_entry (desc);
+ if (desc != NULL)
+ func_desc_adjust (desc, info);
+ desc_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_desc",
+ FALSE, FALSE, TRUE);
+ htab->tga_desc_fd = ppc_elf_hash_entry (desc_fd);
+
if (htab->params->tls_get_addr_opt)
{
- struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
+ struct elf_link_hash_entry *opt, *opt_fd;
opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt",
FALSE, FALSE, TRUE);
signalled by the presence of __tls_get_addr_opt, and we'll
be calling __tls_get_addr via a plt call stub, then
make __tls_get_addr point to __tls_get_addr_opt. */
- tga_fd = &htab->tls_get_addr_fd->elf;
- if (htab->elf.dynamic_sections_created
- && tga_fd != NULL
- && (tga_fd->type == STT_FUNC
- || tga_fd->needs_plt)
- && !(SYMBOL_CALLS_LOCAL (info, tga_fd)
- || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga_fd)))
+ if (!(htab->elf.dynamic_sections_created
+ && tga_fd != NULL
+ && (tga_fd->type == STT_FUNC
+ || tga_fd->needs_plt)
+ && !(SYMBOL_CALLS_LOCAL (info, tga_fd)
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga_fd))))
+ tga_fd = NULL;
+ if (!(htab->elf.dynamic_sections_created
+ && desc_fd != NULL
+ && (desc_fd->type == STT_FUNC
+ || desc_fd->needs_plt)
+ && !(SYMBOL_CALLS_LOCAL (info, desc_fd)
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, desc_fd))))
+ desc_fd = NULL;
+
+ if (tga_fd != NULL || desc_fd != NULL)
{
- struct plt_entry *ent;
+ struct plt_entry *ent = NULL;
- for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next)
- if (ent->plt.refcount > 0)
- break;
+ if (tga_fd != NULL)
+ for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.refcount > 0)
+ break;
+ if (ent == NULL && desc_fd != NULL)
+ for (ent = desc_fd->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.refcount > 0)
+ break;
if (ent != NULL)
{
- tga_fd->root.type = bfd_link_hash_indirect;
- tga_fd->root.u.i.link = &opt_fd->root;
- ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd);
+ if (tga_fd != NULL)
+ {
+ tga_fd->root.type = bfd_link_hash_indirect;
+ tga_fd->root.u.i.link = &opt_fd->root;
+ tga_fd->root.u.i.warning = NULL;
+ ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd);
+ }
+ if (desc_fd != NULL)
+ {
+ desc_fd->root.type = bfd_link_hash_indirect;
+ desc_fd->root.u.i.link = &opt_fd->root;
+ desc_fd->root.u.i.warning = NULL;
+ ppc64_elf_copy_indirect_symbol (info, opt_fd, desc_fd);
+ }
opt_fd->mark = 1;
if (opt_fd->dynindx != -1)
{
if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
return NULL;
}
- htab->tls_get_addr_fd
- = (struct ppc_link_hash_entry *) opt_fd;
- tga = &htab->tls_get_addr->elf;
- if (opt != NULL && tga != NULL)
+ if (tga_fd != NULL)
{
- tga->root.type = bfd_link_hash_indirect;
- tga->root.u.i.link = &opt->root;
- ppc64_elf_copy_indirect_symbol (info, opt, tga);
- opt->mark = 1;
- _bfd_elf_link_hash_hide_symbol (info, opt,
- tga->forced_local);
- htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
+ htab->tls_get_addr_fd = ppc_elf_hash_entry (opt_fd);
+ tga = &htab->tls_get_addr->elf;
+ if (opt != NULL && tga != NULL)
+ {
+ tga->root.type = bfd_link_hash_indirect;
+ tga->root.u.i.link = &opt->root;
+ tga->root.u.i.warning = NULL;
+ ppc64_elf_copy_indirect_symbol (info, opt, tga);
+ opt->mark = 1;
+ _bfd_elf_link_hash_hide_symbol (info, opt,
+ tga->forced_local);
+ htab->tls_get_addr = ppc_elf_hash_entry (opt);
+ }
+ htab->tls_get_addr_fd->oh = htab->tls_get_addr;
+ htab->tls_get_addr_fd->is_func_descriptor = 1;
+ if (htab->tls_get_addr != NULL)
+ {
+ htab->tls_get_addr->oh = htab->tls_get_addr_fd;
+ htab->tls_get_addr->is_func = 1;
+ }
}
- htab->tls_get_addr_fd->oh = htab->tls_get_addr;
- htab->tls_get_addr_fd->is_func_descriptor = 1;
- if (htab->tls_get_addr != NULL)
+ if (desc_fd != NULL)
{
- htab->tls_get_addr->oh = htab->tls_get_addr_fd;
- htab->tls_get_addr->is_func = 1;
+ htab->tga_desc_fd = ppc_elf_hash_entry (opt_fd);
+ if (opt != NULL && desc != NULL)
+ {
+ desc->root.type = bfd_link_hash_indirect;
+ desc->root.u.i.link = &opt->root;
+ desc->root.u.i.warning = NULL;
+ ppc64_elf_copy_indirect_symbol (info, opt, desc);
+ opt->mark = 1;
+ _bfd_elf_link_hash_hide_symbol (info, opt,
+ desc->forced_local);
+ htab->tga_desc = ppc_elf_hash_entry (opt);
+ }
+ htab->tga_desc_fd->oh = htab->tga_desc;
+ htab->tga_desc_fd->is_func_descriptor = 1;
+ if (htab->tga_desc != NULL)
+ {
+ htab->tga_desc->oh = htab->tga_desc_fd;
+ htab->tga_desc->is_func = 1;
+ }
}
}
}
else if (htab->params->tls_get_addr_opt < 0)
htab->params->tls_get_addr_opt = 0;
}
+
+ if (htab->tga_desc_fd != NULL
+ && htab->params->tls_get_addr_opt
+ && htab->params->no_tls_get_addr_regsave == -1)
+ htab->params->no_tls_get_addr_regsave = 0;
+
return _bfd_elf_tls_setup (info->output_bfd, info);
}
/* Return TRUE iff REL is a branch reloc with a global symbol matching
- HASH1 or HASH2. */
+ any of HASH1, HASH2, HASH3, or HASH4. */
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)
+ const struct ppc_link_hash_entry *hash2,
+ const struct ppc_link_hash_entry *hash3,
+ const struct ppc_link_hash_entry *hash4)
{
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
h = elf_follow_link (h);
- if (h == &hash1->elf || h == &hash2->elf)
+ if (h == &hash1->elf || h == &hash2->elf
+ || h == &hash3->elf || h == &hash4->elf)
return TRUE;
}
return FALSE;
err_free_rel:
if (elf_section_data (sec)->relocs != relstart)
free (relstart);
- if (toc_ref != NULL)
- free (toc_ref);
- if (locsyms != NULL
- && (elf_symtab_hdr (ibfd).contents
- != (unsigned char *) locsyms))
+ free (toc_ref);
+ if (elf_symtab_hdr (ibfd).contents
+ != (unsigned char *) locsyms)
free (locsyms);
return ret;
}
value = sym->st_value;
ok_tprel = FALSE;
- is_local = FALSE;
- if (h == NULL
- || !h->def_dynamic)
+ is_local = SYMBOL_REFERENCES_LOCAL (info, h);
+ if (is_local)
{
- is_local = TRUE;
if (h != NULL
&& h->root.type == bfd_link_hash_undefweak)
ok_tprel = TRUE;
value += sym_sec->output_offset;
value += sym_sec->output_section->vma;
value -= htab->elf.tls_sec->vma + TP_OFFSET;
+ /* Note that even though the prefix insns
+ allow a 1<<33 offset we use the same test
+ as for addis;addi. There may be a mix of
+ pcrel and non-pcrel code and the decision
+ to optimise is per symbol, not per TLS
+ sequence. */
ok_tprel = value + 0x80008000ULL < 1ULL << 32;
}
}
setup insn. If we don't find matching arg setup
relocs, don't do any tls optimization. */
if (pass == 0
- && sec->has_tls_get_addr_call
+ && sec->nomark_tls_get_addr
&& h != NULL
- && (h == &htab->tls_get_addr->elf
- || h == &htab->tls_get_addr_fd->elf)
+ && is_tls_get_addr (h, htab)
&& !found_tls_get_addr_arg
&& is_branch_reloc (r_type))
{
{
case R_PPC64_GOT_TLSLD16:
case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_GOT_TLSLD34:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
/* Fall through. */
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TLSGD34:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
/* Fall through. */
tls_type = TLS_TLS | TLS_GD;
break;
+ case R_PPC64_GOT_TPREL34:
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
}
continue;
- case R_PPC64_TLSGD:
case R_PPC64_TLSLD:
+ if (!is_local)
+ continue;
+ /* Fall through. */
+ case R_PPC64_TLSGD:
if (rel + 1 < relend
&& is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
{
if (pass == 0)
{
if (!expecting_tls_get_addr
- || !sec->has_tls_get_addr_call)
+ || !sec->nomark_tls_get_addr)
continue;
if (rel + 1 < relend
&& branch_reloc_hash_match (ibfd, rel + 1,
+ htab->tls_get_addr_fd,
+ htab->tga_desc_fd,
htab->tls_get_addr,
- htab->tls_get_addr_fd))
+ htab->tga_desc))
{
if (expecting_tls_get_addr == 2)
{
Disable optimization in this case. */
if ((tls_clear & (TLS_GD | TLS_LD)) != 0
&& (tls_set & TLS_EXPLICIT) == 0
- && !sec->has_tls_get_addr_call
+ && !sec->nomark_tls_get_addr
&& ((*tls_mask & (TLS_TLS | TLS_MARK))
!= (TLS_TLS | TLS_MARK)))
continue;
- if (expecting_tls_get_addr)
+ if (expecting_tls_get_addr == 1 + !sec->nomark_tls_get_addr)
{
struct plt_entry *ent = NULL;
- if (htab->tls_get_addr != NULL)
+ if (htab->tls_get_addr_fd != NULL)
+ for (ent = htab->tls_get_addr_fd->elf.plt.plist;
+ ent != NULL;
+ ent = ent->next)
+ if (ent->addend == 0)
+ break;
+
+ if (ent == NULL && htab->tga_desc_fd != NULL)
+ for (ent = htab->tga_desc_fd->elf.plt.plist;
+ ent != NULL;
+ ent = ent->next)
+ if (ent->addend == 0)
+ break;
+
+ if (ent == NULL && htab->tls_get_addr != NULL)
for (ent = htab->tls_get_addr->elf.plt.plist;
ent != NULL;
ent = ent->next)
if (ent->addend == 0)
break;
- if (ent == NULL && htab->tls_get_addr_fd != NULL)
- for (ent = htab->tls_get_addr_fd->elf.plt.plist;
+ if (ent == NULL && htab->tga_desc != NULL)
+ for (ent = htab->tga_desc->elf.plt.plist;
ent != NULL;
ent = ent->next)
if (ent->addend == 0)
}
}
- if (toc_ref != NULL)
- free (toc_ref);
+ free (toc_ref);
htab->do_tls_opt = 1;
return TRUE;
}
&& h->root.type != bfd_link_hash_defweak)
return TRUE;
- eh = (struct ppc_link_hash_entry *) h;
+ eh = ppc_elf_hash_entry (h);
if (eh->adjust_done)
return TRUE;
static bfd_boolean
ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
{
- return ((insn & (0x3f << 26)) == 12u << 26 /* addic */
- || (insn & (0x3f << 26)) == 14u << 26 /* addi */
- || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
- || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
- || (insn & (0x3f << 26)) == 36u << 26 /* stw */
- || (insn & (0x3f << 26)) == 38u << 26 /* stb */
- || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
- || (insn & (0x3f << 26)) == 42u << 26 /* lha */
- || (insn & (0x3f << 26)) == 44u << 26 /* sth */
- || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
- || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
- || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
- || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
- || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
- || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
- || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */
- || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
+ return ((insn & (0x3fu << 26)) == 12u << 26 /* addic */
+ || (insn & (0x3fu << 26)) == 14u << 26 /* addi */
+ || (insn & (0x3fu << 26)) == 32u << 26 /* lwz */
+ || (insn & (0x3fu << 26)) == 34u << 26 /* lbz */
+ || (insn & (0x3fu << 26)) == 36u << 26 /* stw */
+ || (insn & (0x3fu << 26)) == 38u << 26 /* stb */
+ || (insn & (0x3fu << 26)) == 40u << 26 /* lhz */
+ || (insn & (0x3fu << 26)) == 42u << 26 /* lha */
+ || (insn & (0x3fu << 26)) == 44u << 26 /* sth */
+ || (insn & (0x3fu << 26)) == 46u << 26 /* lmw */
+ || (insn & (0x3fu << 26)) == 47u << 26 /* stmw */
+ || (insn & (0x3fu << 26)) == 48u << 26 /* lfs */
+ || (insn & (0x3fu << 26)) == 50u << 26 /* lfd */
+ || (insn & (0x3fu << 26)) == 52u << 26 /* stfs */
+ || (insn & (0x3fu << 26)) == 54u << 26 /* stfd */
+ || (insn & (0x3fu << 26)) == 56u << 26 /* lq,lfq */
+ || ((insn & (0x3fu << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
/* Exclude lfqu by testing reloc. If relocs are ever
defined for the reduced D field in psq_lu then those
will need testing too. */
&& r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
- || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */
+ || ((insn & (0x3fu << 26)) == 58u << 26 /* ld,lwa */
&& (insn & 1) == 0)
- || (insn & (0x3f << 26)) == 60u << 26 /* stfq */
- || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */
+ || (insn & (0x3fu << 26)) == 60u << 26 /* stfq */
+ || ((insn & (0x3fu << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */
/* Exclude stfqu. psq_stu as above for psq_lu. */
&& r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
- || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */
+ || ((insn & (0x3fu << 26)) == 62u << 26 /* std,stq */
&& (insn & 1) == 0));
}
/* PCREL_OPT in one instance flags to the linker that a pair of insns:
pld ra,symbol@got@pcrel
- load/store rt,0(ra)
+ load/store rt,off(ra)
or
pla ra,symbol@pcrel
- load/store rt,0(ra)
+ load/store rt,off(ra)
may be translated to
- pload/pstore rt,symbol@pcrel
+ pload/pstore rt,symbol+off@pcrel
nop.
This function returns true if the optimization is possible, placing
- the prefix insn in *PINSN1 and a NOP in *PINSN2.
+ the prefix insn in *PINSN1, a NOP in *PINSN2 and the offset in *POFF.
On entry to this function, the linker has already determined that
the pld can be replaced with pla: *PINSN1 is that pla insn,
while *PINSN2 is the second instruction. */
static bfd_boolean
-xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2)
+xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
{
- uint32_t insn2 = *pinsn2 >> 32;
- uint64_t i1new;
+ uint64_t insn1 = *pinsn1;
+ uint64_t insn2 = *pinsn2;
+ bfd_signed_vma off;
+
+ if ((insn2 & (63ULL << 58)) == 1ULL << 58)
+ {
+ /* Check that regs match. */
+ if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
+ return FALSE;
+
+ /* P8LS or PMLS form, non-pcrel. */
+ if ((insn2 & (-1ULL << 50) & ~(1ULL << 56)) != (1ULL << 58))
+ return FALSE;
+
+ *pinsn1 = (insn2 & ~(31 << 16) & ~0x3ffff0000ffffULL) | (1ULL << 52);
+ *pinsn2 = PNOP;
+ off = ((insn2 >> 16) & 0x3ffff0000ULL) | (insn2 & 0xffff);
+ *poff = (off ^ 0x200000000ULL) - 0x200000000ULL;
+ return TRUE;
+ }
+
+ insn2 >>= 32;
/* Check that regs match. */
- if (((insn2 >> 16) & 31) != ((*pinsn1 >> 21) & 31))
+ if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
return FALSE;
switch ((insn2 >> 26) & 63)
case 52: /* stfs */
case 54: /* stfd */
/* These are the PMLS cases, where we just need to tack a prefix
- on the insn. Check that the D field is zero. */
- if ((insn2 & 0xffff) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
+ on the insn. */
+ insn1 = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
| (insn2 & ((63ULL << 26) | (31ULL << 21))));
+ off = insn2 & 0xffff;
break;
case 58: /* lwa, ld */
- if ((insn2 & 0xfffd) != 0)
+ if ((insn2 & 1) != 0)
return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| (insn2 & 2 ? 41ULL << 26 : 57ULL << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
break;
case 57: /* lxsd, lxssp */
- if ((insn2 & 0xfffc) != 0 || (insn2 & 3) < 2)
+ if ((insn2 & 3) < 2)
return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((40ULL | (insn2 & 3)) << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
break;
case 61: /* stxsd, stxssp, lxv, stxv */
return FALSE;
else if ((insn2 & 3) >= 2)
{
- if ((insn2 & 0xfffc) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((44ULL | (insn2 & 3)) << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
}
else
{
- if ((insn2 & 0xfff0) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((50ULL | (insn2 & 4) | ((insn2 & 8) >> 3)) << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfff0;
}
break;
case 56: /* lq */
- if ((insn2 & 0xffff) != 0)
- return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| (insn2 & ((63ULL << 26) | (31ULL << 21))));
+ off = insn2 & 0xffff;
+ break;
+
+ case 6: /* lxvp, stxvp */
+ if ((insn2 & 0xe) != 0)
+ return FALSE;
+ insn1 = ((1ULL << 58) | (1ULL << 52)
+ | ((insn2 & 1) == 0 ? 58ULL << 26 : 62ULL << 26)
+ | (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfff0;
break;
case 62: /* std, stq */
- if ((insn2 & 0xfffd) != 0)
+ if ((insn2 & 1) != 0)
return FALSE;
- i1new = ((1ULL << 58) | (1ULL << 52)
+ insn1 = ((1ULL << 58) | (1ULL << 52)
| ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26)
| (insn2 & (31ULL << 21)));
+ off = insn2 & 0xfffc;
break;
}
- *pinsn1 = i1new;
+ *pinsn1 = insn1;
*pinsn2 = (uint64_t) NOP << 32;
+ *poff = (off ^ 0x8000) - 0x8000;
return TRUE;
}
if (used == NULL)
{
error_ret:
- if (local_syms != NULL
- && symtab_hdr->contents != (unsigned char *) local_syms)
+ if (symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
if (sec != NULL
- && relstart != NULL
&& elf_section_data (sec)->relocs != relstart)
free (relstart);
- if (toc_relocs != NULL
- && elf_section_data (toc)->relocs != toc_relocs)
+ if (elf_section_data (toc)->relocs != toc_relocs)
free (toc_relocs);
- if (skip != NULL)
- free (skip);
+ free (skip);
return FALSE;
}
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
bfd_vma val;
- enum {no_check, check_lo, check_ha} insn_check;
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
- default:
- insn_check = no_check;
- break;
-
- case R_PPC64_GOT_TLSLD16_HA:
- case R_PPC64_GOT_TLSGD16_HA:
- case R_PPC64_GOT_TPREL16_HA:
- case R_PPC64_GOT_DTPREL16_HA:
- case R_PPC64_GOT16_HA:
- case R_PPC64_TOC16_HA:
- insn_check = check_ha;
- break;
-
- case R_PPC64_GOT_TLSLD16_LO:
- case R_PPC64_GOT_TLSGD16_LO:
- case R_PPC64_GOT_TPREL16_LO_DS:
- case R_PPC64_GOT_DTPREL16_LO_DS:
- case R_PPC64_GOT16_LO:
- case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16:
case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_LO_DS:
- insn_check = check_lo;
+ /* In case we're taking addresses of toc entries. */
+ case R_PPC64_ADDR64:
break;
+
+ default:
+ continue;
}
- if (insn_check != no_check)
- {
- bfd_vma off = rel->r_offset & ~3;
- unsigned char buf[4];
- unsigned int insn;
-
- if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
- {
- free (used);
- goto error_ret;
- }
- insn = bfd_get_32 (ibfd, buf);
- if (insn_check == check_lo
- ? !ok_lo_toc_insn (insn, r_type)
- : ((insn & ((0x3f << 26) | 0x1f << 16))
- != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
- {
- char str[12];
-
- ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
- sprintf (str, "%#08x", insn);
- info->callbacks->einfo
- /* xgettext:c-format */
- (_("%H: toc optimization is not supported for"
- " %s instruction\n"),
- ibfd, sec, rel->r_offset & ~3, str);
- }
- }
-
- switch (r_type)
- {
- case R_PPC64_TOC16:
- case R_PPC64_TOC16_LO:
- case R_PPC64_TOC16_HI:
- case R_PPC64_TOC16_HA:
- case R_PPC64_TOC16_DS:
- case R_PPC64_TOC16_LO_DS:
- /* In case we're taking addresses of toc entries. */
- case R_PPC64_ADDR64:
- break;
-
- default:
- continue;
- }
-
- r_symndx = ELF64_R_SYM (rel->r_info);
- if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
- r_symndx, ibfd))
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+ r_symndx, ibfd))
{
free (used);
goto error_ret;
rel_hdr->sh_size = toc->reloc_count * sz;
}
}
- else if (toc_relocs != NULL
- && elf_section_data (toc)->relocs != toc_relocs)
+ else if (elf_section_data (toc)->relocs != toc_relocs)
free (toc_relocs);
if (local_syms != NULL
if (!is_ppc64_elf (ibfd))
continue;
- if (!ppc64_elf_tdata (ibfd)->has_gotrel)
+ if (!ppc64_elf_tdata (ibfd)->has_optrel)
continue;
sec = ppc64_elf_tdata (ibfd)->got;
- got = sec->output_section->vma + sec->output_offset + 0x8000;
+ got = 0;
+ if (sec != NULL)
+ got = sec->output_section->vma + sec->output_offset + 0x8000;
local_syms = NULL;
symtab_hdr = &elf_symtab_hdr (ibfd);
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
if (sec->reloc_count == 0
- || !ppc64_elf_section_data (sec)->has_gotrel
+ || !ppc64_elf_section_data (sec)->has_optrel
|| discarded_section (sec))
continue;
if (relstart == NULL)
{
got_error_ret:
- if (local_syms != NULL
- && symtab_hdr->contents != (unsigned char *) local_syms)
+ if (symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
if (sec != NULL
- && relstart != NULL
&& elf_section_data (sec)->relocs != relstart)
free (relstart);
return FALSE;
asection *sym_sec;
struct elf_link_hash_entry *h;
struct got_entry *ent;
- bfd_vma sym_addend, val, pc;
+ bfd_vma val, pc;
unsigned char buf[8];
unsigned int insn;
+ enum {no_check, check_lo, check_ha} insn_check;
r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ default:
+ insn_check = no_check;
+ break;
+
+ case R_PPC64_PLT16_HA:
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_TOC16_HA:
+ insn_check = check_ha;
+ break;
+
+ case R_PPC64_PLT16_LO:
+ case R_PPC64_PLT16_LO_DS:
+ case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ insn_check = check_lo;
+ break;
+ }
+
+ if (insn_check != no_check)
+ {
+ bfd_vma off = rel->r_offset & ~3;
+
+ if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
+ goto got_error_ret;
+
+ insn = bfd_get_32 (ibfd, buf);
+ if (insn_check == check_lo
+ ? !ok_lo_toc_insn (insn, r_type)
+ : ((insn & ((0x3fu << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+ {
+ char str[12];
+
+ ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
+ sprintf (str, "%#08x", insn);
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%H: got/toc optimization is not supported for"
+ " %s instruction\n"),
+ ibfd, sec, rel->r_offset & ~3, str);
+ continue;
+ }
+ }
+
switch (r_type)
{
/* Note that we don't delete GOT entries for
case R_PPC64_GOT16_HA:
case R_PPC64_GOT16_LO_DS:
- sym_addend = rel->r_addend;
- break;
-
case R_PPC64_GOT_PCREL34:
- sym_addend = 0;
break;
}
r_symndx, ibfd))
goto got_error_ret;
+ if (sym_sec == NULL
+ || sym_sec->output_section == NULL
+ || discarded_section (sym_sec))
+ continue;
+
+ if ((h ? h->type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
+ continue;
+
if (!SYMBOL_REFERENCES_LOCAL (info, h))
continue;
val = h->root.u.def.value;
else
val = sym->st_value;
- val += sym_addend;
+ val += rel->r_addend;
val += sym_sec->output_section->vma + sym_sec->output_offset;
/* Fudge factor to allow for the fact that the preliminary layout
rel->r_offset & ~3, 4))
goto got_error_ret;
insn = bfd_get_32 (ibfd, buf);
- if (((insn & ((0x3f << 26) | 0x1f << 16))
+ if (((insn & ((0x3fu << 26) | 0x1f << 16))
!= ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
continue;
break;
rel->r_offset & ~3, 4))
goto got_error_ret;
insn = bfd_get_32 (ibfd, buf);
- if ((insn & (0x3f << 26 | 0x3)) != 58u << 26 /* ld */)
+ if ((insn & (0x3fu << 26 | 0x3)) != 58u << 26 /* ld */)
continue;
break;
if ((insn & (-1u << 18)) != ((1u << 26) | (1u << 20)))
continue;
insn = bfd_get_32 (ibfd, buf + 4);
- if ((insn & (0x3f << 26)) != 57u << 26)
+ if ((insn & (0x3fu << 26)) != 57u << 26)
continue;
break;
}
ent = local_got_ents[r_symndx];
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == rel->r_addend
&& ent->owner == ibfd
&& ent->tls_type == 0)
break;
struct got_entry *gent)
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
- struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
+ struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h);
int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)
? 16 : 8);
int rentsize = (gent->tls_type & eh->tls_mask & TLS_GD
htab->got_reli_size += rentsize;
}
else if (((bfd_link_pic (info)
- && !((gent->tls_type & TLS_TPREL) != 0
+ && !(gent->tls_type != 0
&& bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
|| (htab->elf.dynamic_sections_created
if (htab == NULL)
return FALSE;
- eh = (struct ppc_link_hash_entry *) h;
+ eh = ppc_elf_hash_entry (h);
/* Run through the TLS GD got entries first if we're changing them
to TPREL. */
if ((eh->tls_mask & (TLS_TLS | TLS_GDIE)) == (TLS_TLS | TLS_GDIE))
if (gent->got.refcount > 0)
{
if ((gent->tls_type & TLS_LD) != 0
- && !h->def_dynamic)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
{
ppc64_tlsld_got (gent->owner)->got.refcount += 1;
*pgent = gent->next;
for (gent = h->got.glist; gent != NULL; gent = gent->next)
if (!gent->is_indirect)
{
- /* Make sure this symbol is output as a dynamic symbol. */
+ /* Ensure we catch all the cases where this symbol should
+ be made dynamic. */
if (!ensure_undef_dynamic (info, h))
return FALSE;
be defined in regular objects. For the normal shared case,
discard space for relocs that have become local due to symbol
visibility changes. */
-
if (bfd_link_pic (info))
{
/* Relocs that use pc_count are those that appear on a call
if (eh->dyn_relocs != NULL)
{
- /* Make sure this symbol is output as a dynamic symbol. */
+ /* Ensure we catch all the cases where this symbol
+ should be made dynamic. */
if (!ensure_undef_dynamic (info, h))
return FALSE;
}
}
- else if (ELIMINATE_COPY_RELOCS && h->type != STT_GNU_IFUNC)
+
+ /* For a fixed position executable, discard space for
+ relocs against symbols which are not dynamic. */
+ else if (h->type != STT_GNU_IFUNC)
{
- /* For the non-pic case, discard space for relocs against
- symbols which turn out to need copy relocs or are not
- dynamic. */
if (h->dynamic_adjusted
&& !h->def_regular
&& !ELF_COMMON_DEF_P (h))
{
- /* Make sure this symbol is output as a dynamic symbol. */
+ /* Ensure we catch all the cases where this symbol
+ should be made dynamic. */
if (!ensure_undef_dynamic (info, h))
return FALSE;
+ /* But if that didn't work out, discard dynamic relocs. */
if (h->dynindx == -1)
eh->dyn_relocs = NULL;
}
&& h->def_regular
&& !htab->elf.dynamic_sections_created
&& !htab->can_convert_all_inline_plt
- && (((struct ppc_link_hash_entry *) h)->tls_mask
+ && (ppc_elf_hash_entry (h)->tls_mask
& (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
{
struct plt_entry *pent;
htab->got_reli_size += rel_size;
}
else if (bfd_link_pic (info)
- && !((ent->tls_type & TLS_TPREL) != 0
+ && !(ent->tls_type != 0
&& bfd_link_executable (info)))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
ent->got.offset = s->size;
ent->owner = ibfd;
s->size += 16;
- if (bfd_link_pic (info))
+ if (bfd_link_dll (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += sizeof (Elf64_External_Rela);
}
tls_opt = (htab->params->tls_get_addr_opt
- && htab->tls_get_addr_fd != NULL
- && htab->tls_get_addr_fd->elf.plt.plist != NULL);
+ && ((htab->tls_get_addr_fd != NULL
+ && htab->tls_get_addr_fd->elf.plt.plist != NULL)
+ || (htab->tga_desc_fd != NULL
+ && htab->tga_desc_fd->elf.plt.plist != NULL)));
if (tls_opt || !htab->opd_abi)
{
if (!add_dynamic_entry (DT_PPC64_OPT, tls_opt ? PPC64_OPT_TLS : 0))
}
static bfd_byte *
-build_powerxx_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd,
+build_power10_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd,
bfd_boolean load)
{
uint64_t insn;
}
static unsigned int
-size_powerxx_offset (bfd_vma off, int odd)
+size_power10_offset (bfd_vma off, int odd)
{
if (off - odd + (1ULL << 33) < 1ULL << 34)
return odd + 8;
}
static unsigned int
-num_relocs_for_powerxx_offset (bfd_vma off, int odd)
+num_relocs_for_power10_offset (bfd_vma off, int odd)
{
if (off - odd + (1ULL << 33) < 1ULL << 34)
return 1;
}
static Elf_Internal_Rela *
-emit_relocs_for_powerxx_offset (struct bfd_link_info *info,
+emit_relocs_for_power10_offset (struct bfd_link_info *info,
Elf_Internal_Rela *r, bfd_vma roff,
bfd_vma targ, bfd_vma off, int odd)
{
if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
{
- if (htab->powerxx_stubs)
+ if (htab->power10_stubs)
{
bfd_vma start = (stub_entry->stub_offset
+ stub_entry->group->stub_sec->output_offset
+ stub_entry->group->stub_sec->output_section->vma);
if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
start += 4;
- size = 8 + size_powerxx_offset (off, start & 4);
+ size = 8 + size_power10_offset (off, start & 4);
}
else
size = 8 + size_offset (off - 8);
size += 4;
}
if (stub_entry->h != NULL
- && (stub_entry->h == htab->tls_get_addr_fd
- || stub_entry->h == htab->tls_get_addr)
+ && is_tls_get_addr (&stub_entry->h->elf, htab)
&& htab->params->tls_get_addr_opt)
{
- size += 7 * 4;
- if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
- size += 6 * 4;
+ if (htab->params->no_tls_get_addr_regsave)
+ {
+ size += 7 * 4;
+ if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
+ size += 6 * 4;
+ }
+ else
+ {
+ size += 30 * 4;
+ if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
+ size += 4;
+ }
}
return size;
}
if (!ALWAYS_USE_FAKE_DEP
&& plt_load_toc
&& plt_thread_safe
- && !((stub_entry->h == htab->tls_get_addr_fd
- || stub_entry->h == htab->tls_get_addr)
+ && !(is_tls_get_addr (&stub_entry->h->elf, htab)
&& htab->params->tls_get_addr_opt))
{
bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
/* Build a special .plt call stub for __tls_get_addr. */
-#define LD_R11_0R3 0xe9630000
+#define LD_R0_0R3 0xe8030000
#define LD_R12_0R3 0xe9830000
#define MR_R0_R3 0x7c601b78
-#define CMPDI_R11_0 0x2c2b0000
+#define CMPDI_R0_0 0x2c200000
#define ADD_R3_R12_R13 0x7c6c6a14
#define BEQLR 0x4d820020
#define MR_R3_R0 0x7c030378
-#define STD_R11_0R1 0xf9610000
#define BCTRL 0x4e800421
-#define LD_R11_0R1 0xe9610000
-#define MTLR_R11 0x7d6803a6
static inline bfd_byte *
build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
{
bfd *obfd = htab->params->stub_bfd;
bfd_byte *loc = p;
+ unsigned int i;
- bfd_put_32 (obfd, LD_R11_0R3 + 0, p), p += 4;
+ bfd_put_32 (obfd, LD_R0_0R3 + 0, p), p += 4;
bfd_put_32 (obfd, LD_R12_0R3 + 8, p), p += 4;
+ bfd_put_32 (obfd, CMPDI_R0_0, p), p += 4;
bfd_put_32 (obfd, MR_R0_R3, p), p += 4;
- bfd_put_32 (obfd, CMPDI_R11_0, p), p += 4;
bfd_put_32 (obfd, ADD_R3_R12_R13, p), p += 4;
bfd_put_32 (obfd, BEQLR, p), p += 4;
bfd_put_32 (obfd, MR_R3_R0, p), p += 4;
- if (r != NULL)
- r[0].r_offset += 7 * 4;
- if (stub_entry->stub_type != ppc_stub_plt_call_r2save)
- return build_plt_stub (htab, stub_entry, p, offset, r);
+ if (htab->params->no_tls_get_addr_regsave)
+ {
+ if (r != NULL)
+ r[0].r_offset += 7 * 4;
+ if (stub_entry->stub_type != ppc_stub_plt_call_r2save)
+ return build_plt_stub (htab, stub_entry, p, offset, r);
+
+ bfd_put_32 (obfd, MFLR_R0, p);
+ p += 4;
+ bfd_put_32 (obfd, STD_R0_0R1 + STK_LINKER (htab), p);
+ p += 4;
+
+ if (r != NULL)
+ r[0].r_offset += 2 * 4;
+ p = build_plt_stub (htab, stub_entry, p, offset, r);
+ bfd_put_32 (obfd, BCTRL, p - 4);
+
+ bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
+ p += 4;
+ bfd_put_32 (obfd, LD_R0_0R1 + STK_LINKER (htab), p);
+ p += 4;
+ bfd_put_32 (obfd, MTLR_R0, p);
+ p += 4;
+ bfd_put_32 (obfd, BLR, p);
+ p += 4;
+ }
+ else
+ {
+ p = tls_get_addr_prologue (obfd, p, htab);
- bfd_put_32 (obfd, MFLR_R11, p), p += 4;
- bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4;
+ if (r != NULL)
+ r[0].r_offset += 18 * 4;
- if (r != NULL)
- r[0].r_offset += 2 * 4;
- p = build_plt_stub (htab, stub_entry, p, offset, r);
- bfd_put_32 (obfd, BCTRL, p - 4);
+ p = build_plt_stub (htab, stub_entry, p, offset, r);
+ bfd_put_32 (obfd, BCTRL, p - 4);
- bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4;
- bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4;
- bfd_put_32 (obfd, MTLR_R11, p), p += 4;
- bfd_put_32 (obfd, BLR, p), p += 4;
+ if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
+ {
+ bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
+ p += 4;
+ }
+
+ p = tls_get_addr_epilogue (obfd, p, htab);
+ }
if (htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->size != 0)
{
bfd_byte *base, *eh;
- unsigned int lr_used, delta;
base = htab->glink_eh_frame->contents + stub_entry->group->eh_base + 17;
eh = base + stub_entry->group->eh_size;
- lr_used = stub_entry->stub_offset + (p - 20 - loc);
- delta = lr_used - stub_entry->group->lr_restore;
- stub_entry->group->lr_restore = lr_used + 16;
- eh = eh_advance (htab->elf.dynobj, eh, delta);
- *eh++ = DW_CFA_offset_extended_sf;
- *eh++ = 65;
- *eh++ = -(STK_LINKER (htab) / 8) & 0x7f;
- *eh++ = DW_CFA_advance_loc + 4;
+ if (htab->params->no_tls_get_addr_regsave)
+ {
+ unsigned int lr_used, delta;
+ lr_used = stub_entry->stub_offset + (p - 20 - loc);
+ delta = lr_used - stub_entry->group->lr_restore;
+ stub_entry->group->lr_restore = lr_used + 16;
+ eh = eh_advance (htab->elf.dynobj, eh, delta);
+ *eh++ = DW_CFA_offset_extended_sf;
+ *eh++ = 65;
+ *eh++ = -(STK_LINKER (htab) / 8) & 0x7f;
+ *eh++ = DW_CFA_advance_loc + 4;
+ }
+ else
+ {
+ unsigned int cfa_updt, delta;
+ /* After the bctrl, lr has been modified so we need to emit
+ .eh_frame info saying the return address is on the stack. In
+ fact we must put the EH info at or before the call rather
+ than after it, because the EH info for a call needs to be
+ specified by that point.
+ See libgcc/unwind-dw2.c execute_cfa_program.
+ Any stack pointer update must be described immediately after
+ the instruction making the change, and since the stdu occurs
+ after saving regs we put all the reg saves and the cfa
+ change there. */
+ cfa_updt = stub_entry->stub_offset + 18 * 4;
+ delta = cfa_updt - stub_entry->group->lr_restore;
+ stub_entry->group->lr_restore
+ = stub_entry->stub_offset + (p - loc) - 4;
+ eh = eh_advance (htab->elf.dynobj, eh, delta);
+ *eh++ = DW_CFA_def_cfa_offset;
+ if (htab->opd_abi)
+ {
+ *eh++ = 128;
+ *eh++ = 1;
+ }
+ else
+ *eh++ = 96;
+ *eh++ = DW_CFA_offset_extended_sf;
+ *eh++ = 65;
+ *eh++ = (-16 / 8) & 0x7f;
+ for (i = 4; i < 12; i++)
+ {
+ *eh++ = DW_CFA_offset + i;
+ *eh++ = (htab->opd_abi ? 13 : 12) - i;
+ }
+ *eh++ = (DW_CFA_advance_loc
+ + (stub_entry->group->lr_restore - 8 - cfa_updt) / 4);
+ *eh++ = DW_CFA_def_cfa_offset;
+ *eh++ = 0;
+ for (i = 4; i < 12; i++)
+ *eh++ = DW_CFA_restore + i;
+ *eh++ = DW_CFA_advance_loc + 2;
+ }
*eh++ = DW_CFA_restore_extended;
*eh++ = 65;
stub_entry->group->eh_size = eh - base;
h = ppc_follow_link (h->oh);
BFD_ASSERT (h->elf.root.type == bfd_link_hash_defined
|| h->elf.root.type == bfd_link_hash_defweak);
- symval = (h->elf.root.u.def.value
- + h->elf.root.u.def.section->output_offset
- + h->elf.root.u.def.section->output_section->vma);
+ symval = defined_sym_val (&h->elf);
while (num_rel-- != 0)
{
r->r_info = ELF64_R_INFO (symndx, ELF64_R_TYPE (r->r_info));
stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
info = in_arg;
+ /* Fail if the target section could not be assigned to an output
+ section. The user should fix his linker script. */
+ if (stub_entry->target_section != NULL
+ && stub_entry->target_section->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. "
+ "Retry without --enable-non-contiguous-regions.\n"),
+ stub_entry->target_section);
+
+ /* Same for the group. */
+ if (stub_entry->group->stub_sec != NULL
+ && stub_entry->group->stub_sec->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign group %pA target %pA to an "
+ "output section. Retry without "
+ "--enable-non-contiguous-regions.\n"),
+ stub_entry->group->stub_sec,
+ stub_entry->target_section);
+
htab = ppc_hash_table (info);
if (htab == NULL)
return FALSE;
relp = p;
num_rel = 0;
- if (htab->powerxx_stubs)
+ if (htab->power10_stubs)
{
bfd_boolean load = stub_entry->stub_type >= ppc_stub_plt_call_notoc;
- p = build_powerxx_offset (htab->params->stub_bfd, p, off, odd, load);
+ p = build_power10_offset (htab->params->stub_bfd, p, off, odd, load);
}
else
{
if (info->emitrelocations)
{
bfd_vma roff = relp - stub_entry->group->stub_sec->contents;
- if (htab->powerxx_stubs)
- num_rel += num_relocs_for_powerxx_offset (off, odd);
+ if (htab->power10_stubs)
+ num_rel += num_relocs_for_power10_offset (off, odd);
else
{
num_rel += num_relocs_for_offset (off);
r = get_relocs (stub_entry->group->stub_sec, num_rel);
if (r == NULL)
return FALSE;
- if (htab->powerxx_stubs)
- r = emit_relocs_for_powerxx_offset (info, r, roff, targ, off, odd);
+ if (htab->power10_stubs)
+ r = emit_relocs_for_power10_offset (info, r, roff, targ, off, odd);
else
r = emit_relocs_for_offset (info, r, roff, targ, off);
if (stub_entry->stub_type == ppc_stub_long_branch_notoc
}
}
- if (!htab->powerxx_stubs
+ if (!htab->power10_stubs
&& htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->size != 0)
{
r[0].r_addend = targ;
}
if (stub_entry->h != NULL
- && (stub_entry->h == htab->tls_get_addr_fd
- || stub_entry->h == htab->tls_get_addr)
+ && is_tls_get_addr (&stub_entry->h->elf, htab)
&& htab->params->tls_get_addr_opt)
p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
else
if (htab == NULL)
return FALSE;
+ /* Fail if the target section could not be assigned to an output
+ section. The user should fix his linker script. */
+ if (stub_entry->target_section != NULL
+ && stub_entry->target_section->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign %pA to an output section. "
+ "Retry without --enable-non-contiguous-regions.\n"),
+ stub_entry->target_section);
+
+ /* Same for the group. */
+ if (stub_entry->group->stub_sec != NULL
+ && stub_entry->group->stub_sec->output_section == NULL
+ && info->non_contiguous_regions)
+ info->callbacks->einfo (_("%F%P: Could not assign group %pA target %pA to an "
+ "output section. Retry without "
+ "--enable-non-contiguous-regions.\n"),
+ stub_entry->group->stub_sec,
+ stub_entry->target_section);
+
/* Make a note of the offset within the stubs for this entry. */
stub_entry->stub_offset = stub_entry->group->stub_sec->size;
if (info->emitrelocations)
{
unsigned int num_rel;
- if (htab->powerxx_stubs)
- num_rel = num_relocs_for_powerxx_offset (off, odd);
+ if (htab->power10_stubs)
+ num_rel = num_relocs_for_power10_offset (off, odd);
else
num_rel = num_relocs_for_offset (off - 8);
stub_entry->group->stub_sec->reloc_count += num_rel;
stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
- if (htab->powerxx_stubs)
- extra = size_powerxx_offset (off, odd);
+ if (htab->power10_stubs)
+ extra = size_power10_offset (off, odd);
else
extra = size_offset (off - 8);
/* Include branch insn plus those in the offset sequence. */
calculated. */
off -= extra;
- if (!htab->powerxx_stubs)
+ if (!htab->power10_stubs)
{
/* After the bcl, lr has been modified so we need to emit
.eh_frame info saying the return address is in r12. */
if (info->emitrelocations)
{
unsigned int num_rel;
- if (htab->powerxx_stubs)
- num_rel = num_relocs_for_powerxx_offset (off, odd);
+ if (htab->power10_stubs)
+ num_rel = num_relocs_for_power10_offset (off, odd);
else
num_rel = num_relocs_for_offset (off - 8);
stub_entry->group->stub_sec->reloc_count += num_rel;
size = plt_stub_size (htab, stub_entry, off);
- if (!htab->powerxx_stubs)
+ if (!htab->power10_stubs)
{
/* After the bcl, lr has been modified so we need to emit
.eh_frame info saying the return address is in r12. */
size = plt_stub_size (htab, stub_entry, off);
if (stub_entry->h != NULL
- && (stub_entry->h == htab->tls_get_addr_fd
- || stub_entry->h == htab->tls_get_addr)
+ && is_tls_get_addr (&stub_entry->h->elf, htab)
&& htab->params->tls_get_addr_opt
&& stub_entry->stub_type == ppc_stub_plt_call_r2save)
{
- /* After the bctrl, lr has been modified so we need to
- emit .eh_frame info saying the return address is
- on the stack. In fact we put the EH info specifying
- that the return address is on the stack *at* the
- call rather than after it, because the EH info for a
- call needs to be specified by that point.
- See libgcc/unwind-dw2.c execute_cfa_program. */
- lr_used = stub_entry->stub_offset + size - 20;
- /* The eh_frame info will consist of a DW_CFA_advance_loc
- or variant, DW_CFA_offset_externed_sf, 65, -stackoff,
- DW_CFA_advance_loc+4, DW_CFA_restore_extended, 65. */
- delta = lr_used - stub_entry->group->lr_restore;
- stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+ if (htab->params->no_tls_get_addr_regsave)
+ {
+ lr_used = stub_entry->stub_offset + size - 20;
+ /* The eh_frame info will consist of a DW_CFA_advance_loc
+ or variant, DW_CFA_offset_externed_sf, 65, -stackoff,
+ DW_CFA_advance_loc+4, DW_CFA_restore_extended, 65. */
+ delta = lr_used - stub_entry->group->lr_restore;
+ stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+ }
+ else
+ {
+ /* Adjustments to r1 need to be described. */
+ unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4;
+ delta = cfa_updt - stub_entry->group->lr_restore;
+ stub_entry->group->eh_size += eh_advance_size (delta);
+ stub_entry->group->eh_size += htab->opd_abi ? 36 : 35;
+ }
stub_entry->group->lr_restore = size - 4;
}
break;
ppc64_elf_setup_section_lists (struct bfd_link_info *info)
{
unsigned int id;
- bfd_size_type amt;
+ size_t amt;
struct ppc_link_hash_table *htab = ppc_hash_table (info);
if (htab == NULL)
htab->got_reli_size += rel_size;
}
else if (bfd_link_pic (info)
- && !((ent->tls_type & TLS_TPREL) != 0
+ && !(ent->tls_type != 0
&& bfd_link_executable (info)))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
asection *s = ppc64_elf_tdata (ibfd)->got;
ent->got.offset = s->size;
s->size += 16;
- if (bfd_link_pic (info))
+ if (bfd_link_dll (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += sizeof (Elf64_External_Rela);
/* Calls to dynamic lib functions go through a plt call stub
that uses r2. */
- eh = (struct ppc_link_hash_entry *) h;
+ eh = ppc_elf_hash_entry (h);
if (eh != NULL
&& (eh->elf.plt.plist != NULL
|| (eh->oh != NULL
}
}
- if (local_syms != NULL
- && (elf_symtab_hdr (isec->owner).contents
- != (unsigned char *) local_syms))
+ if (elf_symtab_hdr (isec->owner).contents
+ != (unsigned char *) local_syms)
free (local_syms);
if (elf_section_data (isec)->relocs != relstart)
free (relstart);
if (!group_sections (info, stub_group_size, stubs_always_before_branch))
return FALSE;
+ htab->tga_group = NULL;
+ if (!htab->params->no_tls_get_addr_regsave
+ && htab->tga_desc_fd != NULL
+ && (htab->tga_desc_fd->elf.root.type == bfd_link_hash_undefined
+ || htab->tga_desc_fd->elf.root.type == bfd_link_hash_undefweak)
+ && htab->tls_get_addr_fd != NULL
+ && is_static_defined (&htab->tls_get_addr_fd->elf))
+ {
+ asection *sym_sec, *code_sec, *stub_sec;
+ bfd_vma sym_value;
+ struct _opd_sec_data *opd;
+
+ sym_sec = htab->tls_get_addr_fd->elf.root.u.def.section;
+ sym_value = defined_sym_val (&htab->tls_get_addr_fd->elf);
+ code_sec = sym_sec;
+ opd = get_opd_info (sym_sec);
+ if (opd != NULL)
+ opd_entry_value (sym_sec, sym_value, &code_sec, NULL, FALSE);
+ htab->tga_group = htab->sec_info[code_sec->id].u.group;
+ stub_sec = (*htab->params->add_stub_section) (".tga_desc.stub",
+ htab->tga_group->link_sec);
+ if (stub_sec == NULL)
+ return FALSE;
+ htab->tga_group->stub_sec = stub_sec;
+
+ htab->tga_desc_fd->elf.root.type = bfd_link_hash_defined;
+ htab->tga_desc_fd->elf.root.u.def.section = stub_sec;
+ htab->tga_desc_fd->elf.root.u.def.value = 0;
+ htab->tga_desc_fd->elf.type = STT_FUNC;
+ htab->tga_desc_fd->elf.def_regular = 1;
+ htab->tga_desc_fd->elf.non_elf = 0;
+ _bfd_elf_link_hash_hide_symbol (info, &htab->tga_desc_fd->elf, TRUE);
+ }
+
#define STUB_SHRINK_ITER 20
/* Loop until no stubs added. After iteration 20 of this loop we may
exit on a stub section shrinking. This is to break out of a
if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
r_indx, input_bfd))
goto error_ret_free_internal;
- hash = (struct ppc_link_hash_entry *) h;
+ hash = ppc_elf_hash_entry (h);
ok_dest = FALSE;
fdh = NULL;
if (stub_type != ppc_stub_plt_call
&& stub_type != ppc_stub_plt_call_notoc
&& hash != NULL
- && (hash == htab->tls_get_addr
- || hash == htab->tls_get_addr_fd)
+ && is_tls_get_addr (&hash->elf, htab)
&& section->has_tls_reloc
&& irela != internal_relocs)
{
if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
irela - 1, input_bfd))
goto error_ret_free_internal;
- if ((*tls_mask & TLS_TLS) != 0)
+ if ((*tls_mask & TLS_TLS) != 0
+ && (*tls_mask & (TLS_GD | TLS_LD)) == 0)
continue;
}
if (elf_section_data (section)->relocs == NULL)
free (internal_relocs);
error_ret_free_local:
- if (local_syms != NULL
- && (symtab_hdr->contents
- != (unsigned char *) local_syms))
+ if (symtab_hdr->contents
+ != (unsigned char *) local_syms)
free (local_syms);
return FALSE;
}
stub_sec->flags &= ~SEC_RELOC;
}
}
+ if (htab->tga_group != NULL)
+ {
+ /* See emit_tga_desc and emit_tga_desc_eh_frame. */
+ htab->tga_group->eh_size
+ = 1 + 2 + (htab->opd_abi != 0) + 3 + 8 * 2 + 3 + 8 + 3;
+ htab->tga_group->lr_restore = 23 * 4;
+ htab->tga_group->stub_sec->size = 24 * 4;
+ }
if (htab->stub_iteration <= STUB_SHRINK_ITER
|| htab->brlt->rawsize < htab->brlt->size)
|| (htab->stub_iteration > STUB_SHRINK_ITER
&& htab->brlt->rawsize > htab->brlt->size))
&& (htab->glink_eh_frame == NULL
- || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
+ || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)
+ && (htab->tga_group == NULL
+ || htab->stub_iteration > 1))
break;
/* Ask the linker to do its stuff. */
}
maybe_strip_output (info, htab->brlt);
+ if (htab->relbrlt != NULL)
+ maybe_strip_output (info, htab->relbrlt);
if (htab->glink_eh_frame != NULL)
maybe_strip_output (info, htab->glink_eh_frame);
&& (!is_elf_hash_table (htab)
|| h->def_regular))
{
- TOCstart = (h->root.u.def.value - TOC_BASE_OFF
- + h->root.u.def.section->output_offset
- + h->root.u.def.section->output_section->vma);
+ TOCstart = defined_sym_val (h) - TOC_BASE_OFF;
_bfd_set_gp_value (obfd, TOCstart);
return TOCstart;
}
else
relplt = NULL;
}
- rela.r_addend = (h->root.u.def.value
- + h->root.u.def.section->output_offset
- + h->root.u.def.section->output_section->vma
- + ent->addend);
+ rela.r_addend = defined_sym_val (h) + ent->addend;
if (relplt == NULL)
{
if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
lplt - local_plt, ibfd))
{
- if (local_syms != NULL
- && symtab_hdr->contents != (unsigned char *) local_syms)
+ if (symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
return FALSE;
}
return TRUE;
}
+/* Emit the static wrapper function preserving registers around a
+ __tls_get_addr_opt call. */
+
+static bfd_boolean
+emit_tga_desc (struct ppc_link_hash_table *htab)
+{
+ asection *stub_sec = htab->tga_group->stub_sec;
+ unsigned int cfa_updt = 11 * 4;
+ bfd_byte *p;
+ bfd_vma to, from, delta;
+
+ BFD_ASSERT (htab->tga_desc_fd->elf.root.type == bfd_link_hash_defined
+ && htab->tga_desc_fd->elf.root.u.def.section == stub_sec
+ && htab->tga_desc_fd->elf.root.u.def.value == 0);
+ to = defined_sym_val (&htab->tls_get_addr_fd->elf);
+ from = defined_sym_val (&htab->tga_desc_fd->elf) + cfa_updt;
+ delta = to - from;
+ if (delta + (1 << 25) >= 1 << 26)
+ {
+ _bfd_error_handler (_("__tls_get_addr call offset overflow"));
+ htab->stub_error = TRUE;
+ return FALSE;
+ }
+
+ p = stub_sec->contents;
+ p = tls_get_addr_prologue (htab->elf.dynobj, p, htab);
+ bfd_put_32 (stub_sec->owner, B_DOT | 1 | (delta & 0x3fffffc), p);
+ p += 4;
+ p = tls_get_addr_epilogue (htab->elf.dynobj, p, htab);
+ return stub_sec->size == (bfd_size_type) (p - stub_sec->contents);
+}
+
+/* Emit eh_frame describing the static wrapper function. */
+
+static bfd_byte *
+emit_tga_desc_eh_frame (struct ppc_link_hash_table *htab, bfd_byte *p)
+{
+ unsigned int cfa_updt = 11 * 4;
+ unsigned int i;
+
+ *p++ = DW_CFA_advance_loc + cfa_updt / 4;
+ *p++ = DW_CFA_def_cfa_offset;
+ if (htab->opd_abi)
+ {
+ *p++ = 128;
+ *p++ = 1;
+ }
+ else
+ *p++ = 96;
+ *p++ = DW_CFA_offset_extended_sf;
+ *p++ = 65;
+ *p++ = (-16 / 8) & 0x7f;
+ for (i = 4; i < 12; i++)
+ {
+ *p++ = DW_CFA_offset + i;
+ *p++ = (htab->opd_abi ? 13 : 12) - i;
+ }
+ *p++ = DW_CFA_advance_loc + 10;
+ *p++ = DW_CFA_def_cfa_offset;
+ *p++ = 0;
+ for (i = 4; i < 12; i++)
+ *p++ = DW_CFA_restore + i;
+ *p++ = DW_CFA_advance_loc + 2;
+ *p++ = DW_CFA_restore_extended;
+ *p++ = 65;
+ return p;
+}
+
/* Build all the stubs associated with the current output file.
The stubs are kept in a hash table attached to the main linker
hash table. This function is called via gldelf64ppc_finish. */
}
}
+ if (htab->tga_group != NULL)
+ {
+ htab->tga_group->lr_restore = 23 * 4;
+ htab->tga_group->stub_sec->size = 24 * 4;
+ if (!emit_tga_desc (htab))
+ return FALSE;
+ if (htab->glink_eh_frame != NULL
+ && htab->glink_eh_frame->size != 0)
+ {
+ size_t align = 4;
+
+ p = htab->glink_eh_frame->contents;
+ p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
+ p += 17;
+ htab->tga_group->eh_size = emit_tga_desc_eh_frame (htab, p) - p;
+ }
+ }
+
/* Build .glink global entry stubs, and PLT relocs for globals. */
elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info);
if (stats != NULL)
{
- size_t len;
- *stats = bfd_malloc (500);
- if (*stats == NULL)
- return FALSE;
-
- len = sprintf (*stats,
- ngettext ("linker stubs in %u group\n",
- "linker stubs in %u groups\n",
- stub_sec_count),
- stub_sec_count);
- sprintf (*stats + len, _(" branch %lu\n"
- " branch toc adj %lu\n"
- " branch notoc %lu\n"
- " branch both %lu\n"
- " long branch %lu\n"
- " long toc adj %lu\n"
- " long notoc %lu\n"
- " long both %lu\n"
- " plt call %lu\n"
- " plt call save %lu\n"
- " plt call notoc %lu\n"
- " plt call both %lu\n"
- " global entry %lu"),
- htab->stub_count[ppc_stub_long_branch - 1],
- htab->stub_count[ppc_stub_long_branch_r2off - 1],
- htab->stub_count[ppc_stub_long_branch_notoc - 1],
- htab->stub_count[ppc_stub_long_branch_both - 1],
- htab->stub_count[ppc_stub_plt_branch - 1],
- htab->stub_count[ppc_stub_plt_branch_r2off - 1],
- htab->stub_count[ppc_stub_plt_branch_notoc - 1],
- htab->stub_count[ppc_stub_plt_branch_both - 1],
- htab->stub_count[ppc_stub_plt_call - 1],
- htab->stub_count[ppc_stub_plt_call_r2save - 1],
- htab->stub_count[ppc_stub_plt_call_notoc - 1],
- htab->stub_count[ppc_stub_plt_call_both - 1],
- htab->stub_count[ppc_stub_global_entry - 1]);
+ char *groupmsg;
+ if (asprintf (&groupmsg,
+ ngettext ("linker stubs in %u group\n",
+ "linker stubs in %u groups\n",
+ stub_sec_count),
+ stub_sec_count) < 0)
+ *stats = NULL;
+ else
+ {
+ if (asprintf (stats, _("%s"
+ " branch %lu\n"
+ " branch toc adj %lu\n"
+ " branch notoc %lu\n"
+ " branch both %lu\n"
+ " long branch %lu\n"
+ " long toc adj %lu\n"
+ " long notoc %lu\n"
+ " long both %lu\n"
+ " plt call %lu\n"
+ " plt call save %lu\n"
+ " plt call notoc %lu\n"
+ " plt call both %lu\n"
+ " global entry %lu"),
+ groupmsg,
+ htab->stub_count[ppc_stub_long_branch - 1],
+ htab->stub_count[ppc_stub_long_branch_r2off - 1],
+ htab->stub_count[ppc_stub_long_branch_notoc - 1],
+ htab->stub_count[ppc_stub_long_branch_both - 1],
+ htab->stub_count[ppc_stub_plt_branch - 1],
+ htab->stub_count[ppc_stub_plt_branch_r2off - 1],
+ htab->stub_count[ppc_stub_plt_branch_notoc - 1],
+ htab->stub_count[ppc_stub_plt_branch_both - 1],
+ htab->stub_count[ppc_stub_plt_call - 1],
+ htab->stub_count[ppc_stub_plt_call_r2save - 1],
+ htab->stub_count[ppc_stub_plt_call_notoc - 1],
+ htab->stub_count[ppc_stub_plt_call_both - 1],
+ htab->stub_count[ppc_stub_global_entry - 1]) < 0)
+ *stats = NULL;
+ free (groupmsg);
+ }
}
return TRUE;
}
return _bfd_elf_default_action_discarded (sec);
}
+/* These are the dynamic relocations supported by glibc. */
+
+static bfd_boolean
+ppc64_glibc_dynamic_reloc (enum elf_ppc64_reloc_type r_type)
+{
+ switch (r_type)
+ {
+ case R_PPC64_RELATIVE:
+ case R_PPC64_NONE:
+ case R_PPC64_ADDR64:
+ case R_PPC64_GLOB_DAT:
+ case R_PPC64_IRELATIVE:
+ case R_PPC64_JMP_IREL:
+ case R_PPC64_JMP_SLOT:
+ case R_PPC64_DTPMOD64:
+ case R_PPC64_DTPREL64:
+ case R_PPC64_TPREL64:
+ case R_PPC64_TPREL16_LO_DS:
+ case R_PPC64_TPREL16_DS:
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_HIGH:
+ case R_PPC64_TPREL16_HA:
+ case R_PPC64_TPREL16_HIGHA:
+ case R_PPC64_TPREL16_HIGHER:
+ case R_PPC64_TPREL16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHESTA:
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_LO:
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_ADDR16_HIGH:
+ case R_PPC64_ADDR16_HA:
+ case R_PPC64_ADDR16_HIGHA:
+ case R_PPC64_REL30:
+ case R_PPC64_COPY:
+ case R_PPC64_UADDR64:
+ case R_PPC64_UADDR32:
+ case R_PPC64_ADDR32:
+ case R_PPC64_ADDR24:
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ case R_PPC64_ADDR16_DS:
+ case R_PPC64_ADDR16_HIGHER:
+ case R_PPC64_ADDR16_HIGHEST:
+ case R_PPC64_ADDR16_HIGHERA:
+ case R_PPC64_ADDR16_HIGHESTA:
+ case R_PPC64_ADDR14:
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ case R_PPC64_REL32:
+ case R_PPC64_REL64:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
/* The RELOCATE_SECTION function is called by the ELF backend linker
to handle the relocations for a section.
bfd_boolean is_opd;
/* Assume 'at' branch hints. */
bfd_boolean is_isa_v2 = TRUE;
+ bfd_boolean warned_dynamic = FALSE;
bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
/* Initialize howto table if needed. */
}
}
}
- h = (struct ppc_link_hash_entry *) h_elf;
+ h = ppc_elf_hash_entry (h_elf);
if (sec != NULL && discarded_section (sec))
{
case R_PPC64_LO_DS_OPT:
insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset);
- if ((insn & (0x3f << 26)) != 58u << 26)
+ if ((insn & (0x3fu << 26)) != 58u << 26)
abort ();
insn += (14u << 26) - (58u << 26);
bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset);
}
break;
+ case R_PPC64_GOT_TPREL34:
+ if ((tls_mask & TLS_TLS) != 0
+ && (tls_mask & TLS_TPREL) == 0)
+ {
+ /* pld ra,sym@got@tprel@pcrel -> paddi ra,r13,sym@tprel */
+ pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ pinsn += ((2ULL << 56) + (-1ULL << 52)
+ + (14ULL << 26) - (57ULL << 26) + (13ULL << 16));
+ bfd_put_32 (input_bfd, pinsn >> 32,
+ contents + rel->r_offset);
+ bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+ contents + rel->r_offset + 4);
+ r_type = R_PPC64_TPREL34;
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ }
+ break;
+
case R_PPC64_TLS:
if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & TLS_TPREL) == 0)
{
- insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
if (insn == 0)
- abort ();
- bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
- /* Was PPC64_TLS which sits on insn boundary, now
- PPC64_TPREL16_LO which is at low-order half-word. */
- rel->r_offset += d_offset;
- r_type = R_PPC64_TPREL16_LO;
- if (toc_symndx != 0)
+ break;
+ if ((rel->r_offset & 3) == 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. */
- goto again;
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ /* Was PPC64_TLS which sits on insn boundary, now
+ PPC64_TPREL16_LO which is at low-order half-word. */
+ rel->r_offset += d_offset;
+ r_type = R_PPC64_TPREL16_LO;
+ 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. */
+ goto again;
+ }
+ else
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ }
+ else if ((rel->r_offset & 3) == 1)
+ {
+ /* For pcrel IE to LE we already have the full
+ offset and thus don't need an addi here. A nop
+ or mr will do. */
+ if ((insn & (0x3fu << 26)) == 14 << 26)
+ {
+ /* Extract regs from addi rt,ra,si. */
+ unsigned int rt = (insn >> 21) & 0x1f;
+ unsigned int ra = (insn >> 16) & 0x1f;
+ if (rt == ra)
+ insn = NOP;
+ else
+ {
+ /* Build or ra,rs,rb with rb==rs, ie. mr ra,rs. */
+ insn = (rt << 16) | (ra << 21) | (ra << 11);
+ insn |= (31u << 26) | (444u << 1);
+ }
+ }
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset - 1);
}
- else
- rel->r_info = ELF64_R_INFO (r_symndx, r_type);
}
break;
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
+ if (input_section->nomark_tls_get_addr
&& rel + 1 < relend
&& branch_reloc_hash_match (input_bfd, rel + 1,
+ htab->tls_get_addr_fd,
+ htab->tga_desc_fd,
htab->tls_get_addr,
- htab->tls_get_addr_fd))
+ htab->tga_desc))
offset = rel[1].r_offset;
/* We read the low GOT_TLS (or TOC16) insn because we
need to keep the destination reg. It may be
{
/* IE */
insn1 &= (0x1f << 21) | (0x1f << 16);
- insn1 |= 58 << 26; /* ld */
+ insn1 |= 58u << 26; /* ld */
insn2 = 0x7c636a14; /* add 3,3,13 */
if (offset != (bfd_vma) -1)
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
}
break;
+ case R_PPC64_GOT_TLSGD34:
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+ {
+ pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ if ((tls_mask & TLS_GDIE) != 0)
+ {
+ /* IE, pla -> pld */
+ pinsn += (-2ULL << 56) + (57ULL << 26) - (14ULL << 26);
+ r_type = R_PPC64_GOT_TPREL34;
+ }
+ else
+ {
+ /* LE, pla pcrel -> paddi r13 */
+ pinsn += (-1ULL << 52) + (13ULL << 16);
+ r_type = R_PPC64_TPREL34;
+ }
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ bfd_put_32 (input_bfd, pinsn >> 32,
+ contents + rel->r_offset);
+ bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+ contents + rel->r_offset + 4);
+ }
+ break;
+
+ case R_PPC64_GOT_TLSLD34:
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+ {
+ pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ pinsn += (-1ULL << 52) + (13ULL << 16);
+ bfd_put_32 (input_bfd, pinsn >> 32,
+ contents + rel->r_offset);
+ bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+ contents + rel->r_offset + 4);
+ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+ r_symndx = STN_UNDEF;
+ r_type = R_PPC64_TPREL34;
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ goto again;
+ }
+ break;
+
case R_PPC64_TLSGD:
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
&& rel + 1 < relend)
r_symndx = toc_symndx;
rel->r_addend = toc_addend;
}
- r_type = R_PPC64_TPREL16_LO;
- rel->r_offset = offset + d_offset;
- insn2 = 0x38630000; /* addi 3,3,0 */
+ if (r_type1 == R_PPC64_REL24_NOTOC
+ || r_type1 == R_PPC64_PLTCALL_NOTOC)
+ {
+ r_type = R_PPC64_NONE;
+ insn2 = NOP;
+ }
+ else
+ {
+ rel->r_offset = offset + d_offset;
+ r_type = R_PPC64_TPREL16_LO;
+ insn2 = 0x38630000; /* addi 3,3,0 */
+ }
}
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
/* Zap the reloc on the _tls_get_addr call too. */
BFD_ASSERT (offset == rel[1].r_offset);
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
bfd_put_32 (input_bfd, insn2, contents + offset);
- if ((tls_mask & TLS_GDIE) == 0 && toc_symndx != 0)
+ if ((tls_mask & TLS_GDIE) == 0
+ && toc_symndx != 0
+ && r_type != R_PPC64_NONE)
goto again;
}
break;
if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
bfd_put_32 (output_bfd, NOP, contents + offset + 4);
- rel->r_offset = offset + d_offset;
- r_symndx = STN_UNDEF;
- r_type = R_PPC64_TPREL16_LO;
+ if (r_type1 == R_PPC64_REL24_NOTOC
+ || r_type1 == R_PPC64_PLTCALL_NOTOC)
+ {
+ r_type = R_PPC64_NONE;
+ insn2 = NOP;
+ }
+ else
+ {
+ rel->r_offset = offset + d_offset;
+ r_symndx = STN_UNDEF;
+ r_type = R_PPC64_TPREL16_LO;
+ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+ insn2 = 0x38630000; /* addi 3,3,0 */
+ }
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
- rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-
/* Zap the reloc on the _tls_get_addr call too. */
BFD_ASSERT (offset == rel[1].r_offset);
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
- insn2 = 0x38630000; /* addi 3,3,0 */
bfd_put_32 (input_bfd, insn2, contents + offset);
- goto again;
+ if (r_type != R_PPC64_NONE)
+ goto again;
}
break;
|| nop == CROR_313131)
{
if (h != NULL
- && (h == htab->tls_get_addr_fd
- || h == htab->tls_get_addr)
+ && is_tls_get_addr (&h->elf, htab)
&& htab->params->tls_get_addr_opt)
{
/* Special stub used, leave nop alone. */
|| stub_entry->stub_type == ppc_stub_plt_call_r2save
|| stub_entry->stub_type == ppc_stub_plt_call_both)
&& !(h != NULL
- && (h == htab->tls_get_addr_fd
- || h == htab->tls_get_addr)
+ && is_tls_get_addr (&h->elf, htab)
&& htab->params->tls_get_addr_opt)
&& rel + 1 < relend
&& rel[1].r_offset == rel->r_offset + 4
break;
case R_PPC64_GOT16_DS:
+ if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
+ break;
from = TOCstart + htab->sec_info[input_section->id].toc_off;
if (relocation + addend - from + 0x8000 < 0x10000
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))
{
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
- if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */)
+ if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
{
insn += (14u << 26) - (58u << 26);
bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3));
case R_PPC64_GOT16_LO_DS:
case R_PPC64_GOT16_HA:
+ if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
+ break;
from = TOCstart + htab->sec_info[input_section->id].toc_off;
if (relocation + addend - from + 0x80008000ULL < 0x100000000ULL
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))
{
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
- if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */)
+ if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
{
insn += (14u << 26) - (58u << 26);
bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3));
r_type = R_PPC64_TOC16_LO;
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
}
- else if ((insn & (0x3f << 26)) == 15u << 26 /* addis */)
+ else if ((insn & (0x3fu << 26)) == 15u << 26 /* addis */)
{
r_type = R_PPC64_TOC16_HA;
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
break;
case R_PPC64_GOT_PCREL34:
+ if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
+ break;
from = (rel->r_offset
+ input_section->output_section->vma
+ input_section->output_offset);
if (off2 + 4 <= input_section->size)
{
uint64_t pinsn2;
+ bfd_signed_vma addend_off;
pinsn2 = bfd_get_32 (input_bfd, contents + off2);
pinsn2 <<= 32;
if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
- break;
- if (xlate_pcrel_opt (&pinsn, &pinsn2))
{
+ if (off2 + 8 > input_section->size)
+ break;
+ pinsn2 |= bfd_get_32 (input_bfd,
+ contents + off2 + 4);
+ }
+ if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off))
+ {
+ addend += addend_off;
+ rel->r_addend = addend;
bfd_put_32 (input_bfd, pinsn >> 32,
contents + offset);
bfd_put_32 (input_bfd, pinsn,
contents + offset + 4);
bfd_put_32 (input_bfd, pinsn2 >> 32,
contents + off2);
+ if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
+ bfd_put_32 (input_bfd, pinsn2,
+ contents + off2 + 4);
}
}
}
break;
}
- /* Set `addend'. */
tls_type = 0;
save_unresolved_reloc = unresolved_reloc;
switch (r_type)
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TLSGD34:
tls_type = TLS_TLS | TLS_GD;
goto dogot;
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSLD34:
tls_type = TLS_TLS | TLS_LD;
goto dogot;
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_TPREL34:
tls_type = TLS_TLS | TLS_TPREL;
goto dogot;
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT_DTPREL34:
tls_type = TLS_TLS | TLS_DTPREL;
goto dogot;
bfd_vma off;
unsigned long indx = 0;
struct got_entry *ent;
- bfd_vma sym_addend = orig_rel.r_addend;
-
- if (r_type == R_PPC64_GOT_PCREL34)
- sym_addend = 0;
if (tls_type == (TLS_TLS | TLS_LD)
- && (h == NULL
- || !h->elf.def_dynamic))
+ && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
ent = ppc64_tlsld_got (input_bfd);
else
{
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == orig_rel.r_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
else if (indx != 0
|| (bfd_link_pic (info)
&& (h == NULL
- || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)
- || (tls_type == (TLS_TLS | TLS_LD)
- && !h->elf.def_dynamic))
- && !(tls_type == (TLS_TLS | TLS_TPREL)
+ || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf))
+ && !(tls_type != 0
&& bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))))
relgot = ppc64_elf_tdata (ent->owner)->relgot;
outrel.r_offset = (got->output_section->vma
+ got->output_offset
+ off);
- outrel.r_addend = sym_addend;
+ outrel.r_addend = orig_rel.r_addend;
if (tls_type & (TLS_LD | TLS_GD))
{
outrel.r_addend = 0;
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
outrel.r_offset += 8;
- outrel.r_addend = sym_addend;
+ outrel.r_addend = orig_rel.r_addend;
outrel.r_info
= ELF64_R_INFO (indx, R_PPC64_DTPREL64);
}
emitting a reloc. */
else
{
- relocation += sym_addend;
+ relocation += orig_rel.r_addend;
if (tls_type != 0)
{
if (htab->elf.tls_sec == NULL)
abort ();
relocation = got->output_section->vma + got->output_offset + off;
- if (r_type != R_PPC64_GOT_PCREL34)
+ addend = 0;
+ if (!(r_type == R_PPC64_GOT_PCREL34
+ || r_type == R_PPC64_GOT_TLSGD34
+ || r_type == R_PPC64_GOT_TLSLD34
+ || r_type == R_PPC64_GOT_TPREL34
+ || r_type == R_PPC64_GOT_DTPREL34))
addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
}
break;
if (plt_list)
{
struct plt_entry *ent;
- bfd_vma sym_addend = orig_rel.r_addend;
-
- if (r_type == R_PPC64_PLT_PCREL34
- || r_type == R_PPC64_PLT_PCREL34_NOTOC)
- sym_addend = 0;
for (ent = *plt_list; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1
- && ent->addend == sym_addend)
+ && ent->addend == orig_rel.r_addend)
{
asection *plt;
bfd_vma got;
+ htab->sec_info[input_section->id].toc_off);
relocation -= got;
}
- if (r_type != R_PPC64_PLT_PCREL34
- && r_type != R_PPC64_PLT_PCREL34_NOTOC)
- addend = 0;
+ addend = 0;
unresolved_reloc = FALSE;
break;
}
case R_PPC64_TOC16_LO_DS:
case R_PPC64_TOC16_HA:
addend -= TOCstart + htab->sec_info[input_section->id].toc_off;
+ if (h != NULL)
+ goto dodyn;
break;
/* Relocate against the beginning of the section. */
case R_PPC64_TPREL16_HIGHERA:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
+ case R_PPC64_TPREL34:
if (h != NULL
&& h->elf.root.type == bfd_link_hash_undefweak
&& h->elf.dynindx == -1)
case R_PPC64_DTPREL16_HIGHERA:
case R_PPC64_DTPREL16_HIGHEST:
case R_PPC64_DTPREL16_HIGHESTA:
+ case R_PPC64_DTPREL34:
if (htab->elf.tls_sec != NULL)
addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
break;
loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+ if (!warned_dynamic
+ && !ppc64_glibc_dynamic_reloc (ELF64_R_TYPE (outrel.r_info)))
+ {
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%P: %pB: %s against %pT "
+ "is not supported by glibc as a dynamic relocation\n"),
+ input_bfd,
+ ppc64_elf_howto_table[ELF64_R_TYPE (outrel.r_info)]->name,
+ sym_name);
+ warned_dynamic = TRUE;
+ }
+
/* If this reloc is against an external symbol, it will
be computed at runtime, so there's no need to do
anything now. However, for the sake of prelink ensure
{
bfd_byte *p = contents + (rel->r_offset & ~3);
insn = bfd_get_32 (input_bfd, p);
- if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
+ if ((insn & (0x3fu << 26)) == 12u << 26 /* addic */)
{
/* Transform addic to addi when we change reg. */
- insn &= ~((0x3f << 26) | (0x1f << 16));
+ insn &= ~((0x3fu << 26) | (0x1f << 16));
insn |= (14u << 26) | (2 << 16);
}
else
{
bfd_byte *p = contents + (rel->r_offset & ~3);
insn = bfd_get_32 (input_bfd, p);
- if ((insn & ((0x3f << 26) | 0x1f << 16))
+ if ((insn & ((0x3fu << 26) | 0x1f << 16))
!= ((15u << 26) | (13 << 16)) /* addis rt,13,imm */)
/* xgettext:c-format */
info->callbacks->minfo
forms of all the _DS relocs bloats all reloc switches in
this file. It doesn't make much sense to use these
relocs in data, so testing the insn should be safe. */
- if ((insn & (0x3f << 26)) == (56u << 26)
- || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1))
+ if ((insn & (0x3fu << 26)) == (56u << 26)
+ || ((insn & (0x3fu << 26)) == (61u << 26) && (insn & 3) == 1))
mask = 15;
relocation += addend;
addend = insn & (mask ^ 3);
enum complain_overflow complain = complain_overflow_signed;
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
- if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+ if ((insn & (0x3fu << 26)) == 10u << 26 /* cmpli */)
complain = complain_overflow_bitfield;
else if (howto->rightshift == 0
- ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
- || (insn & (0x3f << 26)) == 24u << 26 /* ori */
- || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
- : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
- || (insn & (0x3f << 26)) == 25u << 26 /* oris */
- || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+ ? ((insn & (0x3fu << 26)) == 28u << 26 /* andi */
+ || (insn & (0x3fu << 26)) == 24u << 26 /* ori */
+ || (insn & (0x3fu << 26)) == 26u << 26 /* xori */)
+ : ((insn & (0x3fu << 26)) == 29u << 26 /* andis */
+ || (insn & (0x3fu << 26)) == 25u << 26 /* oris */
+ || (insn & (0x3fu << 26)) == 27u << 26 /* xoris */))
complain = complain_overflow_unsigned;
if (howto->complain_on_overflow != complain)
{
case R_PPC64_D34_HA30:
case R_PPC64_PCREL34:
case R_PPC64_GOT_PCREL34:
+ case R_PPC64_TPREL34:
+ case R_PPC64_DTPREL34:
+ case R_PPC64_GOT_TLSGD34:
+ case R_PPC64_GOT_TLSLD34:
+ case R_PPC64_GOT_TPREL34:
+ case R_PPC64_GOT_DTPREL34:
case R_PPC64_PLT_PCREL34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_D28:
reloc_name, sym_name, (int) r);
ret = FALSE;
}
- if (more_info != NULL)
- free (more_info);
+ free (more_info);
}
copy_reloc:
if (wrel != rel)
break;
}
- if (h->needs_copy)
+ if (h->needs_copy
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && (h->root.u.def.section == htab->elf.sdynbss
+ || h->root.u.def.section == htab->elf.sdynrelro))
{
/* This symbol needs a copy reloc. Set it up. */
Elf_Internal_Rela rela;
asection *srel;
bfd_byte *loc;
- if (h->dynindx == -1
- || (h->root.type != bfd_link_hash_defined
- && h->root.type != bfd_link_hash_defweak)
- || htab->elf.srelbss == NULL
- || htab->elf.sreldynrelro == NULL)
+ if (h->dynindx == -1)
abort ();
- rela.r_offset = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
+ rela.r_offset = defined_sym_val (h);
rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY);
rela.r_addend = 0;
if (h->root.u.def.section == htab->elf.sdynrelro)