/* PowerPC64-specific support for 64-bit ELF.
- Copyright (C) 1999-2019 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
based on elf32-ppc.c by Ian Lance Taylor.
Largely rewritten by Alan Modra.
#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
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)
{
free_contents_and_exit_err:
count = -1;
free_contents_and_exit:
- if (contents)
- free (contents);
+ free (contents);
goto done;
}
}
/* 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;
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)
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;
case R_PPC64_PLT_PCREL34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PCREL28:
- htab->powerxx_stubs = 1;
+ htab->power10_stubs = 1;
break;
default:
break;
/* 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,
rel->r_addend,
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 == rel->r_addend
&& ent->owner == abfd
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;
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
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, rel->r_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)
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)
{
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,
rel->r_addend, tls_type))
&& 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. */
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
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;
}
|| 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;
{
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;
}
if (pass == 0
&& 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))
{
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)
{
{
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;
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 & 1) != 0)
return FALSE;
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;
}
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 (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;
|| 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;
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
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))
&& 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;
}
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_R11, p), p += 4;
- bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4;
+ 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);
+ 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_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;
+ 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);
+
+ if (r != NULL)
+ r[0].r_offset += 18 * 4;
+
+ p = build_plt_stub (htab, stub_entry, p, offset, r);
+ bfd_put_32 (obfd, BCTRL, 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)
/* 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;
}
}
}
}
- h = (struct ppc_link_hash_entry *) h_elf;
+ h = ppc_elf_hash_entry (h_elf);
if (sec != NULL && discarded_section (sec))
{
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
|| 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))
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))
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);
reloc_name, sym_name, (int) r);
ret = FALSE;
}
- if (more_info != NULL)
- free (more_info);
+ free (more_info);
}
copy_reloc:
if (wrel != rel)
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)