/* Whether func_desc_adjust needs to be run over symbols. */
unsigned int need_func_desc_adj:1;
- /* Whether there exist local gnu indirect function resolvers,
- referenced by dynamic relocations. */
- unsigned int local_ifunc_resolver:1;
-
/* Whether plt calls for ELFv2 localentry:0 funcs have been optimized. */
unsigned int has_plt_localentry0:1;
/* Whether calls are made via the PLT from NOTOC functions. */
unsigned int notoc_plt:1;
- /* Whether to use power10 instructions in linkage stubs. */
- unsigned int power10_stubs:1;
+ /* Whether any code linked seems to be Power10. */
+ unsigned int has_power10_relocs:1;
/* Incremented every time we size stubs. */
unsigned int stub_iteration;
-
- /* Small local sym cache. */
- struct sym_cache sym_cache;
};
/* Rename some of the generic section flags to better document how they
return stub_name;
}
+/* If mixing power10 with non-power10 code and --power10-stubs is not
+ specified (or is auto) then calls using @notoc relocations that
+ need a stub will utilize power10 instructions in the stub, and
+ calls without @notoc relocations will not use power10 instructions.
+ The two classes of stubs are stored in separate stub_hash_table
+ entries having the same key string. The two entries will always be
+ adjacent on entry->root.next chain, even if hash table resizing
+ occurs. This function selects the correct entry to use. */
+
+static struct ppc_stub_hash_entry *
+select_alt_stub (struct ppc_stub_hash_entry *entry, bfd_boolean notoc)
+{
+ bfd_boolean have_notoc;
+
+ have_notoc = (entry->stub_type == ppc_stub_plt_call_notoc
+ || entry->stub_type == ppc_stub_plt_branch_notoc
+ || entry->stub_type == ppc_stub_long_branch_notoc);
+
+ if (have_notoc != notoc)
+ {
+ const char *stub_name = entry->root.string;
+
+ entry = (struct ppc_stub_hash_entry *) entry->root.next;
+ if (entry != NULL
+ && entry->root.string != stub_name)
+ entry = NULL;
+ }
+
+ return entry;
+}
+
/* Look up an entry in the stub hash. Stub entries are cached because
creating the stub name takes a bit of time. */
free (stub_name);
}
+ if (stub_entry != NULL && htab->params->power10_stubs == -1)
+ {
+ bfd_boolean notoc = ELF64_R_TYPE (rel->r_info) == R_PPC64_REL24_NOTOC;
+
+ stub_entry = select_alt_stub (stub_entry, notoc);
+ }
+
return stub_entry;
}
Elf_Internal_Sym *isym;
asection *s;
- isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, r_symndx);
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, ibfd,
+ r_symndx);
if (isym == NULL)
{
if (elf_section_data (opd)->relocs != relocs)
case R_PPC64_PLT_PCREL34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PCREL28:
- htab->power10_stubs = 1;
+ htab->has_power10_relocs = 1;
break;
default:
break;
}
else
{
- Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
{
Elf_Internal_Sym *isym;
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
void *vpp;
Elf_Internal_Sym *isym;
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
{
- if (htab->power10_stubs)
+ if (htab->params->power10_stubs != 0)
{
bfd_vma start = (stub_entry->stub_offset
+ stub_entry->group->stub_sec->output_offset
relp = p;
num_rel = 0;
- if (htab->power10_stubs)
+ if (htab->params->power10_stubs != 0)
{
bfd_boolean load = stub_entry->stub_type >= ppc_stub_plt_call_notoc;
p = build_power10_offset (htab->params->stub_bfd, p, off, odd, load);
if (info->emitrelocations)
{
bfd_vma roff = relp - stub_entry->group->stub_sec->contents;
- if (htab->power10_stubs)
+ if (htab->params->power10_stubs != 0)
num_rel += num_relocs_for_power10_offset (off, odd);
else
{
r = get_relocs (stub_entry->group->stub_sec, num_rel);
if (r == NULL)
return FALSE;
- if (htab->power10_stubs)
+ if (htab->params->power10_stubs != 0)
r = emit_relocs_for_power10_offset (info, r, roff, targ, off, odd);
else
r = emit_relocs_for_offset (info, r, roff, targ, off);
}
}
- if (!htab->power10_stubs
+ if (htab->params->power10_stubs == 0
&& htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->size != 0)
{
if (info->emitrelocations)
{
unsigned int num_rel;
- if (htab->power10_stubs)
+ if (htab->params->power10_stubs != 0)
num_rel = num_relocs_for_power10_offset (off, odd);
else
num_rel = num_relocs_for_offset (off - 8);
stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
- if (htab->power10_stubs)
+ if (htab->params->power10_stubs != 0)
extra = size_power10_offset (off, odd);
else
extra = size_offset (off - 8);
calculated. */
off -= extra;
- if (!htab->power10_stubs)
+ if (htab->params->power10_stubs == 0)
{
/* 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->power10_stubs)
+ if (htab->params->power10_stubs != 0)
num_rel = num_relocs_for_power10_offset (off, odd);
else
num_rel = num_relocs_for_offset (off - 8);
size = plt_stub_size (htab, stub_entry, off);
- if (!htab->power10_stubs)
+ if (htab->params->power10_stubs == 0)
{
/* After the bcl, lr has been modified so we need to emit
.eh_frame info saying the return address is in r12. */
if (htab == NULL)
return FALSE;
+ if (htab->params->power10_stubs == -1 && !htab->has_power10_relocs)
+ htab->params->power10_stubs = 0;
+
if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info))
htab->params->plt_thread_safe = 1;
if (!htab->opd_abi)
if (stub_entry != NULL)
{
enum ppc_stub_type old_type;
+
/* A stub has already been created, but it may
not be the required type. We shouldn't be
transitioning from plt_call to long_branch
upgrading from plt_call to plt_call_r2save or
from long_branch to long_branch_r2off. */
free (stub_name);
+ if (htab->params->power10_stubs == -1)
+ {
+ /* For --power10-stubs=auto, don't merge _notoc
+ and other varieties of stubs. (The _both
+ variety won't be created.) */
+ bfd_boolean notoc = r_type == R_PPC64_REL24_NOTOC;
+ struct ppc_stub_hash_entry *alt_stub
+ = select_alt_stub (stub_entry, notoc);
+
+ if (alt_stub == NULL)
+ {
+ alt_stub = (struct ppc_stub_hash_entry *)
+ stub_hash_newfunc (NULL,
+ &htab->stub_hash_table,
+ stub_entry->root.string);
+ if (alt_stub == NULL)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler
+ (_("%pB: cannot create stub entry %s"),
+ section->owner, stub_entry->root.string);
+ goto error_ret_free_internal;
+ }
+ *alt_stub = *stub_entry;
+ stub_entry->root.next = &alt_stub->root;
+ if (notoc)
+ /* Sort notoc stubs first, for no good
+ reason. */
+ alt_stub = stub_entry;
+ alt_stub->stub_type = stub_type;
+ }
+ stub_entry = alt_stub;
+ }
old_type = stub_entry->stub_type;
switch (old_type)
{
{
plt = htab->elf.iplt;
relplt = htab->elf.irelplt;
- htab->local_ifunc_resolver = 1;
+ htab->elf.ifunc_resolvers = TRUE;
if (htab->opd_abi)
rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
else
+ ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
/ PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
if (h->type == STT_GNU_IFUNC && is_static_defined (h))
- htab->local_ifunc_resolver = 1;
+ htab->elf.ifunc_resolvers = TRUE;
bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
}
}
if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
- htab->local_ifunc_resolver = 1;
+ htab->elf.ifunc_resolvers = TRUE;
plt = htab->elf.iplt;
relplt = htab->elf.irelplt;
}
break;
case R_PPC64_GOT16_DS:
- if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
+ if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+ || !htab->do_toc_opt)
break;
from = TOCstart + htab->sec_info[input_section->id].toc_off;
if (relocation + addend - from + 0x8000 < 0x10000
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)
+ if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+ || !htab->do_toc_opt)
break;
from = TOCstart + htab->sec_info[input_section->id].toc_off;
if (relocation + addend - from + 0x80008000ULL < 0x100000000ULL
break;
case R_PPC64_GOT_PCREL34:
- if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
+ if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+ || !htab->do_toc_opt)
break;
from = (rel->r_offset
+ input_section->output_section->vma
+ input_section->output_offset);
- if (relocation - from + (1ULL << 33) < 1ULL << 34
- && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
- {
- offset = rel->r_offset;
- pinsn = bfd_get_32 (input_bfd, contents + offset);
- pinsn <<= 32;
- pinsn |= bfd_get_32 (input_bfd, contents + offset + 4);
- if ((pinsn & ((-1ULL << 50) | (63ULL << 26)))
- == ((1ULL << 58) | (1ULL << 52) | (57ULL << 26) /* pld */))
- {
- /* Replace with paddi. */
- pinsn += (2ULL << 56) + (14ULL << 26) - (57ULL << 26);
- r_type = R_PPC64_PCREL34;
- rel->r_info = ELF64_R_INFO (r_symndx, r_type);
- bfd_put_32 (input_bfd, pinsn >> 32, contents + offset);
- bfd_put_32 (input_bfd, pinsn, contents + offset + 4);
- goto pcrelopt;
- }
- }
- break;
+ if (!(relocation - from + (1ULL << 33) < 1ULL << 34
+ && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
+ break;
+
+ offset = rel->r_offset;
+ pinsn = bfd_get_32 (input_bfd, contents + offset);
+ pinsn <<= 32;
+ pinsn |= bfd_get_32 (input_bfd, contents + offset + 4);
+ if ((pinsn & ((-1ULL << 50) | (63ULL << 26)))
+ != ((1ULL << 58) | (1ULL << 52) | (57ULL << 26) /* pld */))
+ break;
+
+ /* Replace with paddi. */
+ pinsn += (2ULL << 56) + (14ULL << 26) - (57ULL << 26);
+ r_type = R_PPC64_PCREL34;
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ bfd_put_32 (input_bfd, pinsn >> 32, contents + offset);
+ bfd_put_32 (input_bfd, pinsn, contents + offset + 4);
+ /* Fall through. */
case R_PPC64_PCREL34:
- if (SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+ if (!htab->params->no_pcrel_opt
+ && rel + 1 < relend
+ && rel[1].r_offset == rel->r_offset
+ && rel[1].r_info == ELF64_R_INFO (0, R_PPC64_PCREL_OPT)
+ && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
{
offset = rel->r_offset;
pinsn = bfd_get_32 (input_bfd, contents + offset);
== ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
| (14ULL << 26) /* paddi */))
{
- pcrelopt:
- if (rel + 1 < relend
- && rel[1].r_offset == offset
- && rel[1].r_info == ELF64_R_INFO (0, R_PPC64_PCREL_OPT))
+ bfd_vma off2 = rel[1].r_addend;
+ if (off2 == 0)
+ /* zero means next insn. */
+ off2 = 8;
+ off2 += offset;
+ if (off2 + 4 <= input_section->size)
{
- bfd_vma off2 = rel[1].r_addend;
- if (off2 == 0)
- /* zero means next insn. */
- off2 = 8;
- off2 += 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)
{
- uint64_t pinsn2;
- bfd_signed_vma addend_off;
- pinsn2 = bfd_get_32 (input_bfd, contents + off2);
- pinsn2 <<= 32;
+ 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)
- {
- 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);
- }
+ bfd_put_32 (input_bfd, pinsn2,
+ contents + off2 + 4);
}
}
}
{
relgot = htab->elf.irelplt;
if (indx == 0 || is_static_defined (&h->elf))
- htab->local_ifunc_resolver = 1;
+ htab->elf.ifunc_resolvers = TRUE;
}
else if (indx != 0
|| (bfd_link_pic (info)
{
sreloc = htab->elf.irelplt;
if (indx == 0 || is_static_defined (&h->elf))
- htab->local_ifunc_resolver = 1;
+ htab->elf.ifunc_resolvers = TRUE;
}
if (sreloc == NULL)
abort ();
break;
case DT_TEXTREL:
- if (htab->local_ifunc_resolver)
+ if (htab->elf.ifunc_resolvers)
info->callbacks->einfo
(_("%P: warning: text relocations and GNU indirect "
"functions may result in a segfault at runtime\n"));