/* PowerPC64-specific support for 64-bit ELF.
- Copyright (C) 1999-2019 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
Written by Linus Nordberg, Swox AB <info@swox.com>,
based on elf32-ppc.c by Ian Lance Taylor.
Largely rewritten by Alan Modra.
#include "elf64-ppc.h"
#include "dwarf2.h"
+/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */
+#define OCTETS_PER_BYTE(ABFD, SEC) 1
+
static bfd_reloc_status_type ppc64_elf_ha_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type ppc64_elf_branch_reloc
+ input_section->output_section->vma);
value = (bfd_signed_vma) value >> 16;
- octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
insn &= ~0x1fffc1;
insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
- octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
insn &= ~(0x01 << 21);
r_type = reloc_entry->howto->type;
if (TOCstart == 0)
TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
- octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
return bfd_reloc_ok;
}
if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
return 1;
- return a > b;
+ /* Finally, sort on where the symbol is in memory. The symbols will
+ be in at most two malloc'd blocks, one for static syms, one for
+ dynamic syms, and we distinguish the two blocks above by testing
+ BSF_DYNAMIC. Since we are sorting the symbol pointers which were
+ originally in the same order as the symbols (and we're not
+ sorting the symbols themselves), this ensures a stable sort. */
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
}
/* Search SYMS for a symbol of the given VALUE. */
static asymbol *
-sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value)
+sym_exists_at (asymbol **syms, size_t lo, size_t hi, unsigned int id,
+ bfd_vma value)
{
- long mid;
+ size_t mid;
if (id == (unsigned) -1)
{
case R_PPC64_REL32:
case R_PPC64_REL64:
case R_PPC64_REL30:
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_LO_DS:
return 0;
case R_PPC64_TPREL16:
/* Nonzero if this section has TLS related relocations. */
#define has_tls_reloc sec_flg0
-/* Nonzero if this section has an old-style call to __tls_get_addr. */
-#define has_tls_get_addr_call sec_flg1
+/* Nonzero if this section has a call to __tls_get_addr lacking marker
+ relocations. */
+#define nomark_tls_get_addr sec_flg1
/* Nonzero if this section has any toc or got relocs. */
#define has_toc_reloc sec_flg2
htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
flags);
if (htab->sfpr == NULL
- || !bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+ || !bfd_set_section_alignment (htab->sfpr, 2))
return FALSE;
}
htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
flags);
if (htab->glink == NULL
- || !bfd_set_section_alignment (dynobj, htab->glink, 3))
+ || !bfd_set_section_alignment (htab->glink, 3))
return FALSE;
/* The part of .glink used by global entry stubs, separate so that
htab->global_entry = bfd_make_section_anyway_with_flags (dynobj, ".glink",
flags);
if (htab->global_entry == NULL
- || !bfd_set_section_alignment (dynobj, htab->global_entry, 2))
+ || !bfd_set_section_alignment (htab->global_entry, 2))
return FALSE;
if (!info->no_ld_generated_unwind_info)
".eh_frame",
flags);
if (htab->glink_eh_frame == NULL
- || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
+ || !bfd_set_section_alignment (htab->glink_eh_frame, 2))
return FALSE;
}
flags = SEC_ALLOC | SEC_LINKER_CREATED;
htab->elf.iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
if (htab->elf.iplt == NULL
- || !bfd_set_section_alignment (dynobj, htab->elf.iplt, 3))
+ || !bfd_set_section_alignment (htab->elf.iplt, 3))
return FALSE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
htab->elf.irelplt
= bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags);
if (htab->elf.irelplt == NULL
- || !bfd_set_section_alignment (dynobj, htab->elf.irelplt, 3))
+ || !bfd_set_section_alignment (htab->elf.irelplt, 3))
return FALSE;
/* Create branch lookup table for plt_branch stubs. */
htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
flags);
if (htab->brlt == NULL
- || !bfd_set_section_alignment (dynobj, htab->brlt, 3))
+ || !bfd_set_section_alignment (htab->brlt, 3))
return FALSE;
/* Local plt entries, put in .branch_lt but a separate section for
htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
flags);
if (htab->pltlocal == NULL
- || !bfd_set_section_alignment (dynobj, htab->pltlocal, 3))
+ || !bfd_set_section_alignment (htab->pltlocal, 3))
return FALSE;
if (!bfd_link_pic (info))
htab->relbrlt
= bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
if (htab->relbrlt == NULL
- || !bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
+ || !bfd_set_section_alignment (htab->relbrlt, 3))
return FALSE;
htab->relpltlocal
= bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
if (htab->relpltlocal == NULL
- || !bfd_set_section_alignment (dynobj, htab->relpltlocal, 3))
+ || !bfd_set_section_alignment (htab->relpltlocal, 3))
return FALSE;
return TRUE;
got = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (!got
- || !bfd_set_section_alignment (abfd, got, 3))
+ || !bfd_set_section_alignment (got, 3))
return FALSE;
relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got",
flags | SEC_READONLY);
if (!relgot
- || !bfd_set_section_alignment (abfd, relgot, 3))
+ || !bfd_set_section_alignment (relgot, 3))
return FALSE;
ppc64_elf_tdata (abfd)->got = got;
int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
struct plt_entry **ifunc, **plt_list;
- bfd_vma sym_addend;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
sec->has_toc_reloc = 1;
}
- tls_type = 0;
- ifunc = NULL;
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
case R_PPC64_D28:
case R_PPC64_TPREL34:
case R_PPC64_DTPREL34:
- htab->powerxx_stubs = 1;
- /* Fall through. */
- default:
- /* Somewhat foolishly, because the ABIs don't specifically
- allow it, ppc64 gas and ld support GOT and PLT relocs
- with non-zero addends where the addend results in
- sym+addend being stored in the GOT or PLT entry. This
- can't be supported for pcrel relocs because the addend is
- used to specify the pcrel offset. */
- sym_addend = rel->r_addend;
- break;
-
case R_PPC64_PCREL34:
case R_PPC64_GOT_PCREL34:
case R_PPC64_GOT_TLSGD34:
case R_PPC64_PLT_PCREL34_NOTOC:
case R_PPC64_PCREL28:
htab->powerxx_stubs = 1;
- sym_addend = 0;
+ break;
+ default:
break;
}
break;
}
+ ifunc = NULL;
if (h != NULL)
{
if (h->type == STT_GNU_IFUNC)
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | PLT_IFUNC);
if (ifunc == NULL)
return FALSE;
}
}
+ tls_type = 0;
switch (r_type)
{
case R_PPC64_TLSGD:
((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK;
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | TLS_TLS | TLS_MARK))
return FALSE;
sec->has_tls_reloc = 1;
eh = (struct ppc_link_hash_entry *) h;
for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == rel->r_addend
&& ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
return FALSE;
ent->next = eh->elf.got.glist;
- ent->addend = sym_addend;
+ ent->addend = rel->r_addend;
ent->owner = abfd;
ent->tls_type = tls_type;
ent->is_indirect = FALSE;
else
/* This is a global offset table entry for a local symbol. */
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend, tls_type))
+ rel->r_addend, tls_type))
return FALSE;
/* We may also need a plt entry if the symbol turns out to be
an ifunc. */
if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
{
- if (!update_plt_info (abfd, &h->plt.plist, sym_addend))
+ if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
return FALSE;
}
break;
}
if (plt_list == NULL)
plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend,
+ rel->r_addend,
NON_GOT | PLT_KEEP);
- if (!update_plt_info (abfd, plt_list, sym_addend))
+ if (!update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE;
break;
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_LO_DS:
sec->has_toc_reloc = 1;
+ if (h != NULL && bfd_link_executable (info))
+ {
+ /* We may need a copy reloc. */
+ h->non_got_ref = 1;
+ /* Strongly prefer a copy reloc over a dynamic reloc.
+ glibc ld.so as of 2019-08 will error out if one of
+ these relocations is emitted. */
+ h->needs_copy = 1;
+ goto dodyn;
+ }
break;
/* Marker reloc. */
;
else
/* Mark this section as having an old-style call. */
- sec->has_tls_get_addr_call = 1;
+ sec->nomark_tls_get_addr = 1;
}
plt_list = &h->plt.plist;
}
/* We may need a .plt entry if the function this reloc
refers to is in a shared lib. */
if (plt_list
- && !update_plt_info (abfd, plt_list, sym_addend))
+ && !update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE;
break;
}
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
- sym_addend, tls_type))
+ rel->r_addend, tls_type))
return FALSE;
ppc64_sec = ppc64_elf_section_data (sec);
}
BFD_ASSERT (rel->r_offset % 8 == 0);
ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
- ppc64_sec->u.toc.add[rel->r_offset / 8] = sym_addend;
+ ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
/* Mark the second slot of a GD or LD entry.
-1 to indicate GD and -2 to indicate LD. */
case R_PPC64_UADDR32:
case R_PPC64_UADDR64:
case R_PPC64_TOC:
- if (h != NULL && !bfd_link_pic (info))
+ if (h != NULL && bfd_link_executable (info))
/* We may need a copy reloc. */
h->non_got_ref = 1;
dynamic library if we manage to avoid copy relocs for the
symbol. */
dodyn:
- if ((bfd_link_pic (info)
- && (must_be_dyn_reloc (info, r_type)
- || (h != NULL
- && (!SYMBOLIC_BIND (info, h)
- || h->root.type == bfd_link_hash_defweak
- || !h->def_regular))))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && (h->root.type == bfd_link_hash_defweak
- || !h->def_regular))
+ if ((h != NULL
+ && (h->root.type == bfd_link_hash_defweak
+ || !h->def_regular))
+ || (h != NULL
+ && !bfd_link_executable (info)
+ && !SYMBOLIC_BIND (info, h))
+ || (bfd_link_pic (info)
+ && must_be_dyn_reloc (info, r_type))
|| (!bfd_link_pic (info)
&& ifunc != NULL))
{
s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE);
if (s == NULL)
return FALSE;
- if (s->root.type == bfd_link_hash_new
- || (s->root.type = bfd_link_hash_defined
- && s->root.u.def.section == stub_sec))
+ if (s->root.type == bfd_link_hash_new)
{
s->root.type = bfd_link_hash_defined;
s->root.u.def.section = stub_sec;
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
- if (bfd_link_pic (info))
+ if (!bfd_link_executable (info))
return TRUE;
/* If there are no references to this symbol that do not use the
/* If we don't find any dynamic relocs in read-only sections, then
we'll be keeping the dynamic relocs and avoiding the copy reloc. */
- || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h))
+ || (ELIMINATE_COPY_RELOCS
+ && !h->needs_copy
+ && !alias_readonly_dynrelocs (h))
/* Protected variables do not work with .dynbss. The copy in
.dynbss won't be used by the shared library with the protected
default:
return TRUE;
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_LO_DS:
+ if (h == NULL)
+ return TRUE;
+ break;
+
case R_PPC64_TPREL16:
case R_PPC64_TPREL16_LO:
case R_PPC64_TPREL16_HI:
return FALSE;
}
- if ((bfd_link_pic (info)
- && (must_be_dyn_reloc (info, r_type)
- || (h != NULL
- && (!SYMBOLIC_BIND (info, h)
- || h->root.type == bfd_link_hash_defweak
- || !h->def_regular))))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && h != NULL
- && (h->root.type == bfd_link_hash_defweak
- || !h->def_regular)))
+ if ((h != NULL
+ && (h->root.type == bfd_link_hash_defweak
+ || !h->def_regular))
+ || (h != NULL
+ && !bfd_link_executable (info)
+ && !SYMBOLIC_BIND (info, h))
+ || (bfd_link_pic (info)
+ && must_be_dyn_reloc (info, r_type))
+ || (!bfd_link_pic (info)
+ && (h != NULL
+ ? h->type == STT_GNU_IFUNC
+ : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
;
else
return TRUE;
value = sym->st_value;
ok_tprel = FALSE;
- is_local = FALSE;
- if (h == NULL
- || !h->def_dynamic)
+ is_local = SYMBOL_REFERENCES_LOCAL (info, h);
+ if (is_local)
{
- is_local = TRUE;
if (h != NULL
&& h->root.type == bfd_link_hash_undefweak)
ok_tprel = TRUE;
setup insn. If we don't find matching arg setup
relocs, don't do any tls optimization. */
if (pass == 0
- && sec->has_tls_get_addr_call
+ && sec->nomark_tls_get_addr
&& h != NULL
&& (h == &htab->tls_get_addr->elf
|| h == &htab->tls_get_addr_fd->elf)
}
continue;
- case R_PPC64_TLSGD:
case R_PPC64_TLSLD:
+ if (!is_local)
+ continue;
+ /* Fall through. */
+ case R_PPC64_TLSGD:
if (rel + 1 < relend
&& is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
{
if (pass == 0)
{
if (!expecting_tls_get_addr
- || !sec->has_tls_get_addr_call)
+ || !sec->nomark_tls_get_addr)
continue;
if (rel + 1 < relend
Disable optimization in this case. */
if ((tls_clear & (TLS_GD | TLS_LD)) != 0
&& (tls_set & TLS_EXPLICIT) == 0
- && !sec->has_tls_get_addr_call
+ && !sec->nomark_tls_get_addr
&& ((*tls_mask & (TLS_TLS | TLS_MARK))
!= (TLS_TLS | TLS_MARK)))
continue;
- if (expecting_tls_get_addr)
+ if (expecting_tls_get_addr == 1 + !sec->nomark_tls_get_addr)
{
struct plt_entry *ent = NULL;
static bfd_boolean
ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
{
- return ((insn & (0x3f << 26)) == 12u << 26 /* addic */
- || (insn & (0x3f << 26)) == 14u << 26 /* addi */
- || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
- || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
- || (insn & (0x3f << 26)) == 36u << 26 /* stw */
- || (insn & (0x3f << 26)) == 38u << 26 /* stb */
- || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
- || (insn & (0x3f << 26)) == 42u << 26 /* lha */
- || (insn & (0x3f << 26)) == 44u << 26 /* sth */
- || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
- || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
- || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
- || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
- || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
- || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
- || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */
- || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
+ return ((insn & (0x3fu << 26)) == 12u << 26 /* addic */
+ || (insn & (0x3fu << 26)) == 14u << 26 /* addi */
+ || (insn & (0x3fu << 26)) == 32u << 26 /* lwz */
+ || (insn & (0x3fu << 26)) == 34u << 26 /* lbz */
+ || (insn & (0x3fu << 26)) == 36u << 26 /* stw */
+ || (insn & (0x3fu << 26)) == 38u << 26 /* stb */
+ || (insn & (0x3fu << 26)) == 40u << 26 /* lhz */
+ || (insn & (0x3fu << 26)) == 42u << 26 /* lha */
+ || (insn & (0x3fu << 26)) == 44u << 26 /* sth */
+ || (insn & (0x3fu << 26)) == 46u << 26 /* lmw */
+ || (insn & (0x3fu << 26)) == 47u << 26 /* stmw */
+ || (insn & (0x3fu << 26)) == 48u << 26 /* lfs */
+ || (insn & (0x3fu << 26)) == 50u << 26 /* lfd */
+ || (insn & (0x3fu << 26)) == 52u << 26 /* stfs */
+ || (insn & (0x3fu << 26)) == 54u << 26 /* stfd */
+ || (insn & (0x3fu << 26)) == 56u << 26 /* lq,lfq */
+ || ((insn & (0x3fu << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
/* Exclude lfqu by testing reloc. If relocs are ever
defined for the reduced D field in psq_lu then those
will need testing too. */
&& r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
- || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */
+ || ((insn & (0x3fu << 26)) == 58u << 26 /* ld,lwa */
&& (insn & 1) == 0)
- || (insn & (0x3f << 26)) == 60u << 26 /* stfq */
- || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */
+ || (insn & (0x3fu << 26)) == 60u << 26 /* stfq */
+ || ((insn & (0x3fu << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */
/* Exclude stfqu. psq_stu as above for psq_lu. */
&& r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
- || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */
+ || ((insn & (0x3fu << 26)) == 62u << 26 /* std,stq */
&& (insn & 1) == 0));
}
asection *sym_sec;
struct elf_link_hash_entry *h;
struct got_entry *ent;
- bfd_vma sym_addend, val, pc;
+ bfd_vma val, pc;
unsigned char buf[8];
unsigned int insn;
enum {no_check, check_lo, check_ha} insn_check;
insn = bfd_get_32 (ibfd, buf);
if (insn_check == check_lo
? !ok_lo_toc_insn (insn, r_type)
- : ((insn & ((0x3f << 26) | 0x1f << 16))
+ : ((insn & ((0x3fu << 26) | 0x1f << 16))
!= ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
{
char str[12];
case R_PPC64_GOT16_HA:
case R_PPC64_GOT16_LO_DS:
- sym_addend = rel->r_addend;
- break;
-
case R_PPC64_GOT_PCREL34:
- sym_addend = 0;
break;
}
val = h->root.u.def.value;
else
val = sym->st_value;
- val += sym_addend;
+ val += rel->r_addend;
val += sym_sec->output_section->vma + sym_sec->output_offset;
/* Fudge factor to allow for the fact that the preliminary layout
rel->r_offset & ~3, 4))
goto got_error_ret;
insn = bfd_get_32 (ibfd, buf);
- if (((insn & ((0x3f << 26) | 0x1f << 16))
+ if (((insn & ((0x3fu << 26) | 0x1f << 16))
!= ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
continue;
break;
rel->r_offset & ~3, 4))
goto got_error_ret;
insn = bfd_get_32 (ibfd, buf);
- if ((insn & (0x3f << 26 | 0x3)) != 58u << 26 /* ld */)
+ if ((insn & (0x3fu << 26 | 0x3)) != 58u << 26 /* ld */)
continue;
break;
if ((insn & (-1u << 18)) != ((1u << 26) | (1u << 20)))
continue;
insn = bfd_get_32 (ibfd, buf + 4);
- if ((insn & (0x3f << 26)) != 57u << 26)
+ if ((insn & (0x3fu << 26)) != 57u << 26)
continue;
break;
}
ent = local_got_ents[r_symndx];
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == rel->r_addend
&& ent->owner == ibfd
&& ent->tls_type == 0)
break;
htab->got_reli_size += rentsize;
}
else if (((bfd_link_pic (info)
- && !((gent->tls_type & TLS_TPREL) != 0
+ && !(gent->tls_type != 0
&& bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
|| (htab->elf.dynamic_sections_created
if (gent->got.refcount > 0)
{
if ((gent->tls_type & TLS_LD) != 0
- && !h->def_dynamic)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
{
ppc64_tlsld_got (gent->owner)->got.refcount += 1;
*pgent = gent->next;
for (gent = h->got.glist; gent != NULL; gent = gent->next)
if (!gent->is_indirect)
{
- /* Make sure this symbol is output as a dynamic symbol. */
+ /* Ensure we catch all the cases where this symbol should
+ be made dynamic. */
if (!ensure_undef_dynamic (info, h))
return FALSE;
be defined in regular objects. For the normal shared case,
discard space for relocs that have become local due to symbol
visibility changes. */
-
if (bfd_link_pic (info))
{
/* Relocs that use pc_count are those that appear on a call
if (eh->dyn_relocs != NULL)
{
- /* Make sure this symbol is output as a dynamic symbol. */
+ /* Ensure we catch all the cases where this symbol
+ should be made dynamic. */
if (!ensure_undef_dynamic (info, h))
return FALSE;
}
}
- else if (ELIMINATE_COPY_RELOCS && h->type != STT_GNU_IFUNC)
+
+ /* For a fixed position executable, discard space for
+ relocs against symbols which are not dynamic. */
+ else if (h->type != STT_GNU_IFUNC)
{
- /* For the non-pic case, discard space for relocs against
- symbols which turn out to need copy relocs or are not
- dynamic. */
if (h->dynamic_adjusted
&& !h->def_regular
&& !ELF_COMMON_DEF_P (h))
{
- /* Make sure this symbol is output as a dynamic symbol. */
+ /* Ensure we catch all the cases where this symbol
+ should be made dynamic. */
if (!ensure_undef_dynamic (info, h))
return FALSE;
+ /* But if that didn't work out, discard dynamic relocs. */
if (h->dynindx == -1)
eh->dyn_relocs = NULL;
}
htab->got_reli_size += rel_size;
}
else if (bfd_link_pic (info)
- && !((ent->tls_type & TLS_TPREL) != 0
+ && !(ent->tls_type != 0
&& bfd_link_executable (info)))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
ent->got.offset = s->size;
ent->owner = ibfd;
s->size += 16;
- if (bfd_link_pic (info))
+ if (bfd_link_dll (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += sizeof (Elf64_External_Rela);
htab->got_reli_size += rel_size;
}
else if (bfd_link_pic (info)
- && !((ent->tls_type & TLS_TPREL) != 0
+ && !(ent->tls_type != 0
&& bfd_link_executable (info)))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
asection *s = ppc64_elf_tdata (ibfd)->got;
ent->got.offset = s->size;
s->size += 16;
- if (bfd_link_pic (info))
+ if (bfd_link_dll (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += sizeof (Elf64_External_Rela);
return _bfd_elf_default_action_discarded (sec);
}
+/* These are the dynamic relocations supported by glibc. */
+
+static bfd_boolean
+ppc64_glibc_dynamic_reloc (enum elf_ppc64_reloc_type r_type)
+{
+ switch (r_type)
+ {
+ case R_PPC64_RELATIVE:
+ case R_PPC64_NONE:
+ case R_PPC64_ADDR64:
+ case R_PPC64_GLOB_DAT:
+ case R_PPC64_IRELATIVE:
+ case R_PPC64_JMP_IREL:
+ case R_PPC64_JMP_SLOT:
+ case R_PPC64_DTPMOD64:
+ case R_PPC64_DTPREL64:
+ case R_PPC64_TPREL64:
+ case R_PPC64_TPREL16_LO_DS:
+ case R_PPC64_TPREL16_DS:
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_HIGH:
+ case R_PPC64_TPREL16_HA:
+ case R_PPC64_TPREL16_HIGHA:
+ case R_PPC64_TPREL16_HIGHER:
+ case R_PPC64_TPREL16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHESTA:
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_LO:
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_ADDR16_HIGH:
+ case R_PPC64_ADDR16_HA:
+ case R_PPC64_ADDR16_HIGHA:
+ case R_PPC64_REL30:
+ case R_PPC64_COPY:
+ case R_PPC64_UADDR64:
+ case R_PPC64_UADDR32:
+ case R_PPC64_ADDR32:
+ case R_PPC64_ADDR24:
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ case R_PPC64_ADDR16_DS:
+ case R_PPC64_ADDR16_HIGHER:
+ case R_PPC64_ADDR16_HIGHEST:
+ case R_PPC64_ADDR16_HIGHERA:
+ case R_PPC64_ADDR16_HIGHESTA:
+ case R_PPC64_ADDR14:
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ case R_PPC64_REL32:
+ case R_PPC64_REL64:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
/* The RELOCATE_SECTION function is called by the ELF backend linker
to handle the relocations for a section.
bfd_boolean is_opd;
/* Assume 'at' branch hints. */
bfd_boolean is_isa_v2 = TRUE;
+ bfd_boolean warned_dynamic = FALSE;
bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
/* Initialize howto table if needed. */
case R_PPC64_LO_DS_OPT:
insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset);
- if ((insn & (0x3f << 26)) != 58u << 26)
+ if ((insn & (0x3fu << 26)) != 58u << 26)
abort ();
insn += (14u << 26) - (58u << 26);
bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset);
/* For pcrel IE to LE we already have the full
offset and thus don't need an addi here. A nop
or mr will do. */
- if ((insn & (0x3f << 26)) == 14 << 26)
+ if ((insn & (0x3fu << 26)) == 14 << 26)
{
/* Extract regs from addi rt,ra,si. */
unsigned int rt = (insn >> 21) & 0x1f;
stays with its arg setup insns, ie. that the next
reloc is the __tls_get_addr call associated with
the current reloc. Edit both insns. */
- if (input_section->has_tls_get_addr_call
+ if (input_section->nomark_tls_get_addr
&& rel + 1 < relend
&& branch_reloc_hash_match (input_bfd, rel + 1,
htab->tls_get_addr,
{
/* IE */
insn1 &= (0x1f << 21) | (0x1f << 16);
- insn1 |= 58 << 26; /* ld */
+ insn1 |= 58u << 26; /* ld */
insn2 = 0x7c636a14; /* add 3,3,13 */
if (offset != (bfd_vma) -1)
rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))
{
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
- if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */)
+ if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
{
insn += (14u << 26) - (58u << 26);
bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3));
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))
{
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
- if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */)
+ if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
{
insn += (14u << 26) - (58u << 26);
bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3));
r_type = R_PPC64_TOC16_LO;
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
}
- else if ((insn & (0x3f << 26)) == 15u << 26 /* addis */)
+ else if ((insn & (0x3fu << 26)) == 15u << 26 /* addis */)
{
r_type = R_PPC64_TOC16_HA;
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
bfd_vma off;
unsigned long indx = 0;
struct got_entry *ent;
- bfd_vma sym_addend = orig_rel.r_addend;
-
- if (r_type == R_PPC64_GOT_PCREL34
- || r_type == R_PPC64_GOT_TLSGD34
- || r_type == R_PPC64_GOT_TLSLD34
- || r_type == R_PPC64_GOT_TPREL34
- || r_type == R_PPC64_GOT_DTPREL34)
- sym_addend = 0;
if (tls_type == (TLS_TLS | TLS_LD)
- && (h == NULL
- || !h->elf.def_dynamic))
+ && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
ent = ppc64_tlsld_got (input_bfd);
else
{
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == sym_addend
+ if (ent->addend == orig_rel.r_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
else if (indx != 0
|| (bfd_link_pic (info)
&& (h == NULL
- || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)
- || (tls_type == (TLS_TLS | TLS_LD)
- && !h->elf.def_dynamic))
- && !(tls_type == (TLS_TLS | TLS_TPREL)
+ || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf))
+ && !(tls_type != 0
&& bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))))
relgot = ppc64_elf_tdata (ent->owner)->relgot;
outrel.r_offset = (got->output_section->vma
+ got->output_offset
+ off);
- outrel.r_addend = sym_addend;
+ outrel.r_addend = orig_rel.r_addend;
if (tls_type & (TLS_LD | TLS_GD))
{
outrel.r_addend = 0;
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
outrel.r_offset += 8;
- outrel.r_addend = sym_addend;
+ outrel.r_addend = orig_rel.r_addend;
outrel.r_info
= ELF64_R_INFO (indx, R_PPC64_DTPREL64);
}
emitting a reloc. */
else
{
- relocation += sym_addend;
+ relocation += orig_rel.r_addend;
if (tls_type != 0)
{
if (htab->elf.tls_sec == NULL)
abort ();
relocation = got->output_section->vma + got->output_offset + off;
+ addend = 0;
if (!(r_type == R_PPC64_GOT_PCREL34
|| r_type == R_PPC64_GOT_TLSGD34
|| r_type == R_PPC64_GOT_TLSLD34
if (plt_list)
{
struct plt_entry *ent;
- bfd_vma sym_addend = orig_rel.r_addend;
-
- if (r_type == R_PPC64_PLT_PCREL34
- || r_type == R_PPC64_PLT_PCREL34_NOTOC)
- sym_addend = 0;
for (ent = *plt_list; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1
- && ent->addend == sym_addend)
+ && ent->addend == orig_rel.r_addend)
{
asection *plt;
bfd_vma got;
+ htab->sec_info[input_section->id].toc_off);
relocation -= got;
}
- if (r_type != R_PPC64_PLT_PCREL34
- && r_type != R_PPC64_PLT_PCREL34_NOTOC)
- addend = 0;
+ addend = 0;
unresolved_reloc = FALSE;
break;
}
case R_PPC64_TOC16_LO_DS:
case R_PPC64_TOC16_HA:
addend -= TOCstart + htab->sec_info[input_section->id].toc_off;
+ if (h != NULL)
+ goto dodyn;
break;
/* Relocate against the beginning of the section. */
loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+ if (!warned_dynamic
+ && !ppc64_glibc_dynamic_reloc (ELF64_R_TYPE (outrel.r_info)))
+ {
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%P: %pB: %s against %pT "
+ "is not supported by glibc as a dynamic relocation\n"),
+ input_bfd,
+ ppc64_elf_howto_table[ELF64_R_TYPE (outrel.r_info)]->name,
+ sym_name);
+ warned_dynamic = TRUE;
+ }
+
/* If this reloc is against an external symbol, it will
be computed at runtime, so there's no need to do
anything now. However, for the sake of prelink ensure
{
bfd_byte *p = contents + (rel->r_offset & ~3);
insn = bfd_get_32 (input_bfd, p);
- if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
+ if ((insn & (0x3fu << 26)) == 12u << 26 /* addic */)
{
/* Transform addic to addi when we change reg. */
- insn &= ~((0x3f << 26) | (0x1f << 16));
+ insn &= ~((0x3fu << 26) | (0x1f << 16));
insn |= (14u << 26) | (2 << 16);
}
else
{
bfd_byte *p = contents + (rel->r_offset & ~3);
insn = bfd_get_32 (input_bfd, p);
- if ((insn & ((0x3f << 26) | 0x1f << 16))
+ if ((insn & ((0x3fu << 26) | 0x1f << 16))
!= ((15u << 26) | (13 << 16)) /* addis rt,13,imm */)
/* xgettext:c-format */
info->callbacks->minfo
forms of all the _DS relocs bloats all reloc switches in
this file. It doesn't make much sense to use these
relocs in data, so testing the insn should be safe. */
- if ((insn & (0x3f << 26)) == (56u << 26)
- || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1))
+ if ((insn & (0x3fu << 26)) == (56u << 26)
+ || ((insn & (0x3fu << 26)) == (61u << 26) && (insn & 3) == 1))
mask = 15;
relocation += addend;
addend = insn & (mask ^ 3);
enum complain_overflow complain = complain_overflow_signed;
insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
- if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+ if ((insn & (0x3fu << 26)) == 10u << 26 /* cmpli */)
complain = complain_overflow_bitfield;
else if (howto->rightshift == 0
- ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
- || (insn & (0x3f << 26)) == 24u << 26 /* ori */
- || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
- : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
- || (insn & (0x3f << 26)) == 25u << 26 /* oris */
- || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+ ? ((insn & (0x3fu << 26)) == 28u << 26 /* andi */
+ || (insn & (0x3fu << 26)) == 24u << 26 /* ori */
+ || (insn & (0x3fu << 26)) == 26u << 26 /* xori */)
+ : ((insn & (0x3fu << 26)) == 29u << 26 /* andis */
+ || (insn & (0x3fu << 26)) == 25u << 26 /* oris */
+ || (insn & (0x3fu << 26)) == 27u << 26 /* xoris */))
complain = complain_overflow_unsigned;
if (howto->complain_on_overflow != complain)
{
break;
}
- if (h->needs_copy)
+ if (h->needs_copy
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && (h->root.u.def.section == htab->elf.sdynbss
+ || h->root.u.def.section == htab->elf.sdynrelro))
{
/* This symbol needs a copy reloc. Set it up. */
Elf_Internal_Rela rela;
asection *srel;
bfd_byte *loc;
- if (h->dynindx == -1
- || (h->root.type != bfd_link_hash_defined
- && h->root.type != bfd_link_hash_defweak)
- || htab->elf.srelbss == NULL
- || htab->elf.sreldynrelro == NULL)
+ if (h->dynindx == -1)
abort ();
rela.r_offset = (h->root.u.def.value