/* Set the howto pointer for a PowerPC ELF reloc. */
static void
-ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+ppc_elf_info_to_howto (bfd *abfd,
arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */
static bfd_reloc_status_type
-ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ppc_elf_addr16_ha_reloc (bfd *abfd,
arelent *reloc_entry,
asymbol *symbol,
- void *data ATTRIBUTE_UNUSED,
+ void *data,
asection *input_section,
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
amt += (m->count - j - 1) * sizeof (asection *);
n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
if (n == NULL)
- return FALSE;
+ return FALSE;
n->p_type = PT_LOAD;
n->count = m->count - j;
{ STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
static const struct bfd_elf_special_section *
-ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+ppc_elf_get_sec_type_attr (bfd *abfd, asection *sec)
{
const struct bfd_elf_special_section *ssect;
free (buffer);
if (error_message)
- _bfd_error_handler (error_message, ibfd, APUINFO_SECTION_NAME);
+ _bfd_error_handler (error_message, APUINFO_SECTION_NAME, ibfd);
}
/* Prevent the output section from accumulating the input sections'
}
}
+/* Whether an undefined weak symbol should resolve to its link-time
+ value, even in PIC or PIE objects. */
+#define UNDEFWEAK_NO_DYNAMIC_RELOC(INFO, H) \
+ ((H)->root.type == bfd_link_hash_undefweak \
+ && (ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT \
+ || (INFO)->dynamic_undefined_weak == 0))
+
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
copying dynamic variables from a shared lib into an app's dynbss
section, and instead use a dynamic relocation to point into the
/* 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;
+ unsigned int maybe_local_ifunc_resolver:1;
+
/* The size of PLT entries. */
int plt_entry_size;
/* The distance between adjacent PLT slots. */
/* PR15323, ref flags aren't set for references in the same
object. */
- h->root.non_ir_ref = 1;
+ h->root.non_ir_ref_regular = 1;
}
/* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
error = TRUE;
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: uses different e_flags (0x%lx) fields "
- "than previous modules (0x%lx)"),
- ibfd, (long) new_flags, (long) old_flags);
+ (_("%B: uses different e_flags (%#x) fields "
+ "than previous modules (%#x)"),
+ ibfd, new_flags, old_flags);
}
if (error)
|| h->needs_plt)
&& h->ref_regular
&& !(SYMBOL_CALLS_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak)))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
{
/* Profiling of shared libs (and pies) is not supported with
secure plt, because ppc32 does profiling before a
&& (tga->type == STT_FUNC
|| tga->needs_plt)
&& !(SYMBOL_CALLS_LOCAL (info, tga)
- || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT
- && tga->root.type == bfd_link_hash_undefweak)))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga)))
{
struct plt_entry *ent;
for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
if (ent == NULL
|| (h->type != STT_GNU_IFUNC
&& (SYMBOL_CALLS_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak))))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))))
{
/* A PLT entry is not required/allowed when:
struct elf_link_hash_table *htab = elf_hash_table (info);
if (htab->dynamic_sections_created
+ && info->dynamic_undefined_weak != 0
&& h->root.type == bfd_link_hash_undefweak
&& h->dynindx == -1
&& !h->forced_local
|| (htab->elf.dynamic_sections_created
&& eh->elf.dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
- && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
- || eh->elf.root.type != bfd_link_hash_undefweak))
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf))
{
asection *rsec = htab->elf.srelgot;
else
eh->elf.got.offset = (bfd_vma) -1;
+ /* If no dynamic sections we can't have dynamic relocs, except for
+ IFUNCs which are handled even in static executables. */
if (!htab->elf.dynamic_sections_created
&& h->type != STT_GNU_IFUNC)
eh->dyn_relocs = NULL;
changes. */
else if (bfd_link_pic (info))
{
+ /* Discard relocs on undefined symbols that must be local. */
+ if (h->root.type == bfd_link_hash_undefined
+ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ eh->dyn_relocs = NULL;
+
+ /* Also discard relocs on undefined weak syms with non-default
+ visibility, or when dynamic_undefined_weak says so. */
+ else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ 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))
+ else if (SYMBOL_CALLS_LOCAL (info, h))
{
struct elf_dyn_relocs **pp;
}
}
- /* Discard relocs on undefined symbols that must be local. */
- if (eh->dyn_relocs != NULL
- && h->root.type == bfd_link_hash_undefined
- && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
- || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
- eh->dyn_relocs = NULL;
-
- /* Also discard relocs on undefined weak syms with non-default
- visibility. */
- if (eh->dyn_relocs != NULL
- && h->root.type == bfd_link_hash_undefweak)
+ if (eh->dyn_relocs != NULL)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- eh->dyn_relocs = NULL;
-
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
- else if (!ensure_undefweak_dynamic (info, h))
+ if (!ensure_undefweak_dynamic (info, h))
return FALSE;
}
}
wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
wrel->r_addend = got_addr;
insn &= ~0xffff;
- insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+ insn |= ((unsigned int) (got_addr + 0x8000) >> 16) & 0xffff;
bfd_put_32 (input_bfd, insn, p);
/* Convert lis to lwz, loading address from GOT. */
loc += (htab->elf.irelplt->reloc_count++
* sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ htab->local_ifunc_resolver = 1;
ent->plt.offset |= 1;
}
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1
|| SYMBOL_REFERENCES_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
locally, or the symbol was forced to be local
if (indx != 0
|| (bfd_link_pic (info)
&& (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak
+ || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
|| offp == &htab->tlsld_got.offset)))
{
asection *rsec = htab->elf.srelgot;
bfd_byte * loc;
if (ifunc != NULL)
- rsec = htab->elf.irelplt;
+ {
+ rsec = htab->elf.irelplt;
+ if (indx == 0)
+ htab->local_ifunc_resolver = 1;
+ else if (is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
outrel.r_offset = (htab->elf.sgot->output_section->vma
+ htab->elf.sgot->output_offset
+ off);
if ((bfd_link_pic (info)
&& !(h != NULL
&& ((h->root.type == bfd_link_hash_undefined
- && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
- || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
- || (h->root.type == bfd_link_hash_undefweak
- && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)))
+ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
&& (must_be_dyn_reloc (info, r_type)
|| !SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
int skip;
bfd_byte *loc;
asection *sreloc;
+ long indx = 0;
+
#ifdef DEBUG
fprintf (stderr, "ppc_elf_relocate_section needs to "
"create relocation for %s\n",
/* When generating a shared object, these relocations
are copied into the output file to be resolved at run
time. */
- sreloc = elf_section_data (input_section)->sreloc;
- if (ifunc)
- sreloc = htab->elf.irelplt;
- if (sreloc == NULL)
- return FALSE;
-
skip = 0;
outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
input_section,
if (skip)
memset (&outrel, 0, sizeof outrel);
- else if ((h != NULL
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak))
- || !SYMBOL_REFERENCES_LOCAL (info, h))
+ else if (!SYMBOL_REFERENCES_LOCAL (info, h))
{
- BFD_ASSERT (h->dynindx != -1);
+ indx = h->dynindx;
+ BFD_ASSERT (indx != -1);
unresolved_reloc = FALSE;
- outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+ outrel.r_info = ELF32_R_INFO (indx, r_type);
outrel.r_addend = rel->r_addend;
}
else
if (r_type != R_PPC_ADDR32)
{
- long indx = 0;
-
if (ifunc != NULL)
{
/* If we get here when building a static
outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
}
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (ifunc)
+ {
+ sreloc = htab->elf.irelplt;
+ if (indx == 0)
+ htab->local_ifunc_resolver = 1;
+ else if (is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
+ if (sreloc == NULL)
+ return FALSE;
+
loc = sreloc->contents;
loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- loc = (htab->elf.irelplt->contents
- + (htab->elf.irelplt->reloc_count++
- * sizeof (Elf32_External_Rela)));
+ {
+ loc = (htab->elf.irelplt->contents
+ + (htab->elf.irelplt->reloc_count++
+ * sizeof (Elf32_External_Rela)));
+ htab->local_ifunc_resolver = 1;
+ }
else
- loc = (htab->elf.srelplt->contents
- + reloc_index * sizeof (Elf32_External_Rela));
+ {
+ loc = (htab->elf.srelplt->contents
+ + reloc_index * sizeof (Elf32_External_Rela));
+ if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
if (!h->def_regular)
dyn.d_un.d_ptr = got;
break;
+ case DT_TEXTREL:
+ if (htab->local_ifunc_resolver)
+ info->callbacks->einfo
+ (_("%X%P: text relocations and GNU indirect "
+ "functions will result in a segfault at runtime\n"));
+ else if (htab->maybe_local_ifunc_resolver)
+ info->callbacks->einfo
+ (_("%P: warning: text relocations and GNU indirect "
+ "functions may result in a segfault at runtime\n"));
+ continue;
+
default:
if (htab->is_vxworks
&& elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections
#define elf_backend_fake_sections ppc_elf_fake_sections
#define elf_backend_additional_program_headers ppc_elf_additional_program_headers
-#define elf_backend_modify_segment_map ppc_elf_modify_segment_map
+#define elf_backend_modify_segment_map ppc_elf_modify_segment_map
#define elf_backend_grok_prstatus ppc_elf_grok_prstatus
#define elf_backend_grok_psinfo ppc_elf_grok_psinfo
#define elf_backend_write_core_note ppc_elf_write_core_note
/* 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 ATTRIBUTE_UNUSED, asection *sec)
+ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec)
{
if (sec->name == NULL)
return NULL;
if (ret)
{
struct ppc_elf_link_hash_table *htab
- = (struct ppc_elf_link_hash_table *)ret;
+ = (struct ppc_elf_link_hash_table *)ret;
htab->is_vxworks = 1;
htab->plt_type = PLT_VXWORKS;
htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
ppc_elf_vxworks_add_symbol_hook (bfd *abfd,
struct bfd_link_info *info,
Elf_Internal_Sym *sym,
- const char **namep ATTRIBUTE_UNUSED,
- flagword *flagsp ATTRIBUTE_UNUSED,
+ const char **namep,
+ flagword *flagsp,
asection **secp,
bfd_vma *valp)
{
- if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp,
- valp))
+ if (!elf_vxworks_add_symbol_hook (abfd, info, sym, namep, flagsp, secp,
+ valp))
return FALSE;
- return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp);
+ return ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp);
}
static void
ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
{
- ppc_elf_final_write_processing(abfd, linker);
- elf_vxworks_final_write_processing(abfd, linker);
+ ppc_elf_final_write_processing (abfd, linker);
+ elf_vxworks_final_write_processing (abfd, linker);
}
/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so