/* PowerPC-specific support for 32-bit ELF
- Copyright (C) 1994-2020 Free Software Foundation, Inc.
+ Copyright (C) 1994-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
-
-/* This file is based on a preliminary PowerPC ELF ABI. The
- information may not match the final PowerPC ELF ABI. It includes
- suggestions from the in-progress Embedded PowerPC ABI, and that
- information may also not match. */
+/* Don't generate unused section symbols. */
+#define TARGET_KEEP_UNUSED_SECTION_SYMBOLS FALSE
#include "sysdep.h"
#include <stdarg.h>
if (error_message != NULL)
{
- static char buf[60];
- sprintf (buf, _("generic linker can't handle %s"),
- reloc_entry->howto->name);
- *error_message = buf;
+ static char *message;
+ free (message);
+ if (asprintf (&message, _("generic linker can't handle %s"),
+ reloc_entry->howto->name) < 0)
+ message = NULL;
+ *error_message = message;
}
return bfd_reloc_dangerous;
}
};
/* This is what we want for new plt/got. */
-static struct bfd_elf_special_section ppc_alt_plt =
+static const struct bfd_elf_special_section ppc_alt_plt =
{ STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
static const struct bfd_elf_special_section *
/* The type of PLT we have chosen to use. */
enum ppc_elf_plt_type plt_type;
- /* True if the target system is VxWorks. */
- unsigned int is_vxworks:1;
-
/* Whether there exist local gnu indirect function resolvers,
referenced by dynamic relocations. */
unsigned int local_ifunc_resolver:1;
int plt_slot_size;
/* The size of the first PLT entry. */
int plt_initial_entry_size;
-
- /* Small local sym cache. */
- struct sym_cache sym_cache;
};
/* Rename some of the generic section flags to better document how they
/* Get the PPC ELF linker hash table from a link_info structure. */
#define ppc_elf_hash_table(p) \
- (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
- == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL)
+ ((is_elf_hash_table ((p)->hash) \
+ && elf_hash_table_id (elf_hash_table (p)) == PPC32_ELF_DATA) \
+ ? (struct ppc_elf_link_hash_table *) (p)->hash : NULL)
/* Create an entry in a PPC ELF linker hash table. */
return FALSE;
htab = ppc_elf_hash_table (info);
- if (!htab->is_vxworks)
+ if (htab->elf.target_os != is_vxworks)
{
/* The powerpc .got has a blrl instruction in it. Mark it
executable. */
return FALSE;
}
- if (htab->is_vxworks
+ if (htab->elf.target_os == is_vxworks
&& !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
return FALSE;
htab = ppc_elf_hash_table (info);
if (htab->sbss == NULL)
{
- flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED;
+ flagword flags = SEC_IS_COMMON | SEC_SMALL_DATA | SEC_LINKER_CREATED;
if (!htab->elf.dynobj)
htab->elf.dynobj = abfd;
if (bfd_link_relocatable (info))
return TRUE;
- /* Don't do anything special with non-loaded, non-alloced sections.
- In particular, any relocs in such sections should not affect GOT
- and PLT reference counting (ie. we don't allow them to create GOT
- or PLT entries), there's no possibility or desire to optimize TLS
- relocs, and there's not much point in propagating relocs to shared
- libs that the dynamic linker won't relocate. */
- if ((sec->flags & SEC_ALLOC) == 0)
- return TRUE;
-
#ifdef DEBUG
_bfd_error_handler ("ppc_elf_check_relocs called for section %pA in %pB",
sec, abfd);
tls_type = 0;
r_type = ELF32_R_TYPE (rel->r_info);
ifunc = NULL;
- if (h == NULL && !htab->is_vxworks)
+ if (h == NULL && htab->elf.target_os != is_vxworks)
{
- Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
}
}
- if (!htab->is_vxworks
+ if (htab->elf.target_os != is_vxworks
&& is_branch_reloc (r_type)
&& h != NULL
&& h == tga)
return FALSE;
break;
+ case R_PPC_TPREL16_HI:
+ case R_PPC_TPREL16_HA:
+ sec->has_tls_reloc = 1;
+ /* Fall through. */
/* We shouldn't really be seeing TPREL32. */
case R_PPC_TPREL32:
case R_PPC_TPREL16:
case R_PPC_TPREL16_LO:
- case R_PPC_TPREL16_HI:
- case R_PPC_TPREL16_HA:
if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
asection *s;
Elf_Internal_Sym *isym;
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
void *vpp;
Elf_Internal_Sym *isym;
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
if (htab == NULL)
return FALSE;
+ htab->do_tls_opt = 1;
+
/* Make two passes through the relocs. First time check that tls
relocs involved in setting up a tls_get_addr call are indeed
followed by such a call. If they are not, don't do any tls
tls_clear = 0;
break;
+ case R_PPC_TPREL16_HA:
+ if (pass == 0)
+ {
+ unsigned char buf[4];
+ unsigned int insn;
+ bfd_vma off = rel->r_offset & ~3;
+ if (!bfd_get_section_contents (ibfd, sec, buf,
+ off, 4))
+ {
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+ return FALSE;
+ }
+ insn = bfd_get_32 (ibfd, buf);
+ /* addis rt,2,imm */
+ if ((insn & ((0x3fu << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)))
+ {
+ /* xgettext:c-format */
+ info->callbacks->minfo
+ (_("%H: warning: %s unexpected insn %#x.\n"),
+ ibfd, sec, off, "R_PPC_TPREL16_HA", insn);
+ htab->do_tls_opt = 0;
+ }
+ }
+ continue;
+
+ case R_PPC_TPREL16_HI:
+ htab->do_tls_opt = 0;
+ continue;
+
default:
continue;
}
free (relstart);
}
}
- htab->do_tls_opt = 1;
return TRUE;
}
\f
-/* Find dynamic relocs for H that apply to read-only sections. */
-
-static asection *
-readonly_dynrelocs (struct elf_link_hash_entry *h)
-{
- struct elf_dyn_relocs *p;
-
- for (p = h->dyn_relocs; p != NULL; p = p->next)
- {
- asection *s = p->sec->output_section;
-
- if (s != NULL && (s->flags & SEC_READONLY) != 0)
- return p->sec;
- }
- return NULL;
-}
-
/* Return true if we have dynamic relocs against H or any of its weak
aliases, that apply to read-only sections. Cannot be used after
size_dynamic_sections. */
struct ppc_elf_link_hash_entry *eh = ppc_elf_hash_entry (h);
do
{
- if (readonly_dynrelocs (&eh->elf))
+ if (_bfd_elf_readonly_dynrelocs (&eh->elf))
return TRUE;
eh = ppc_elf_hash_entry (eh->elf.u.alias);
} while (eh != NULL && &eh->elf != h);
|| (h->non_got_ref
&& !h->ref_regular_nonweak
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
- && !htab->is_vxworks
+ && htab->elf.target_os != is_vxworks
&& !ppc_elf_hash_entry (h)->has_sda_refs
- && !readonly_dynrelocs (h))
+ && !_bfd_elf_readonly_dynrelocs (h))
{
h->pointer_equality_needed = 0;
/* If we haven't seen a branch reloc and the symbol
executable. */
if (ELIMINATE_COPY_RELOCS
&& !ppc_elf_hash_entry (h)->has_sda_refs
- && !htab->is_vxworks
+ && htab->elf.target_os != is_vxworks
&& !h->def_regular
&& !alias_readonly_dynrelocs (h))
return TRUE;
return TRUE;
}
+/* Choose whether to use htab->iplt or htab->pltlocal rather than the
+ usual htab->elf.splt section for a PLT entry. */
+
+static inline
+bfd_boolean use_local_plt (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ return (h == NULL
+ || h->dynindx == -1
+ || !elf_hash_table (info)->dynamic_sections_created);
+}
+
/* Allocate space in associated reloc sections for dynamic relocs. */
static bfd_boolean
struct ppc_elf_link_hash_entry *eh;
struct ppc_elf_link_hash_table *htab;
struct elf_dyn_relocs *p;
- bfd_boolean dyn;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
}
}
- if (htab->is_vxworks)
+ if (htab->elf.target_os == is_vxworks)
{
struct elf_dyn_relocs **pp;
b) is an ifunc, or
c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
d) has plt16 relocs and we are linking statically. */
- dyn = htab->elf.dynamic_sections_created && h->dynindx != -1;
- if (dyn
+ if ((htab->elf.dynamic_sections_created && h->dynindx != -1)
|| h->type == STT_GNU_IFUNC
|| (h->needs_plt && h->dynamic_adjusted)
|| (h->needs_plt
if (ent->plt.refcount > 0)
{
asection *s = htab->elf.splt;
+ bfd_boolean dyn = !use_local_plt (info, h);
if (!dyn)
{
return TRUE;
}
-/* Set DF_TEXTREL if we find any dynamic relocs that apply to
- read-only sections. */
-
-static bfd_boolean
-maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
-{
- asection *sec;
-
- if (h->root.type == bfd_link_hash_indirect)
- return TRUE;
-
- sec = readonly_dynrelocs (h);
- if (sec != NULL)
- {
- struct bfd_link_info *info = (struct bfd_link_info *) info_p;
-
- info->flags |= DF_TEXTREL;
- info->callbacks->minfo
- (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
- sec->owner, h->root.root.string, sec);
-
- /* Not an error, just cut short the traversal. */
- return FALSE;
- }
- return TRUE;
-}
-
static const unsigned char glink_eh_frame_cie[] =
{
0, 0, 0, 16, /* length. */
linker script /DISCARD/, so we'll be discarding
the relocs too. */
}
- else if (htab->is_vxworks
+ else if (htab->elf.target_os == is_vxworks
&& strcmp (p->sec->output_section->name,
".tls_vars") == 0)
{
else
*local_got = (bfd_vma) -1;
- if (htab->is_vxworks)
+ if (htab->elf.target_os == is_vxworks)
continue;
/* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
- if (bfd_link_executable (info))
- {
- if (!add_dynamic_entry (DT_DEBUG, 0))
- return FALSE;
- }
-
- if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
- {
- if (!add_dynamic_entry (DT_PLTGOT, 0)
- || !add_dynamic_entry (DT_PLTRELSZ, 0)
- || !add_dynamic_entry (DT_PLTREL, DT_RELA)
- || !add_dynamic_entry (DT_JMPREL, 0))
- return FALSE;
- }
+ if (!_bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info,
+ relocs))
+ return FALSE;
if (htab->plt_type == PLT_NEW
&& htab->glink != NULL
&& !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS))
return FALSE;
}
-
- if (relocs)
- {
- if (!add_dynamic_entry (DT_RELA, 0)
- || !add_dynamic_entry (DT_RELASZ, 0)
- || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
- return FALSE;
- }
-
- /* If any dynamic relocs apply to a read-only section, then we
- need a DT_TEXTREL entry. */
- if ((info->flags & DF_TEXTREL) == 0)
- elf_link_hash_traverse (elf_hash_table (info), maybe_set_textrel,
- info);
-
- if ((info->flags & DF_TEXTREL) != 0)
- {
- if (!add_dynamic_entry (DT_TEXTREL, 0))
- return FALSE;
- }
- if (htab->is_vxworks
- && !elf_vxworks_add_dynamic_entries (output_bfd, info))
- return FALSE;
}
#undef add_dynamic_entry
sym_hashes = elf_sym_hashes (input_bfd);
/* We have to handle relocations in vxworks .tls_vars sections
specially, because the dynamic loader is 'weird'. */
- is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
+ is_vxworks_tls = (htab->elf.target_os == is_vxworks && bfd_link_pic (info)
&& !strcmp (input_section->output_section->name,
".tls_vars"));
if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
}
ifunc = NULL;
- if (!htab->is_vxworks)
+ if (htab->elf.target_os != is_vxworks)
{
struct plt_entry *ent;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
- switch (r_type)
- {
- default:
- break;
-
- case R_PPC_TPREL16_HA:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
- {
- bfd_byte *p = contents + (rel->r_offset & ~3);
- unsigned int insn = bfd_get_32 (input_bfd, p);
- if ((insn & ((0x3fu << 26) | 0x1f << 16))
- != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
- /* xgettext:c-format */
- info->callbacks->minfo
- (_("%H: warning: %s unexpected insn %#x.\n"),
- input_bfd, input_section, rel->r_offset, howto->name, insn);
- else
- bfd_put_32 (input_bfd, NOP, p);
- }
- break;
-
- case R_PPC_TPREL16_LO:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
- {
- bfd_byte *p = contents + (rel->r_offset & ~3);
- unsigned int insn = bfd_get_32 (input_bfd, p);
- insn &= ~(0x1f << 16);
- insn |= 2 << 16;
- bfd_put_32 (input_bfd, insn, p);
- }
- break;
- }
-
tls_type = 0;
switch (r_type)
{
unresolved_reloc = FALSE;
plt = htab->elf.splt;
- if (!htab->elf.dynamic_sections_created
- || h == NULL
- || h->dynindx == -1)
+ if (use_local_plt (info, h))
{
if (ifunc != NULL)
plt = htab->elf.iplt;
goto copy_reloc;
}
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC_TPREL16_HA:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ bfd_put_32 (input_bfd, NOP, p);
+ }
+ break;
+
+ case R_PPC_TPREL16_LO:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= ~(0x1f << 16);
+ insn |= 2 << 16;
+ bfd_put_32 (input_bfd, insn, p);
+ }
+ break;
+ }
+
switch (r_type)
{
default:
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
{
+ bfd_boolean dyn = !use_local_plt (info, h);
+
if (!doneone)
{
Elf_Internal_Rela rela;
asection *plt = htab->elf.splt;
asection *relplt = htab->elf.srelplt;
- if (htab->plt_type == PLT_NEW
- || !htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (htab->plt_type == PLT_NEW || !dyn)
reloc_index = ent->plt.offset / 4;
else
{
/* This symbol has an entry in the procedure linkage table.
Set it up. */
- if (htab->plt_type == PLT_VXWORKS
- && htab->elf.dynamic_sections_created
- && h->dynindx != -1)
+ if (htab->plt_type == PLT_VXWORKS && dyn)
{
bfd_vma got_offset;
const bfd_vma *plt_entry;
else
{
rela.r_addend = 0;
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (!dyn)
{
if (h->type == STT_GNU_IFUNC)
{
+ plt->output_offset
+ ent->plt.offset);
- if (htab->plt_type == PLT_OLD
- || !htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (htab->plt_type == PLT_OLD || !dyn)
{
/* We don't need to fill in the .plt. The ppc dynamic
linker will fill it in. */
if (relplt != NULL)
{
/* Fill in the entry in the .rela.plt section. */
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (!dyn)
{
if (h->type == STT_GNU_IFUNC)
rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
doneone = TRUE;
}
- if (htab->plt_type == PLT_NEW
- || !htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (htab->plt_type == PLT_NEW || !dyn)
{
unsigned char *p;
asection *plt = htab->elf.splt;
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (!dyn)
{
if (h->type == STT_GNU_IFUNC)
plt = htab->elf.iplt;
switch (dyn.d_tag)
{
case DT_PLTGOT:
- if (htab->is_vxworks)
+ if (htab->elf.target_os == is_vxworks)
s = htab->elf.sgotplt;
else
s = htab->elf.splt;
continue;
default:
- if (htab->is_vxworks
+ if (htab->elf.target_os == is_vxworks
&& elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
break;
continue;
}
/* Fill in the first entry in the VxWorks procedure linkage table. */
- if (htab->is_vxworks
+ if (htab->elf.target_os == is_vxworks
&& htab->elf.splt != NULL
&& htab->elf.splt->size != 0
&& htab->elf.splt->output_section != bfd_abs_section_ptr)
#undef ELF_OSABI
+#undef ELF_TARGET_OS
+#define ELF_TARGET_OS is_vxworks
+
/* VxWorks uses the elf default section flags for .plt. */
static const struct bfd_elf_special_section *
ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec)
{
struct ppc_elf_link_hash_table *htab
= (struct ppc_elf_link_hash_table *)ret;
- htab->is_vxworks = 1;
htab->plt_type = PLT_VXWORKS;
htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE;