/* PowerPC64-specific support for 64-bit ELF.
- Copyright (C) 1999-2015 Free Software Foundation, Inc.
+ Copyright (C) 1999-2016 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.
#define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */
#define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */
+#define LD_R2_0R12 0xe84c0000 /* ld %r2,0(%r12) */
+#define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */
-#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */
+#define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */
+#define ADDIS_R2_R12 0x3c4c0000 /* addis %r2,%r12,xxx@ha */
+#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */
#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */
#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc64_elf_unhandled_reloc, /* special_function */
"R_PPC64_PLTREL32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
+ /* Like R_PPC64_REL16_HA but for split field in addpcis. */
+ HOWTO (R_PPC64_REL16DX_HA, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc64_elf_ha_reloc, /* special_function */
+ "R_PPC64_REL16DX_HA", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x1fffc1, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
/* Like R_PPC64_ADDR16_HI, but no overflow. */
HOWTO (R_PPC64_ADDR16_HIGH, /* type */
16, /* rightshift */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* Marker reloc on ELFv2 large-model function entry. */
+ HOWTO (R_PPC64_ENTRY,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC64_ENTRY", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* Like ADDR64, but use local entry point of function. */
HOWTO (R_PPC64_ADDR64_LOCAL, /* type */
0, /* rightshift */
break;
case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA;
break;
+ case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC64_REL16DX_HA;
+ break;
+ case BFD_RELOC_PPC64_ENTRY: r = R_PPC64_ENTRY;
+ break;
case BFD_RELOC_PPC64_ADDR64_LOCAL: r = R_PPC64_ADDR64_LOCAL;
break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT;
type = ELF64_R_TYPE (dst->r_info);
if (type >= ARRAY_SIZE (ppc64_elf_howto_table))
{
- (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
- abfd, (int) type);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: invalid relocation type %d"),
+ abfd, (int) type);
type = R_PPC64_NONE;
}
cache_ptr->howto = ppc64_elf_howto_table[type];
void *data, asection *input_section,
bfd *output_bfd, char **error_message)
{
+ enum elf_ppc64_reloc_type r_type;
+ long insn;
+ bfd_size_type octets;
+ bfd_vma value;
+
/* If this is a relocatable link (output_bfd test tells us), just
call the generic function. Any adjustment will be done at final
link time. */
We won't actually be using the low 16 bits, so trashing them
doesn't matter. */
reloc_entry->addend += 0x8000;
- return bfd_reloc_continue;
+ r_type = reloc_entry->howto->type;
+ if (r_type != R_PPC64_REL16DX_HA)
+ return bfd_reloc_continue;
+
+ value = 0;
+ if (!bfd_is_com_section (symbol->section))
+ value = symbol->value;
+ value += (reloc_entry->addend
+ + symbol->section->output_offset
+ + symbol->section->output_section->vma);
+ value -= (reloc_entry->address
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ value = (bfd_signed_vma) value >> 16;
+
+ octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+ insn &= ~0x1fffc1;
+ insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+ if (value + 0x8000 > 0xffff)
+ return bfd_reloc_overflow;
+ return bfd_reloc_ok;
}
static bfd_reloc_status_type
elf_symbol_type *elfsym = (elf_symbol_type *) symbol;
if (symbol->section->owner != abfd
+ && symbol->section->owner != NULL
&& abiversion (symbol->section->owner) >= 2)
{
unsigned int i;
}
/* Fix bad default arch selected for a 64 bit input bfd when the
- default is 32 bit. */
+ default is 32 bit. Also select arch based on apuinfo. */
static bfd_boolean
ppc64_elf_object_p (bfd *abfd)
{
- if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32)
+ if (!abfd->arch_info->the_default)
+ return TRUE;
+
+ if (abfd->arch_info->bits_per_word == 32)
{
Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
BFD_ASSERT (abfd->arch_info->bits_per_word == 64);
}
}
- return TRUE;
+ return _bfd_elf_ppc_set_arch (abfd);
}
/* Support for core dump NOTE sections. */
\f
/* Parameters for the qsort hook. */
static bfd_boolean synthetic_relocatable;
+static asection *synthetic_opd;
/* qsort comparison function for ppc64_elf_get_synthetic_symtab. */
return 1;
/* then .opd symbols. */
- if (strcmp (a->section->name, ".opd") == 0
- && strcmp (b->section->name, ".opd") != 0)
- return -1;
- if (strcmp (a->section->name, ".opd") != 0
- && strcmp (b->section->name, ".opd") == 0)
- return 1;
+ if (synthetic_opd != NULL)
+ {
+ if (strcmp (a->section->name, ".opd") == 0
+ && strcmp (b->section->name, ".opd") != 0)
+ return -1;
+ if (strcmp (a->section->name, ".opd") != 0
+ && strcmp (b->section->name, ".opd") == 0)
+ return 1;
+ }
/* then other code symbols. */
if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
synthetic_relocatable = relocatable;
+ synthetic_opd = opd;
qsort (syms, symcount, sizeof (*syms), compare_symbols);
if (!relocatable && symcount > 1)
}
i = 0;
- if (strcmp (syms[i]->section->name, ".opd") == 0)
+ /* Note that here and in compare_symbols we can't compare opd and
+ sym->section directly. With separate debug info files, the
+ symbols will be extracted from the debug file while abfd passed
+ to this function is the real binary. */
+ if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0)
++i;
codesecsym = i;
break;
secsymend = i;
- for (; i < symcount; ++i)
- if (strcmp (syms[i]->section->name, ".opd") != 0)
- break;
+ if (opd != NULL)
+ for (; i < symcount; ++i)
+ if (strcmp (syms[i]->section->name, ".opd") != 0)
+ break;
opdsymend = i;
for (; i < symcount; ++i)
/* Track dynamic relocs copied for this symbol. */
struct elf_dyn_relocs *dyn_relocs;
+ /* Chain of aliases referring to a weakdef. */
+ struct ppc_link_hash_entry *weakref;
+
/* Link between function code and descriptor symbols. */
struct ppc_link_hash_entry *oh;
htab = ppc_hash_table (info);
- /* Create .sfpr for code to save and restore fp regs. */
flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
- flags);
- if (htab->sfpr == NULL
- || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
- return FALSE;
+ if (htab->params->save_restore_funcs)
+ {
+ /* Create .sfpr for code to save and restore fp regs. */
+ htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
+ flags);
+ if (htab->sfpr == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+ return FALSE;
+ }
+
+ if (bfd_link_relocatable (info))
+ return TRUE;
/* Create .glink for lazy dynamic linking support. */
htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
linker created stub bfd. This ensures that the GOT header is at
the start of the output TOC section. */
htab = ppc_hash_table (info);
- if (htab == NULL)
- return FALSE;
htab->elf.dynobj = params->stub_bfd;
htab->params = params;
- if (bfd_link_relocatable (info))
- return TRUE;
-
return create_linkage_sections (htab->elf.dynobj, info);
}
more than one stub used to reach say, printf, and we need to
distinguish between them. */
group = htab->sec_info[input_section->id].u.group;
+ if (group == NULL)
+ return NULL;
if (h != NULL && h->u.stub_cache != NULL
&& h->u.stub_cache->h == h
TRUE, FALSE);
if (stub_entry == NULL)
{
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"),
section->owner, stub_name);
return NULL;
edir->elf.needs_plt |= eind->elf.needs_plt;
edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
+ /* If we were called to copy over info for a weak sym, don't copy
+ dyn_relocs, plt/got info, or dynindx. We used to copy dyn_relocs
+ in order to simplify readonly_dynrelocs and save a field in the
+ symbol hash entry, but that means dyn_relocs can't be used in any
+ tests about a specific symbol, or affect other symbol flags which
+ are then tested.
+ Chain weakdefs so we can get from the weakdef back to an alias.
+ The list is circular so that we don't need to use u.weakdef as
+ well as this list to look at all aliases. */
+ if (eind->elf.root.type != bfd_link_hash_indirect)
+ {
+ struct ppc_link_hash_entry *cur, *add, *next;
+
+ add = eind;
+ do
+ {
+ cur = edir->weakref;
+ if (cur != NULL)
+ {
+ do
+ {
+ /* We can be called twice for the same symbols.
+ Don't make multiple loops. */
+ if (cur == add)
+ return;
+ cur = cur->weakref;
+ } while (cur != edir);
+ }
+ next = add->weakref;
+ if (cur != add)
+ {
+ add->weakref = edir->weakref != NULL ? edir->weakref : edir;
+ edir->weakref = add;
+ }
+ add = next;
+ } while (add != NULL && add != eind);
+ return;
+ }
+
/* Copy over any dynamic relocs we may have on the indirect sym. */
if (eind->dyn_relocs != NULL)
{
eind->dyn_relocs = NULL;
}
- /* If we were called to copy over info for a weak sym, that's all.
- You might think dyn_relocs need not be copied over; After all,
- both syms will be dynamic or both non-dynamic so we're just
- moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
- code in ppc64_elf_adjust_dynamic_symbol needs to check for
- dyn_relocs in read-only sections, and it does so on what is the
- DIR sym here. */
- if (eind->elf.root.type != bfd_link_hash_indirect)
- return;
-
/* Copy over got entries that we may have already seen to the
symbol which just became indirect. */
if (eind->elf.got.glist != NULL)
asection **sec,
bfd_vma *value)
{
- if ((ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
- || ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
+ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
&& (ibfd->flags & DYNAMIC) == 0
&& bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
- elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any;
+ elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
if (*sec != NULL
&& strcmp ((*sec)->name, ".opd") == 0)
{
if (abiversion (ibfd) == 0)
set_abiversion (ibfd, 1);
- else if (abiversion (ibfd) == 2)
+ else if (abiversion (ibfd) >= 2)
{
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
" version %d\n"),
ibfd, abiversion (ibfd));
}
/* We need to fix the undefs list for any syms we have twiddled to
- undef_weak. */
+ undefweak. */
if (htab->twiddled_syms)
{
bfd_link_repair_undef_list (&htab->elf.root);
enum elf_ppc64_reloc_type r_type;
int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
- struct plt_entry **ifunc;
+ struct plt_entry **ifunc, **plt_list;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
return FALSE;
}
}
- r_type = ELF64_R_TYPE (rel->r_info);
- if (is_branch_reloc (r_type))
- {
- if (h != NULL && (h == tga || h == dottga))
- {
- if (rel != relocs
- && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
- || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
- /* We have a new-style __tls_get_addr call with a marker
- reloc. */
- ;
- else
- /* Mark this section as having an old-style call. */
- sec->has_tls_get_addr_call = 1;
- }
-
- /* STT_GNU_IFUNC symbols must have a PLT entry. */
- if (ifunc != NULL
- && !update_plt_info (abfd, ifunc, rel->r_addend))
- return FALSE;
- }
+ r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
case R_PPC64_TLSGD:
tls_type = TLS_TLS | TLS_DTPREL;
dogottls:
sec->has_tls_reloc = 1;
- /* Fall thru */
+ /* Fall through */
case R_PPC64_GOT16:
case R_PPC64_GOT16_DS:
case R_PPC64_PLT16_LO:
case R_PPC64_PLT32:
case R_PPC64_PLT64:
- /* This symbol requires a procedure linkage table entry. We
- actually build the entry in adjust_dynamic_symbol,
- because this might be a case of linking PIC code without
- linking in any dynamic objects, in which case we don't
- need to generate a procedure linkage table after all. */
- if (h == NULL)
- {
- /* It does not make sense to have a procedure linkage
- table entry for a local symbol. */
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- else
+ /* This symbol requires a procedure linkage table entry. */
+ plt_list = ifunc;
+ if (h != NULL)
{
- if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
- return FALSE;
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;
+ plt_list = &h->plt.plist;
}
+ if (plt_list == NULL)
+ {
+ /* It does not make sense to have a procedure linkage
+ table entry for a non-ifunc local symbol. */
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%P: %H: %s reloc against local symbol\n"),
+ abfd, sec, rel->r_offset,
+ ppc64_elf_howto_table[r_type]->name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ if (!update_plt_info (abfd, plt_list, rel->r_addend))
+ return FALSE;
break;
/* The following relocations don't need to propagate the
case R_PPC64_REL16_LO:
case R_PPC64_REL16_HI:
case R_PPC64_REL16_HA:
+ case R_PPC64_REL16DX_HA:
break;
/* Not supported as a dynamic relocation. */
{
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: %H: %s reloc unsupported "
"in shared libraries and PIEs.\n"),
abfd, sec, rel->r_offset,
case R_PPC64_TOC16_DS:
htab->do_multi_toc = 1;
ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
+ /* Fall through. */
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_HI:
case R_PPC64_TOC16_HA:
sec->has_toc_reloc = 1;
break;
+ /* Marker reloc. */
+ case R_PPC64_ENTRY:
+ break;
+
/* This relocation describes the C++ object vtable hierarchy.
Reconstruct it for later use during GC. */
case R_PPC64_GNU_VTINHERIT:
/* Fall through. */
case R_PPC64_REL24:
- if (h != NULL && ifunc == NULL)
+ plt_list = ifunc;
+ if (h != NULL)
{
- /* We may need a .plt entry if the function this reloc
- refers to is in a shared lib. */
- if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
- return FALSE;
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;
+
if (h == tga || h == dottga)
- sec->has_tls_reloc = 1;
+ {
+ sec->has_tls_reloc = 1;
+ if (rel != relocs
+ && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+ || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+ /* We have a new-style __tls_get_addr call with
+ a marker reloc. */
+ ;
+ else
+ /* Mark this section as having an old-style call. */
+ sec->has_tls_get_addr_call = 1;
+ }
+ 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, rel->r_addend))
+ return FALSE;
break;
+ case R_PPC64_ADDR14:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR24:
+ goto dodyn;
+
case R_PPC64_TPREL64:
tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
if (bfd_link_pic (info))
case R_PPC64_REL30:
case R_PPC64_REL32:
case R_PPC64_REL64:
- case R_PPC64_ADDR14:
- case R_PPC64_ADDR14_BRNTAKEN:
- case R_PPC64_ADDR14_BRTAKEN:
- case R_PPC64_ADDR24:
case R_PPC64_ADDR32:
case R_PPC64_UADDR16:
case R_PPC64_UADDR32:
object file when linking. */
static bfd_boolean
-ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
unsigned long iflags, oflags;
if ((ibfd->flags & BFD_LINKER_CREATED) != 0)
if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd))
return TRUE;
- if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+ if (!_bfd_generic_verify_endian_match (ibfd, info))
return FALSE;
iflags = elf_elfheader (ibfd)->e_flags;
if (iflags & ~EF_PPC64_ABI)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
else if (iflags != oflags && iflags != 0)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: ABI version %ld is not compatible with ABI version %ld output"),
ibfd, iflags, oflags);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
+ _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+
/* Merge Tag_compatibility attributes and any common GNU ones. */
- _bfd_elf_merge_object_attributes (ibfd, obfd);
+ _bfd_elf_merge_object_attributes (ibfd, info);
return TRUE;
}
{
FILE *file = ptr;
- /* xgettext:c-format */
fprintf (file, _("private flags = 0x%lx:"),
elf_elfheader (abfd)->e_flags);
if (strcmp (sym->section->name, ".opd") == 0)
{
- if (opd_entry_value (sym->section, sym->value,
+ struct _opd_sec_data *opd = get_opd_info (sym->section);
+ bfd_vma symval = sym->value;
+
+ if (opd != NULL
+ && opd->adjust != NULL
+ && elf_section_data (sym->section)->relocs != NULL)
+ {
+ /* opd_entry_value will use cached relocs that have been
+ adjusted, but with raw symbols. That means both local
+ and global symbols need adjusting. */
+ long adjust = opd->adjust[OPD_NDX (symval)];
+ if (adjust == -1)
+ return 0;
+ symval += adjust;
+ }
+
+ if (opd_entry_value (sym->section, symval,
&sec, code_off, TRUE) == (bfd_vma) -1)
return 0;
/* An old ABI binary with dot-syms has a size of 24 on the .opd
unsigned long r_symndx;
enum elf_ppc64_reloc_type r_type;
struct elf_link_hash_entry *h = NULL;
+ struct plt_entry **plt_list;
unsigned char tls_type = 0;
r_symndx = ELF64_R_SYM (rel->r_info);
}
}
- if (is_branch_reloc (r_type))
- {
- struct plt_entry **ifunc = NULL;
- if (h != NULL)
- {
- if (h->type == STT_GNU_IFUNC)
- ifunc = &h->plt.plist;
- }
- else if (local_got_ents != NULL)
- {
- struct plt_entry **local_plt = (struct plt_entry **)
- (local_got_ents + symtab_hdr->sh_info);
- unsigned char *local_got_tls_masks = (unsigned char *)
- (local_plt + symtab_hdr->sh_info);
- if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
- ifunc = local_plt + r_symndx;
- }
- if (ifunc != NULL)
- {
- struct plt_entry *ent;
-
- for (ent = *ifunc; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend)
- break;
- if (ent == NULL)
- abort ();
- if (ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- continue;
- }
- }
-
switch (r_type)
{
case R_PPC64_GOT_TLSLD16:
case R_PPC64_REL14_BRNTAKEN:
case R_PPC64_REL14_BRTAKEN:
case R_PPC64_REL24:
+ plt_list = NULL;
if (h != NULL)
+ plt_list = &h->plt.plist;
+ else if (local_got_ents != NULL)
+ {
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got_ents + symtab_hdr->sh_info);
+ unsigned char *local_got_tls_masks = (unsigned char *)
+ (local_plt + symtab_hdr->sh_info);
+ if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+ plt_list = local_plt + r_symndx;
+ }
+ if (plt_list)
{
struct plt_entry *ent;
- for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ for (ent = *plt_list; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend)
break;
if (ent != NULL && ent->plt.refcount > 0)
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, FALSE, FALSE, TRUE);
+ elf_link_hash_lookup (&htab->elf, sym, writing, TRUE, TRUE);
if (stub_sec != NULL)
{
if (h != NULL
h->elf.root.u.def.value = htab->sfpr->size;
h->elf.type = STT_FUNC;
h->elf.def_regular = 1;
+ h->elf.non_elf = 0;
_bfd_elf_link_hash_hide_symbol (info, &h->elf, TRUE);
writing = TRUE;
if (htab->sfpr->contents == NULL)
struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
- unsigned int i;
htab = ppc_hash_table (info);
if (htab == NULL)
return FALSE;
- if (!bfd_link_relocatable (info)
- && htab->elf.hgot != NULL)
+ /* Provide any missing _save* and _rest* functions. */
+ if (htab->sfpr != NULL)
+ {
+ unsigned int i;
+
+ htab->sfpr->size = 0;
+ for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
+ if (!sfpr_define (info, &save_res_funcs[i], NULL))
+ return FALSE;
+ if (htab->sfpr->size == 0)
+ htab->sfpr->flags |= SEC_EXCLUDE;
+ }
+
+ if (bfd_link_relocatable (info))
+ return TRUE;
+
+ if (htab->elf.hgot != NULL)
{
_bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE);
/* Make .TOC. defined so as to prevent it being made dynamic.
| STV_HIDDEN);
}
- if (htab->sfpr == NULL)
- /* We don't have any relocs. */
- return TRUE;
-
- /* Provide any missing _save* and _rest* functions. */
- htab->sfpr->size = 0;
- if (htab->params->save_restore_funcs)
- for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
- if (!sfpr_define (info, &save_res_funcs[i], NULL))
- return FALSE;
-
elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
- if (htab->sfpr->size == 0)
- htab->sfpr->flags |= SEC_EXCLUDE;
-
return TRUE;
}
-/* Return true if we have dynamic relocs that apply to read-only sections. */
+/* Return true if we have dynamic relocs against H that apply to
+ read-only sections. */
static bfd_boolean
readonly_dynrelocs (struct elf_link_hash_entry *h)
return FALSE;
}
+/* Return true if we have dynamic relocs against H or any of its weak
+ aliases, that apply to read-only sections. */
+
+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;
+ do
+ {
+ if (readonly_dynrelocs (&eh->elf))
+ return TRUE;
+ eh = eh->weakref;
+ } while (eh != NULL && &eh->elf != h);
+
+ return FALSE;
+}
+
+/* Return whether EH has pc-relative dynamic relocs. */
+
+static bfd_boolean
+pc_dynrelocs (struct ppc_link_hash_entry *eh)
+{
+ struct elf_dyn_relocs *p;
+
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ if (p->pc_count != 0)
+ return TRUE;
+ return FALSE;
+}
+
+/* Return true if a global entry stub will be created for H. Valid
+ for ELFv2 before plt entries have been allocated. */
+
+static bfd_boolean
+global_entry_stub (struct elf_link_hash_entry *h)
+{
+ struct plt_entry *pent;
+
+ if (!h->pointer_equality_needed
+ || h->def_regular)
+ return FALSE;
+
+ for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+ if (pent->plt.refcount > 0
+ && pent->addend == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
h->needs_plt = 0;
h->pointer_equality_needed = 0;
}
- else if (abiversion (info->output_bfd) == 2)
+ else if (abiversion (info->output_bfd) >= 2)
{
/* Taking a function's address in a read/write section
doesn't require us to define the function symbol in the
executable on a global entry stub. A dynamic reloc can
- be used instead. */
- if (h->pointer_equality_needed
- && h->type != STT_GNU_IFUNC
- && !readonly_dynrelocs (h))
+ be used instead. The reason we prefer a few more dynamic
+ relocs is that calling via a global entry stub costs a
+ few more instructions, and pointer_equality_needed causes
+ extra work in ld.so when resolving these symbols. */
+ if (global_entry_stub (h)
+ && !alias_readonly_dynrelocs (h))
{
h->pointer_equality_needed = 0;
+ /* After adjust_dynamic_symbol, non_got_ref set in
+ the non-pic case means that dyn_relocs for this
+ symbol should be discarded. */
h->non_got_ref = 0;
}
- /* After adjust_dynamic_symbol, non_got_ref set in the
- non-shared case means that we have allocated space in
- .dynbss for the symbol and thus dyn_relocs for this
- symbol should be discarded.
- If we get here we know we are making a PLT entry for this
- symbol, and in an executable we'd normally resolve
- relocations against this symbol to the PLT entry. Allow
- dynamic relocs if the reference is weak, and the dynamic
- relocs will not cause text relocation. */
- else if (!h->ref_regular_nonweak
- && h->non_got_ref
- && h->type != STT_GNU_IFUNC
- && !readonly_dynrelocs (h))
- h->non_got_ref = 0;
-
/* If making a plt entry, then we don't need copy relocs. */
return TRUE;
}
return TRUE;
/* Don't generate a copy reloc for symbols defined in the executable. */
- if (!h->def_dynamic || !h->ref_regular || h->def_regular)
- return TRUE;
+ if (!h->def_dynamic || !h->ref_regular || h->def_regular
- /* If -z nocopyreloc was given, don't generate them either. */
- if (info->nocopyreloc)
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ /* If -z nocopyreloc was given, don't generate them either. */
+ || info->nocopyreloc
- /* If we didn't find any dynamic relocs in read-only sections, then
- we'll be keeping the dynamic relocs and avoiding the copy reloc. */
- if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h))
- {
- h->non_got_ref = 0;
- return TRUE;
- }
+ /* If we didn'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))
- /* Protected variables do not work with .dynbss. The copy in
- .dynbss won't be used by the shared library with the protected
- definition for the variable. Text relocations are preferable
- to an incorrect program. */
- if (h->protected_def)
+ /* Protected variables do not work with .dynbss. The copy in
+ .dynbss won't be used by the shared library with the protected
+ definition for the variable. Text relocations are preferable
+ to an incorrect program. */
+ || h->protected_def)
{
h->non_got_ref = 0;
return TRUE;
return NULL;
if (ent.sec == NULL || ent.sec->output_section == NULL)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
return NULL;
}
}
}
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
sec->owner, sec);
bfd_set_error (bfd_error_bad_value);
something silly in .opd with the assembler. No .opd
optimization for them! */
broken_opd:
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: .opd is not a regular array of opd entries"), ibfd);
broken = TRUE;
break;
if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
|| (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: unexpected reloc type %u in .opd section"),
ibfd, r_type);
broken = TRUE;
sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
sym_sec);
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: undefined sym `%s' in .opd section"),
ibfd, sym_name);
broken = TRUE;
htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
FALSE, FALSE, TRUE));
- if (!htab->params->no_tls_get_addr_opt)
+ if (htab->params->tls_get_addr_opt)
{
struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
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);
+ opt_fd->forced_local = 0;
if (opt_fd->dynindx != -1)
{
/* Use __tls_get_addr_opt in dynamic relocations. */
tga->root.type = bfd_link_hash_indirect;
tga->root.u.i.link = &opt->root;
ppc64_elf_copy_indirect_symbol (info, opt, tga);
+ opt->forced_local = 0;
_bfd_elf_link_hash_hide_symbol (info, opt,
tga->forced_local);
htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
}
}
}
- else
- htab->params->no_tls_get_addr_opt = TRUE;
+ else if (htab->params->tls_get_addr_opt < 0)
+ htab->params->tls_get_addr_opt = 0;
}
return _bfd_elf_tls_setup (info->output_bfd, info);
}
if (h != NULL
&& h->root.type == bfd_link_hash_undefweak)
ok_tprel = TRUE;
- else
+ else if (sym_sec != NULL
+ && sym_sec->output_section != NULL)
{
value += sym_sec->output_offset;
value += sym_sec->output_section->vma;
case R_PPC64_GOT_TLSLD16_LO:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TLSGD16_LO:
expecting_tls_get_addr = 1;
found_tls_get_addr_arg = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA:
case R_PPC64_TLSGD:
case R_PPC64_TLSLD:
found_tls_get_addr_arg = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_TLS:
case R_PPC64_TOC16:
could just mark this symbol to exclude it
from tls optimization but it's safer to skip
the entire optimization. */
+ /* xgettext:c-format */
info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
"TLS optimization disabled\n"),
ibfd, sec, rel->r_offset);
if ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%s defined on removed toc entry"), eh->elf.root.root.string);
do
++i;
goto error_ret;
if (sym_sec == NULL
+ || sym_sec->output_section == NULL
|| discarded_section (sym_sec))
continue;
ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
sprintf (str, "%#08x", insn);
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: toc optimization is not supported for"
" %s instruction.\n"),
ibfd, sec, rel->r_offset & ~3, str);
}
if ((opc & (0x3f << 2)) == (58u << 2))
break;
- /* Fall thru */
+ /* Fall through. */
default:
/* Wrong sort of reloc, or not a ld. We may
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: %s references "
"optimized away TOC entry\n"),
ibfd, sec, rel->r_offset,
if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
{
if (local_toc_syms)
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%s defined on removed toc entry"),
bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
do
struct ppc_link_hash_table *htab;
asection *s;
struct ppc_link_hash_entry *eh;
- struct elf_dyn_relocs *p;
struct got_entry **pgent, *gent;
if (h->root.type == bfd_link_hash_indirect)
if (htab == NULL)
return FALSE;
- if ((htab->elf.dynamic_sections_created
- && h->dynindx != -1
- && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
- || h->type == STT_GNU_IFUNC)
- {
- struct plt_entry *pent;
- bfd_boolean doneone = FALSE;
- for (pent = h->plt.plist; pent != NULL; pent = pent->next)
- if (pent->plt.refcount > 0)
- {
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
- {
- s = htab->elf.iplt;
- pent->plt.offset = s->size;
- s->size += PLT_ENTRY_SIZE (htab);
- s = htab->elf.irelplt;
- }
- else
- {
- /* If this is the first .plt entry, make room for the special
- first entry. */
- s = htab->elf.splt;
- if (s->size == 0)
- s->size += PLT_INITIAL_ENTRY_SIZE (htab);
-
- pent->plt.offset = s->size;
-
- /* Make room for this entry. */
- s->size += PLT_ENTRY_SIZE (htab);
-
- /* Make room for the .glink code. */
- s = htab->glink;
- if (s->size == 0)
- s->size += GLINK_CALL_STUB_SIZE;
- if (htab->opd_abi)
- {
- /* We need bigger stubs past index 32767. */
- if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
- s->size += 4;
- s->size += 2*4;
- }
- else
- s->size += 4;
-
- /* We also need to make an entry in the .rela.plt section. */
- s = htab->elf.srelplt;
- }
- s->size += sizeof (Elf64_External_Rela);
- doneone = TRUE;
- }
- else
- pent->plt.offset = (bfd_vma) -1;
- if (!doneone)
- {
- h->plt.plist = NULL;
- h->needs_plt = 0;
- }
- }
- else
- {
- h->plt.plist = NULL;
- h->needs_plt = 0;
- }
-
eh = (struct ppc_link_hash_entry *) h;
/* Run through the TLS GD got entries first if we're changing them
to TPREL. */
allocate_got (h, info, gent);
}
- if (eh->dyn_relocs == NULL
- || (!htab->elf.dynamic_sections_created
- && h->type != STT_GNU_IFUNC))
- return TRUE;
-
- /* In the shared -Bsymbolic case, discard space allocated for
- dynamic pc-relative relocs against symbols which turn out to be
- defined in regular objects. For the normal shared case, discard
- space for relocs that have become local due to symbol visibility
- changes. */
+ if (!htab->elf.dynamic_sections_created
+ && h->type != STT_GNU_IFUNC)
+ eh->dyn_relocs = NULL;
- if (bfd_link_pic (info))
+ if (eh->dyn_relocs != NULL)
{
- /* Relocs that use pc_count are those that appear on a call insn,
- or certain REL relocs (see must_be_dyn_reloc) that can be
- generated via assembly. We want calls to protected symbols to
- resolve directly to the function rather than going via the plt.
- If people want function pointer comparisons to work as expected
- then they should avoid writing weird assembly. */
- if (SYMBOL_CALLS_LOCAL (info, h))
+ struct elf_dyn_relocs *p, **pp;
+
+ /* In the shared -Bsymbolic case, discard space allocated for
+ dynamic pc-relative relocs against symbols which turn out to
+ 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))
{
- struct elf_dyn_relocs **pp;
+ /* Relocs that use pc_count are those that appear on a call
+ insn, or certain REL relocs (see must_be_dyn_reloc) that
+ can be generated via assembly. We want calls to
+ protected symbols to resolve directly to the function
+ rather than going via the plt. If people want function
+ pointer comparisons to work as expected then they should
+ avoid writing weird assembly. */
+ if (SYMBOL_CALLS_LOCAL (info, h))
+ {
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ {
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ /* Also discard relocs on undefined weak syms with
+ non-default visibility. */
+ if (eh->dyn_relocs != NULL
+ && h->root.type == bfd_link_hash_undefweak)
{
- p->count -= p->pc_count;
- p->pc_count = 0;
- if (p->count == 0)
- *pp = p->next;
- else
- pp = &p->next;
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ eh->dyn_relocs = NULL;
+
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ else if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
}
}
-
- /* Also discard relocs on undefined weak syms with non-default
- visibility. */
- if (eh->dyn_relocs != NULL
- && h->root.type == bfd_link_hash_undefweak)
+ else if (h->type == STT_GNU_IFUNC)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- eh->dyn_relocs = NULL;
+ /* A plt entry is always created when making direct calls to
+ an ifunc, even when building a static executable, but
+ that doesn't cover all cases. We may have only an ifunc
+ initialised function pointer for a given ifunc symbol.
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- else if (h->dynindx == -1
- && !h->forced_local)
+ For ELFv2, dynamic relocations are not required when
+ generating a global entry PLT stub. */
+ if (abiversion (info->output_bfd) >= 2)
{
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ if (global_entry_stub (h))
+ eh->dyn_relocs = NULL;
}
- }
- }
- else if (h->type == STT_GNU_IFUNC)
- {
- if (!h->non_got_ref)
- eh->dyn_relocs = NULL;
- }
- else if (ELIMINATE_COPY_RELOCS)
- {
- /* For the non-shared case, discard space for relocs against
- symbols which turn out to need copy relocs or are not
- dynamic. */
- if (!h->non_got_ref
- && !h->def_regular)
+ /* For ELFv1 we have function descriptors. Descriptors need
+ to be treated like PLT entries and thus have dynamic
+ relocations. One exception is when the function
+ descriptor is copied into .dynbss (which should only
+ happen with ancient versions of gcc). */
+ else if (h->needs_copy)
+ eh->dyn_relocs = NULL;
+ }
+ else if (ELIMINATE_COPY_RELOCS)
{
- /* Make sure this symbol is output as a dynamic symbol.
+ /* For the non-pic case, discard space for relocs against
+ symbols which turn out to need copy relocs or are not
+ dynamic. */
+
+ /* First make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1
- && !h->forced_local)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- }
+ if (h->root.type == bfd_link_hash_undefweak
+ && !h->non_got_ref
+ && !h->def_regular
+ && h->dynindx == -1
+ && !h->forced_local
+ && !bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
- /* If that succeeded, we know we'll be keeping all the
- relocs. */
- if (h->dynindx != -1)
- goto keep;
+ if (h->non_got_ref
+ || h->def_regular
+ || h->dynindx == -1)
+ eh->dyn_relocs = NULL;
}
- eh->dyn_relocs = NULL;
-
- keep: ;
+ /* Finally, allocate space. */
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *sreloc = elf_section_data (p->sec)->sreloc;
+ if (eh->elf.type == STT_GNU_IFUNC)
+ sreloc = htab->elf.irelplt;
+ sreloc->size += p->count * sizeof (Elf64_External_Rela);
+ }
}
- /* Finally, allocate space. */
- for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ if ((htab->elf.dynamic_sections_created
+ && h->dynindx != -1
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
+ || h->type == STT_GNU_IFUNC)
{
- asection *sreloc = elf_section_data (p->sec)->sreloc;
- if (eh->elf.type == STT_GNU_IFUNC)
- sreloc = htab->elf.irelplt;
- sreloc->size += p->count * sizeof (Elf64_External_Rela);
+ struct plt_entry *pent;
+ bfd_boolean doneone = FALSE;
+ for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+ if (pent->plt.refcount > 0)
+ {
+ if (!htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
+ {
+ s = htab->elf.iplt;
+ pent->plt.offset = s->size;
+ s->size += PLT_ENTRY_SIZE (htab);
+ s = htab->elf.irelplt;
+ }
+ else
+ {
+ /* If this is the first .plt entry, make room for the special
+ first entry. */
+ s = htab->elf.splt;
+ if (s->size == 0)
+ s->size += PLT_INITIAL_ENTRY_SIZE (htab);
+
+ pent->plt.offset = s->size;
+
+ /* Make room for this entry. */
+ s->size += PLT_ENTRY_SIZE (htab);
+
+ /* Make room for the .glink code. */
+ s = htab->glink;
+ if (s->size == 0)
+ s->size += GLINK_CALL_STUB_SIZE;
+ if (htab->opd_abi)
+ {
+ /* We need bigger stubs past index 32767. */
+ if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+ s->size += 4;
+ s->size += 2*4;
+ }
+ else
+ s->size += 4;
+
+ /* We also need to make an entry in the .rela.plt section. */
+ s = htab->elf.srelplt;
+ }
+ s->size += sizeof (Elf64_External_Rela);
+ doneone = TRUE;
+ }
+ else
+ pent->plt.offset = (bfd_vma) -1;
+ if (!doneone)
+ {
+ h->plt.plist = NULL;
+ h->needs_plt = 0;
+ }
+ }
+ else
+ {
+ h->plt.plist = NULL;
+ h->needs_plt = 0;
}
return TRUE;
need to define the symbol in the executable on a call stub.
This is to avoid text relocations. */
s->size = (s->size + 15) & -16;
+ h->root.type = bfd_link_hash_defined;
h->root.u.def.section = s;
h->root.u.def.value = s->size;
s->size += 16;
if (htab->elf.dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
- if (bfd_link_executable (info))
+ if (bfd_link_executable (info) && !info->nointerp)
{
s = bfd_get_linker_section (dynobj, ".interp");
if (s == NULL)
return FALSE;
}
- tls_opt = (!htab->params->no_tls_get_addr_opt
+ tls_opt = (htab->params->tls_get_addr_opt
&& htab->tls_get_addr_fd != NULL
&& htab->tls_get_addr_fd->elf.plt.plist != NULL);
if (tls_opt || !htab->opd_abi)
if (stub_entry->h != NULL
&& (stub_entry->h == htab->tls_get_addr_fd
|| stub_entry->h == htab->tls_get_addr)
- && !htab->params->no_tls_get_addr_opt)
+ && htab->params->tls_get_addr_opt)
size += 13 * 4;
return size;
}
&& plt_thread_safe
&& !((stub_entry->h == htab->tls_get_addr_fd
|| stub_entry->h == htab->tls_get_addr)
- && !htab->params->no_tls_get_addr_opt))
+ && htab->params->tls_get_addr_opt))
{
bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab))
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: linkage table error against `%T'\n"),
stub_entry->h != NULL
? stub_entry->h->elf.root.root.string
if (stub_entry->h != NULL
&& (stub_entry->h == htab->tls_get_addr_fd
|| stub_entry->h == htab->tls_get_addr)
- && !htab->params->no_tls_get_addr_opt)
+ && htab->params->tls_get_addr_opt)
p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
else
p = build_plt_stub (htab, stub_entry, loc, off, r);
{
struct ppc_link_hash_table *htab;
asection *osec;
- bfd_size_type stub14_group_size;
bfd_boolean suppress_size_errors;
htab = ppc_hash_table (info);
return FALSE;
suppress_size_errors = FALSE;
- stub14_group_size = stub_group_size >> 10;
if (stub_group_size == 1)
{
/* Default values. */
if (stubs_always_before_branch)
- {
- stub_group_size = 0x1e00000;
- stub14_group_size = 0x7800;
- }
+ stub_group_size = 0x1e00000;
else
- {
- stub_group_size = 0x1c00000;
- stub14_group_size = 0x7000;
- }
+ stub_group_size = 0x1c00000;
suppress_size_errors = TRUE;
}
bfd_boolean big_sec;
bfd_vma curr_toc;
struct map_stub *group;
+ bfd_size_type group_size;
curr = tail;
total = tail->size;
- big_sec = total > (ppc64_elf_section_data (tail) != NULL
- && ppc64_elf_section_data (tail)->has_14bit_branch
- ? stub14_group_size : stub_group_size);
+ group_size = (ppc64_elf_section_data (tail) != NULL
+ && ppc64_elf_section_data (tail)->has_14bit_branch
+ ? stub_group_size >> 10 : stub_group_size);
+
+ big_sec = total > group_size;
if (big_sec && !suppress_size_errors)
- (*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
- tail->owner, tail);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B section %A exceeds stub group size"),
+ tail->owner, tail);
curr_toc = htab->sec_info[tail->id].toc_off;
while ((prev = htab->sec_info[curr->id].u.list) != NULL
&& ((total += curr->output_offset - prev->output_offset)
< (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch
- ? stub14_group_size : stub_group_size))
+ ? (group_size = stub_group_size >> 10) : group_size))
&& htab->sec_info[prev->id].toc_off == curr_toc)
curr = prev;
/* OK, the size from the start of CURR to the end is less
- than stub_group_size and thus can be handled by one stub
+ than group_size and thus can be handled by one stub
section. (or the tail section is itself larger than
- stub_group_size, in which case we may be toast.) We
- should really be keeping track of the total size of stubs
- added here, as stubs contribute to the final output
- section size. That's a little tricky, and this way will
- only break if stubs added make the total size more than
- 2^25, ie. for the default stub_group_size, if stubs total
- more than 2097152 bytes, or nearly 75000 plt call stubs. */
+ group_size, in which case we may be toast.) We should
+ really be keeping track of the total size of stubs added
+ here, as stubs contribute to the final output section
+ size. That's a little tricky, and this way will only
+ break if stubs added make the total size more than 2^25,
+ ie. for the default stub_group_size, if stubs total more
+ than 2097152 bytes, or nearly 75000 plt call stubs. */
group = bfd_alloc (curr->owner, sizeof (*group));
if (group == NULL)
return FALSE;
}
while (tail != curr && (tail = prev) != NULL);
- /* But wait, there's more! Input sections up to stub_group_size
+ /* But wait, there's more! Input sections up to group_size
bytes before the stub section can be handled by it too.
Don't do this if we have a really large section after the
stubs, as adding more stubs increases the chance that
&& ((total += tail->output_offset - prev->output_offset)
< (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch
- ? stub14_group_size : stub_group_size))
+ ? (group_size = stub_group_size >> 10) : group_size))
&& htab->sec_info[prev->id].toc_off == curr_toc)
{
tail = prev;
if (!group_sections (info, stub_group_size, stubs_always_before_branch))
return FALSE;
+#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
+ pathological case where adding stubs on one iteration decreases
+ section gaps (perhaps due to alignment), which then requires
+ fewer or smaller stubs on the next iteration. */
+
while (1)
{
bfd *input_bfd;
if (hash == NULL)
{
sym_value = sym->st_value;
- ok_dest = TRUE;
+ if (sym_sec != NULL
+ && sym_sec->output_section != NULL)
+ ok_dest = TRUE;
}
else if (hash->elf.root.type == bfd_link_hash_defined
|| hash->elf.root.type == bfd_link_hash_defweak)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
stub_sec->size = ((stub_sec->size
+ (1 << htab->params->plt_stub_align) - 1)
- & (-1 << htab->params->plt_stub_align));
+ & -(1 << htab->params->plt_stub_align));
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
- && stub_sec->rawsize != stub_sec->size)
+ && stub_sec->rawsize != stub_sec->size
+ && (htab->stub_iteration <= STUB_SHRINK_ITER
+ || stub_sec->rawsize < stub_sec->size))
break;
- /* Exit from this loop when no stubs have been added, and no stubs
- have changed size. */
if (stub_sec == NULL
&& (htab->glink_eh_frame == NULL
|| htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
*p++ = DW_CFA_advance_loc + 1;
*p++ = DW_CFA_register;
*p++ = 65;
- *p++ = 12;
+ *p++ = htab->opd_abi ? 12 : 0;
*p++ = DW_CFA_advance_loc + 4;
*p++ = DW_CFA_restore_extended;
*p++ = 65;
stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size);
if (stub_sec->contents == NULL)
return FALSE;
- /* We want to check that built size is the same as calculated
- size. rawsize is a convenient location to use. */
- stub_sec->rawsize = stub_sec->size;
stub_sec->size = 0;
}
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
stub_sec->size = ((stub_sec->size
+ (1 << htab->params->plt_stub_align) - 1)
- & (-1 << htab->params->plt_stub_align));
+ & -(1 << htab->params->plt_stub_align));
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
stub_sec_count += 1;
- if (stub_sec->rawsize != stub_sec->size)
+ if (stub_sec->rawsize != stub_sec->size
+ && (htab->stub_iteration <= STUB_SHRINK_ITER
+ || stub_sec->rawsize < stub_sec->size))
break;
}
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *wrel;
Elf_Internal_Rela *relend;
Elf_Internal_Rela outrel;
bfd_byte *loc;
sym_hashes = elf_sym_hashes (input_bfd);
is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
- rel = relocs;
+ rel = wrel = relocs;
relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++)
+ for (; rel < relend; wrel++, rel++)
{
enum elf_ppc64_reloc_type r_type;
bfd_vma addend;
struct ppc_stub_hash_entry *stub_entry;
bfd_vma max_br_offset;
bfd_vma from;
- const Elf_Internal_Rela orig_rel = *rel;
+ Elf_Internal_Rela orig_rel;
reloc_howto_type *howto;
struct reloc_howto_struct alt_howto;
+ again:
+ orig_rel = *rel;
+
r_type = ELF64_R_TYPE (rel->r_info);
r_symndx = ELF64_R_SYM (rel->r_info);
symbol of the previous ADDR64 reloc. The symbol gives us the
proper TOC base to use. */
if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC)
- && rel != relocs
- && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64
+ && wrel != relocs
+ && ELF64_R_TYPE (wrel[-1].r_info) == R_PPC64_ADDR64
&& is_opd)
- r_symndx = ELF64_R_SYM (rel[-1].r_info);
+ r_symndx = ELF64_R_SYM (wrel[-1].r_info);
sym = NULL;
sec = NULL;
h = (struct ppc_link_hash_entry *) h_elf;
if (sec != NULL && discarded_section (sec))
- RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, 1, relend,
- ppc64_elf_howto_table[r_type], 0,
- contents);
+ {
+ _bfd_clear_contents (ppc64_elf_howto_table[r_type],
+ input_bfd, input_section,
+ contents + rel->r_offset);
+ wrel->r_offset = rel->r_offset;
+ wrel->r_info = 0;
+ wrel->r_addend = 0;
+
+ /* For ld -r, remove relocations in debug sections against
+ sections defined in discarded sections. Not done for
+ non-debug to preserve relocs in .eh_frame which the
+ eh_frame editing code expects to be present. */
+ if (bfd_link_relocatable (info)
+ && (input_section->flags & SEC_DEBUGGING))
+ wrel--;
+
+ continue;
+ }
if (bfd_link_relocatable (info))
- continue;
+ goto copy_reloc;
if (h != NULL && &h->elf == htab->elf.hgot)
{
else
info->callbacks->einfo
(!IS_PPC64_TLS_RELOC (r_type)
+ /* xgettext:c-format */
? _("%P: %H: %s used with TLS symbol `%T'\n")
+ /* xgettext:c-format */
: _("%P: %H: %s used with non-TLS symbol `%T'\n"),
input_bfd, input_section, rel->r_offset,
ppc64_elf_howto_table[r_type]->name,
&& (tls_mask & TLS_TPREL) == 0)
{
toctprel:
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+ insn = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
insn &= 31 << 21;
insn |= 0x3c0d0000; /* addis 0,13,0 */
- bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+ bfd_put_32 (output_bfd, insn,
+ contents + rel->r_offset - d_offset);
r_type = R_PPC64_TPREL16_HA;
if (toc_symndx != 0)
{
rel->r_addend = toc_addend;
/* We changed the symbol. Start over in order to
get h, sym, sec etc. right. */
- rel--;
- continue;
+ goto again;
}
else
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
rel->r_addend = toc_addend;
/* We changed the symbol. Start over in order to
get h, sym, sec etc. right. */
- rel--;
- continue;
+ goto again;
}
else
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
{
/* We changed the symbol. Start over in order
to get h, sym, sec etc. right. */
- rel--;
- continue;
+ goto again;
}
}
break;
}
bfd_put_32 (output_bfd, insn2, contents + offset);
if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
- {
- rel--;
- continue;
- }
+ goto again;
}
break;
insn2 = NOP;
}
bfd_put_32 (output_bfd, insn2, contents + offset);
- rel--;
- continue;
+ goto again;
}
break;
}
break;
+ case R_PPC64_ENTRY:
+ relocation = TOCstart + htab->sec_info[input_section->id].toc_off;
+ if (!bfd_link_pic (info)
+ && !info->traditional_format
+ && relocation + 0x80008000 <= 0xffffffff)
+ {
+ unsigned int insn1, insn2;
+
+ insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ if ((insn1 & ~0xfffc) == LD_R2_0R12
+ && insn2 == ADD_R2_R2_R12)
+ {
+ bfd_put_32 (output_bfd,
+ LIS_R2 + PPC_HA (relocation),
+ contents + rel->r_offset);
+ bfd_put_32 (output_bfd,
+ ADDI_R2_R2 + PPC_LO (relocation),
+ contents + rel->r_offset + 4);
+ }
+ }
+ else
+ {
+ relocation -= (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ if (relocation + 0x80008000 <= 0xffffffff)
+ {
+ unsigned int insn1, insn2;
+
+ insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+ if ((insn1 & ~0xfffc) == LD_R2_0R12
+ && insn2 == ADD_R2_R2_R12)
+ {
+ bfd_put_32 (output_bfd,
+ ADDIS_R2_R12 + PPC_HA (relocation),
+ contents + rel->r_offset);
+ bfd_put_32 (output_bfd,
+ ADDI_R2_R2 + PPC_LO (relocation),
+ contents + rel->r_offset + 4);
+ }
+ }
+ }
+ break;
+
case R_PPC64_REL16_HA:
/* If we are generating a non-PIC executable, edit
. 0: addis 2,12,.TOC.-0b@ha
if .TOC. is in range. */
if (!bfd_link_pic (info)
&& !info->traditional_format
+ && !htab->opd_abi
+ && rel->r_addend == d_offset
&& h != NULL && &h->elf == htab->elf.hgot
&& rel + 1 < relend
&& rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO)
bfd_vma offset = rel->r_offset - d_offset;
insn1 = bfd_get_32 (output_bfd, contents + offset);
insn2 = bfd_get_32 (output_bfd, contents + offset + 4);
- if ((insn1 & 0xffff0000) == 0x3c4c0000 /* addis 2,12 */
- && (insn2 & 0xffff0000) == 0x38420000 /* addi 2,2 */)
+ if ((insn1 & 0xffff0000) == ADDIS_R2_R12
+ && (insn2 & 0xffff0000) == ADDI_R2_R2)
{
r_type = R_PPC64_ADDR16_HA;
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
rel->r_addend -= d_offset;
rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO);
rel[1].r_addend -= d_offset + 4;
- bfd_put_32 (output_bfd, 0x3c400000, contents + offset);
+ bfd_put_32 (output_bfd, LIS_R2, contents + offset);
}
}
break;
case R_PPC64_ADDR14_BRTAKEN:
case R_PPC64_REL14_BRTAKEN:
insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */
- /* Fall thru. */
+ /* Fall through. */
/* Branch not taken prediction relocations. */
case R_PPC64_ADDR14_BRNTAKEN:
case R_PPC64_REL14_BRNTAKEN:
insn |= bfd_get_32 (output_bfd,
contents + rel->r_offset) & ~(0x01 << 21);
- /* Fall thru. */
+ /* Fall through. */
case R_PPC64_REL14:
max_br_offset = 1 << 15;
- /* Fall thru. */
+ /* Fall through. */
case R_PPC64_REL24:
/* Calls to functions with a different TOC, such as calls to
if (h != NULL
&& (h == htab->tls_get_addr_fd
|| h == htab->tls_get_addr)
- && !htab->params->no_tls_get_addr_opt)
+ && htab->params->tls_get_addr_opt)
{
/* Special stub used, leave nop alone. */
}
if (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: call to `%T' lacks nop, can't restore toc; "
"recompile with -fPIC\n"),
input_bfd, input_section, rel->r_offset, sym_name);
else
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: call to `%T' lacks nop, can't restore toc; "
"(-mcmodel=small toc adjust stub)\n"),
input_bfd, input_section, rel->r_offset, sym_name);
&& addend == 0)
{
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
- continue;
+ goto copy_reloc;
}
break;
}
{
default:
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: unknown relocation type %d for `%T'\n"),
input_bfd, (int) r_type, sym_name);
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
+ goto copy_reloc;
case R_PPC64_NONE:
case R_PPC64_TLS:
case R_PPC64_TOCSAVE:
case R_PPC64_GNU_VTINHERIT:
case R_PPC64_GNU_VTENTRY:
- continue;
+ case R_PPC64_ENTRY:
+ goto copy_reloc;
/* GOT16 relocations. Like an ADDR16 using the symbol's
address in the GOT as relocation value instead of the
case R_PPC64_PLT64:
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
+ {
+ struct plt_entry **plt_list = NULL;
+ if (h != NULL)
+ plt_list = &h->elf.plt.plist;
+ else if (local_got_ents != NULL)
+ {
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got_ents + symtab_hdr->sh_info);
+ unsigned char *local_got_tls_masks = (unsigned char *)
+ (local_plt + symtab_hdr->sh_info);
+ if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+ plt_list = local_plt + r_symndx;
+ }
+ if (plt_list)
+ {
+ struct plt_entry *ent;
- /* Resolve a PLT reloc against a local symbol directly,
- without using the procedure linkage table. */
- if (h == NULL)
- break;
-
- /* It's possible that we didn't make a PLT entry for this
- symbol. This happens when statically linking PIC code,
- or when using -Bsymbolic. Go find a match if there is a
- PLT entry. */
- if (htab->elf.splt != NULL)
- {
- struct plt_entry *ent;
- for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
- if (ent->plt.offset != (bfd_vma) -1
- && ent->addend == orig_rel.r_addend)
- {
- relocation = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
- + ent->plt.offset);
- unresolved_reloc = FALSE;
- break;
- }
- }
+ for (ent = *plt_list; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1
+ && ent->addend == orig_rel.r_addend)
+ {
+ asection *plt;
+
+ plt = htab->elf.splt;
+ if (!htab->elf.dynamic_sections_created
+ || h == NULL
+ || h->elf.dynindx == -1)
+ plt = htab->elf.iplt;
+ relocation = (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset);
+ addend = 0;
+ unresolved_reloc = FALSE;
+ break;
+ }
+ }
+ }
break;
case R_PPC64_TOC:
case R_PPC64_REL16_LO:
case R_PPC64_REL16_HI:
case R_PPC64_REL16_HA:
+ case R_PPC64_REL16DX_HA:
break;
case R_PPC64_REL14:
case R_PPC64_DTPREL64:
if (htab->elf.tls_sec != NULL)
addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
- /* Fall thru */
+ /* Fall through. */
/* Relocations that may need to be propagated if this is a
dynamic object. */
if (NO_OPD_RELOCS && is_opd)
break;
- if ((bfd_link_pic (info)
- && (h == NULL
- || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
- || h->elf.root.type != bfd_link_hash_undefweak)
- && (must_be_dyn_reloc (info, r_type)
- || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && h->elf.dynindx != -1
- && !h->elf.non_got_ref
- && !h->elf.def_regular)
- || (!bfd_link_pic (info)
- && (h != NULL
- ? h->elf.type == STT_GNU_IFUNC
- : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
+ if (bfd_link_pic (info)
+ ? ((h != NULL && pc_dynrelocs (h))
+ || must_be_dyn_reloc (info, r_type))
+ : (h != NULL
+ ? h->dyn_relocs != NULL
+ : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
{
bfd_boolean skip, relocate;
asection *sreloc;
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: %s for indirect "
"function `%T' unsupported\n"),
input_bfd, input_section, rel->r_offset,
/* These ones haven't been implemented yet. */
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: %s is not supported for `%T'\n"),
input_bfd,
ppc64_elf_howto_table[r_type]->name, sym_name);
bfd_set_error (bfd_error_invalid_operation);
ret = FALSE;
- continue;
+ goto copy_reloc;
}
/* Multi-instruction sequences that access the TOC can be
break;
case R_PPC64_REL16_HA:
+ case R_PPC64_REL16DX_HA:
case R_PPC64_ADDR16_HA:
case R_PPC64_ADDR16_HIGHA:
case R_PPC64_ADDR16_HIGHERA:
alone (it will be set to zero elsewhere in the link). */
if (sec == NULL)
break;
- /* Fall thru */
+ /* Fall through. */
case R_PPC64_GOT16_HA:
case R_PPC64_PLTGOT16_HA:
case R_PPC64_DTPREL16_LO_DS:
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
mask = 3;
- /* If this reloc is against an lq insn, then the value must be
- a multiple of 16. This is somewhat of a hack, but the
- "correct" way to do this by defining _DQ forms of all the
- _DS relocs bloats all reloc switches in this file. It
- doesn't seem to make much sense to use any of these relocs
- in data, so testing the insn should be safe. */
- if ((insn & (0x3f << 26)) == (56u << 26))
+ /* If this reloc is against an lq, lxv, or stxv insn, then
+ the value must be a multiple of 16. This is somewhat of
+ a hack, but the "correct" way to do this by defining _DQ
+ 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))
mask = 15;
- if (((relocation + addend) & mask) != 0)
+ relocation += addend;
+ addend = insn & (mask ^ 3);
+ if ((relocation & mask) != 0)
{
+ relocation ^= relocation & mask;
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: error: %s not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
mask + 1);
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
+ goto copy_reloc;
}
break;
}
rel->r_offset) != (bfd_vma) -1)
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: unresolvable %s against `%T'\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
}
}
- r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
- rel->r_offset, relocation, addend);
+ if (r_type == R_PPC64_REL16DX_HA)
+ {
+ /* Split field reloc isn't handled by _bfd_final_link_relocate. */
+ if (rel->r_offset + 4 > input_section->size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ relocation += addend;
+ relocation -= (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ relocation = (bfd_signed_vma) relocation >> 16;
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn &= ~0x1fffc1;
+ insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ r = bfd_reloc_ok;
+ if (relocation + 0x8000 > 0xffff)
+ r = bfd_reloc_overflow;
+ }
+ }
+ else
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
&& (h->elf.root.type == bfd_link_hash_undefweak
|| h->elf.root.type == bfd_link_hash_undefined)
&& is_branch_reloc (r_type))))
- {
- if (!((*info->callbacks->reloc_overflow)
- (info, &h->elf.root, sym_name,
- reloc_name, orig_rel.r_addend,
- input_bfd, input_section, rel->r_offset)))
- return FALSE;
- }
+ info->callbacks->reloc_overflow (info, &h->elf.root,
+ sym_name, reloc_name,
+ orig_rel.r_addend,
+ input_bfd, input_section,
+ rel->r_offset);
}
else
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %H: %s against `%T': error %d\n"),
input_bfd, input_section, rel->r_offset,
reloc_name, sym_name, (int) r);
if (more_info != NULL)
free (more_info);
}
+ copy_reloc:
+ if (wrel != rel)
+ *wrel = *rel;
+ }
+
+ if (wrel != rel)
+ {
+ Elf_Internal_Shdr *rel_hdr;
+ size_t deleted = rel - wrel;
+
+ rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+ rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+ if (rel_hdr->sh_size == 0)
+ {
+ /* It is too late to remove an empty reloc section. Leave
+ one NONE reloc.
+ ??? What is wrong with an empty section??? */
+ rel_hdr->sh_size = rel_hdr->sh_entsize;
+ deleted -= 1;
+ }
+ rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+ rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+ input_section->reloc_count -= deleted;
}
/* If we're emitting relocations, then shortly after this function