/* x86 specific support for ELF
- Copyright (C) 2017 Free Software Foundation, Inc.
+ Copyright (C) 2017-2018 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
- /* Clear the reference count of function pointer relocations if
- symbol isn't a normal function. */
- if (h->type != STT_FUNC)
- eh->func_pointer_refcount = 0;
-
/* We can't use the GOT PLT if pointer equality is needed since
finish_dynamic_symbol won't clear symbol value and the dynamic
linker won't update the GOT slot. We will get into an infinite
&& h->got.refcount > 0)
{
/* Don't use the regular PLT if there are both GOT and GOTPLT
- reloctions. */
+ reloctions. */
h->plt.offset = (bfd_vma) -1;
/* Use the GOT PLT. */
/* Don't create the PLT entry if there are only function pointer
relocations which can be resolved at run-time. */
else if (htab->elf.dynamic_sections_created
- && (h->plt.refcount > eh->func_pointer_refcount
+ && (h->plt.refcount > 0
|| eh->plt_got.refcount > 0))
{
bfd_boolean use_plt_got = eh->plt_got.refcount > 0;
- /* Clear the reference count of function pointer relocations
- if PLT is used. */
- eh->func_pointer_refcount = 0;
-
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
asection *s = htab->elf.splt;
asection *second_s = htab->plt_second;
asection *got_s = htab->plt_got;
+ bfd_boolean use_plt;
/* If this is the first .plt entry, make room for the special
first entry. The .plt section is used by prelink to undo
}
/* If this symbol is not defined in a regular file, and we are
- not generating a shared library, then set the symbol to this
- location in the .plt. This is required to make function
- pointers compare as equal between the normal executable and
- the shared library. */
- if (! bfd_link_pic (info)
- && !h->def_regular)
+ generating PDE, then set the symbol to this location in the
+ .plt. This is required to make function pointers compare
+ as equal between PDE and the shared library.
+
+ NB: If PLT is PC-relative, we can use the .plt in PIE for
+ function address. */
+ if (h->def_regular)
+ use_plt = FALSE;
+ else if (htab->pcrel_plt)
+ use_plt = ! bfd_link_dll (info);
+ else
+ use_plt = bfd_link_pde (info);
+ if (use_plt)
{
if (use_plt_got)
{
pointer initialization. */
if ((!h->non_got_ref
- || eh->func_pointer_refcount > 0
|| (h->root.type == bfd_link_hash_undefweak
&& !resolved_to_zero))
&& ((h->def_dynamic
}
eh->dyn_relocs = NULL;
- eh->func_pointer_refcount = 0;
keep: ;
}
return TRUE;
}
-/* Find any dynamic relocs that apply to read-only sections. */
+/* Find dynamic relocs for H that apply to read-only sections. */
-bfd_boolean
-_bfd_x86_elf_readonly_dynrelocs (struct elf_link_hash_entry *h,
- void *inf)
+static asection *
+readonly_dynrelocs (struct elf_link_hash_entry *h)
{
- struct elf_x86_link_hash_entry *eh;
struct elf_dyn_relocs *p;
+ for (p = elf_x86_hash_entry (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;
+}
+
+/* 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 *inf)
+{
+ asection *sec;
+
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
+
/* Skip local IFUNC symbols. */
if (h->forced_local && h->type == STT_GNU_IFUNC)
return TRUE;
- eh = (struct elf_x86_link_hash_entry *) h;
- for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ sec = readonly_dynrelocs (h);
+ if (sec != NULL)
{
- asection *s = p->sec->output_section;
-
- if (s != NULL && (s->flags & SEC_READONLY) != 0)
- {
- struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
- info->flags |= DF_TEXTREL;
+ info->flags |= DF_TEXTREL;
+ /* xgettext:c-format */
+ info->callbacks->minfo (_("%pB: dynamic relocation against `%pT' "
+ "in read-only section `%pA'\n"),
+ sec->owner, h->root.root.string, sec);
- if ((info->warn_shared_textrel && bfd_link_pic (info))
- || info->error_textrel)
- /* xgettext:c-format */
- info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"),
- p->sec->owner, h->root.root.string,
- p->sec);
+ if ((info->warn_shared_textrel && bfd_link_pic (info))
+ || info->error_textrel)
+ /* xgettext:c-format */
+ info->callbacks->einfo (_("%P: %pB: warning: relocation against `%s' "
+ "in read-only section `%pA'\n"),
+ sec->owner, h->root.root.string, sec);
- /* Not an error, just cut short the traversal. */
- return FALSE;
- }
+ /* Not an error, just cut short the traversal. */
+ return FALSE;
}
return TRUE;
}
ret->dt_reloc_sz = DT_RELASZ;
ret->dt_reloc_ent = DT_RELAENT;
ret->got_entry_size = 8;
+ ret->pcrel_plt = TRUE;
ret->tls_get_addr = "__tls_get_addr";
}
if (ABI_64_P (abfd))
ret->dt_reloc_ent = DT_RELENT;
ret->sizeof_reloc = sizeof (Elf32_External_Rel);
ret->got_entry_size = 4;
+ ret->pcrel_plt = FALSE;
ret->pointer_r_type = R_386_32;
ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
ret->dynamic_interpreter_size
return 0;
}
+/* Mark symbol, NAME, as locally defined by linker if it is referenced
+ and not defined in a relocatable object file. */
+
+static void
+elf_x86_linker_defined (struct bfd_link_info *info, const char *name)
+{
+ struct elf_link_hash_entry *h;
+
+ h = elf_link_hash_lookup (elf_hash_table (info), name,
+ FALSE, FALSE, FALSE);
+ if (h == NULL)
+ return;
+
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->root.type == bfd_link_hash_new
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_common
+ || (!h->def_regular && h->def_dynamic))
+ {
+ elf_x86_hash_entry (h)->local_ref = 2;
+ elf_x86_hash_entry (h)->linker_def = 1;
+ }
+}
+
+/* Hide a linker-defined symbol, NAME, with hidden visibility. */
+
+static void
+elf_x86_hide_linker_defined (struct bfd_link_info *info,
+ const char *name)
+{
+ struct elf_link_hash_entry *h;
+
+ h = elf_link_hash_lookup (elf_hash_table (info), name,
+ FALSE, FALSE, FALSE);
+ if (h == NULL)
+ return;
+
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+ || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+ _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+}
+
bfd_boolean
_bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
{
htab->tls_get_addr,
FALSE, FALSE, FALSE);
if (h != NULL)
- elf_x86_hash_entry (h)->tls_get_addr = 1;
+ {
+ elf_x86_hash_entry (h)->tls_get_addr = 1;
+
+ /* Check the versioned __tls_get_addr symbol. */
+ while (h->root.type == bfd_link_hash_indirect)
+ {
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ elf_x86_hash_entry (h)->tls_get_addr = 1;
+ }
+ }
/* "__ehdr_start" will be defined by linker as a hidden symbol
later if it is referenced and not defined. */
- h = elf_link_hash_lookup (elf_hash_table (info),
- "__ehdr_start",
- FALSE, FALSE, FALSE);
- if (h != NULL
- && (h->root.type == bfd_link_hash_new
- || h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_common))
+ elf_x86_linker_defined (info, "__ehdr_start");
+
+ if (bfd_link_executable (info))
+ {
+ /* References to __bss_start, _end and _edata should be
+ locally resolved within executables. */
+ elf_x86_linker_defined (info, "__bss_start");
+ elf_x86_linker_defined (info, "_end");
+ elf_x86_linker_defined (info, "_edata");
+ }
+ else
{
- elf_x86_hash_entry (h)->local_ref = 2;
- elf_x86_hash_entry (h)->linker_def = 1;
+ /* Hide hidden __bss_start, _end and _edata in shared
+ libraries. */
+ elf_x86_hide_linker_defined (info, "__bss_start");
+ elf_x86_hide_linker_defined (info, "_end");
+ elf_x86_hide_linker_defined (info, "_edata");
}
}
}
if ((info->warn_shared_textrel && bfd_link_pic (info))
|| info->error_textrel)
/* xgettext:c-format */
- info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"),
- p->sec->owner, p->sec);
+ info->callbacks->einfo
+ (_("%P: %pB: warning: relocation "
+ "in read-only section `%pA'\n"),
+ p->sec->owner, p->sec);
}
}
}
if (htab->tls_ld_or_ldm_got.refcount > 0)
{
/* Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM
- or R_X86_64_TLSLD relocs. */
+ or R_X86_64_TLSLD relocs. */
htab->tls_ld_or_ldm_got.offset = htab->elf.sgot->size;
htab->elf.sgot->size += 2 * htab->got_entry_size;
htab->elf.srelgot->size += htab->sizeof_reloc;
/* Don't allocate .got.plt section if there are no GOT nor PLT
entries and there is no reference to _GLOBAL_OFFSET_TABLE_. */
if ((htab->elf.hgot == NULL
- || !htab->elf.hgot->ref_regular_nonweak)
+ || !htab->got_referenced)
&& (htab->elf.sgotplt->size == bed->got_header_size)
&& (htab->elf.splt == NULL
|| htab->elf.splt->size == 0)
|| htab->elf.iplt->size == 0)
&& (htab->elf.igotplt == NULL
|| htab->elf.igotplt->size == 0))
- htab->elf.sgotplt->size = 0;
+ {
+ htab->elf.sgotplt->size = 0;
+ /* Solaris requires to keep _GLOBAL_OFFSET_TABLE_ even if it
+ isn't used. */
+ if (htab->elf.hgot != NULL && htab->target_os != is_solaris)
+ {
+ /* Remove the unused _GLOBAL_OFFSET_TABLE_ from symbol
+ table. */
+ htab->elf.hgot->root.type = bfd_link_hash_undefined;
+ htab->elf.hgot->root.u.undef.abfd
+ = htab->elf.hgot->root.u.def.section->owner;
+ htab->elf.hgot->root.linker_def = 0;
+ htab->elf.hgot->ref_regular = 0;
+ htab->elf.hgot->def_regular = 0;
+ }
+ }
}
if (_bfd_elf_eh_frame_present (info))
/* 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 (&htab->elf,
- _bfd_x86_elf_readonly_dynrelocs,
- info);
+ elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info);
if ((info->flags & DF_TEXTREL) != 0)
{
if (htab->readonly_dynrelocs_against_ifunc)
{
info->callbacks->einfo
- (_("%P%X: read-only segment has dynamic IFUNC relocations; recompile with -fPIC\n"));
+ (_("%P%X: read-only segment has dynamic IFUNC relocations;"
+ " recompile with -fPIC\n"));
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (bfd_is_abs_section (htab->elf.sgotplt->output_section))
{
_bfd_error_handler
- (_("discarded output section: `%A'"), htab->elf.sgotplt);
+ (_("discarded output section: `%pA'"), htab->elf.sgotplt);
return NULL;
}
: sdyn->output_section->vma + sdyn->output_offset);
/* Set the first entry in the global offset table to the address
- of the dynamic section. Write GOT[1] and GOT[2], needed for
+ of the dynamic section. Write GOT[1] and GOT[2], needed for
the dynamic linker. */
if (htab->got_entry_size == 8)
{
dir->pointer_equality_needed |= ind->pointer_equality_needed;
}
else
- {
- if (eind->func_pointer_refcount > 0)
- {
- edir->func_pointer_refcount += eind->func_pointer_refcount;
- eind->func_pointer_refcount = 0;
- }
-
- _bfd_elf_link_hash_copy_indirect (info, dir, ind);
- }
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
/* Remove undefined weak symbol from the dynamic symbol table if it
return TRUE;
}
+/* Change the STT_GNU_IFUNC symbol defined in position-dependent
+ executable into the normal function symbol and set its address
+ to its PLT entry, which should be resolved by R_*_IRELATIVE at
+ run-time. */
+
+void
+_bfd_x86_elf_link_fixup_ifunc_symbol (struct bfd_link_info *info,
+ struct elf_x86_link_hash_table *htab,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ if (bfd_link_pde (info)
+ && h->def_regular
+ && h->dynindx != -1
+ && h->plt.offset != (bfd_vma) -1
+ && h->type == STT_GNU_IFUNC
+ && h->pointer_equality_needed)
+ {
+ asection *plt_s;
+ bfd_vma plt_offset;
+ bfd *output_bfd = info->output_bfd;
+
+ if (htab->plt_second)
+ {
+ struct elf_x86_link_hash_entry *eh
+ = (struct elf_x86_link_hash_entry *) h;
+
+ plt_s = htab->plt_second;
+ plt_offset = eh->plt_second.offset;
+ }
+ else
+ {
+ plt_s = htab->elf.splt;
+ plt_offset = h->plt.offset;
+ }
+
+ sym->st_size = 0;
+ sym->st_info = ELF_ST_INFO (ELF_ST_BIND (sym->st_info), STT_FUNC);
+ sym->st_shndx
+ = _bfd_elf_section_from_bfd_section (output_bfd,
+ plt_s->output_section);
+ sym->st_value = (plt_s->output_section->vma
+ + plt_s->output_offset + plt_offset);
+ }
+}
+
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
bfd_boolean
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->u.weakdef != NULL)
+ if (h->is_weakalias)
{
- BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
- || h->u.weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->u.weakdef->root.u.def.section;
- h->root.u.def.value = h->u.weakdef->root.u.def.value;
+ struct elf_link_hash_entry *def = weakdef (h);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = def->root.u.def.section;
+ h->root.u.def.value = def->root.u.def.value;
if (ELIMINATE_COPY_RELOCS
|| info->nocopyreloc
|| SYMBOL_NO_COPYRELOC (info, eh))
{
/* NB: needs_copy is always 0 for i386. */
- h->non_got_ref = h->u.weakdef->non_got_ref;
- eh->needs_copy = h->u.weakdef->needs_copy;
+ h->non_got_ref = def->non_got_ref;
+ eh->needs_copy = def->needs_copy;
}
return TRUE;
}
|| (!eh->gotoff_ref
&& htab->target_os != is_vxworks)))
{
- for (p = eh->dyn_relocs; p != NULL; p = p->next)
- {
- s = p->sec->output_section;
- if (s != NULL && (s->flags & SEC_READONLY) != 0)
- break;
- }
-
- /* If we didn't find any dynamic relocs in read-only sections,
+ /* 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. */
- if (p == NULL)
+ if (!readonly_dynrelocs (h))
{
h->non_got_ref = 0;
return TRUE;
weak symbol dynamic so that PC relative branch to the undefined
weak symbol will land to address 0. */
struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h);
- if (h->plt.refcount > eh->func_pointer_refcount
+ if (h->plt.refcount > 0
|| eh->plt_got.refcount > 0)
return;
}
&& htab->interp == NULL)
|| info->dynamic_undefined_weak == 0))
|| ((h->def_regular || ELF_COMMON_DEF_P (h))
- && h->versioned == unversioned
&& info->version_info != NULL
- && bfd_hide_sym_by_version (info->version_info,
- h->root.root.string)))
+ && _bfd_elf_link_hide_sym_by_version (info, h)))
{
eh->local_ref = 2;
return TRUE;
{
elf_property *prop;
- switch (type)
+ if (type == GNU_PROPERTY_X86_COMPAT_ISA_1_USED
+ || type == GNU_PROPERTY_X86_COMPAT_ISA_1_NEEDED
+ || (type >= GNU_PROPERTY_X86_UINT32_AND_LO
+ && type <= GNU_PROPERTY_X86_UINT32_AND_HI)
+ || (type >= GNU_PROPERTY_X86_UINT32_OR_LO
+ && type <= GNU_PROPERTY_X86_UINT32_OR_HI)
+ || (type >= GNU_PROPERTY_X86_UINT32_OR_AND_LO
+ && type <= GNU_PROPERTY_X86_UINT32_OR_AND_HI))
{
- case GNU_PROPERTY_X86_ISA_1_USED:
- case GNU_PROPERTY_X86_ISA_1_NEEDED:
- case GNU_PROPERTY_X86_FEATURE_1_AND:
if (datasz != 4)
{
_bfd_error_handler
- ((type == GNU_PROPERTY_X86_ISA_1_USED
- ? _("error: %B: <corrupt x86 ISA used size: 0x%x>")
- : (type == GNU_PROPERTY_X86_ISA_1_NEEDED
- ? _("error: %B: <corrupt x86 ISA needed size: 0x%x>")
- : _("error: %B: <corrupt x86 feature size: 0x%x>"))),
- abfd, datasz);
+ (_("error: %pB: <corrupt x86 property (0x%x) size: 0x%x>"),
+ abfd, type, datasz);
return property_corrupt;
}
prop = _bfd_elf_get_property (abfd, type, datasz);
- /* Combine properties of the same type. */
prop->u.number |= bfd_h_get_32 (abfd, ptr);
prop->pr_kind = property_number;
- break;
-
- default:
- return property_ignored;
+ return property_number;
}
- return property_number;
+ return property_ignored;
}
/* Merge x86 GNU property BPROP with APROP. If APROP isn't NULL,
bfd_boolean updated = FALSE;
unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type;
- switch (pr_type)
+ if (pr_type == GNU_PROPERTY_X86_COMPAT_ISA_1_USED
+ || (pr_type >= GNU_PROPERTY_X86_UINT32_OR_AND_LO
+ && pr_type <= GNU_PROPERTY_X86_UINT32_OR_AND_HI))
+ {
+ if (aprop == NULL || bprop == NULL)
+ {
+ /* Only one of APROP and BPROP can be NULL. */
+ if (aprop != NULL)
+ {
+ /* Remove this property since the other input file doesn't
+ have it. */
+ aprop->pr_kind = property_remove;
+ updated = TRUE;
+ }
+ return updated;
+ }
+ goto or_property;
+ }
+ else if (pr_type == GNU_PROPERTY_X86_COMPAT_ISA_1_NEEDED
+ || (pr_type >= GNU_PROPERTY_X86_UINT32_OR_LO
+ && pr_type <= GNU_PROPERTY_X86_UINT32_OR_HI))
{
- case GNU_PROPERTY_X86_ISA_1_USED:
- case GNU_PROPERTY_X86_ISA_1_NEEDED:
if (aprop != NULL && bprop != NULL)
{
+or_property:
number = aprop->u.number;
aprop->u.number = number | bprop->u.number;
- updated = number != (unsigned int) aprop->u.number;
+ /* Remove the property if all bits are empty. */
+ if (aprop->u.number == 0)
+ {
+ aprop->pr_kind = property_remove;
+ updated = TRUE;
+ }
+ else
+ updated = number != (unsigned int) aprop->u.number;
}
else
{
- /* Return TRUE if APROP is NULL to indicate that BPROP should
- be added to ABFD. */
- updated = aprop == NULL;
+ /* Only one of APROP and BPROP can be NULL. */
+ if (aprop != NULL)
+ {
+ if (aprop->u.number == 0)
+ {
+ /* Remove APROP if all bits are empty. */
+ aprop->pr_kind = property_remove;
+ updated = TRUE;
+ }
+ }
+ else
+ {
+ /* Return TRUE if APROP is NULL and all bits of BPROP
+ aren't empty to indicate that BPROP should be added
+ to ABFD. */
+ updated = bprop->u.number != 0;
+ }
}
- break;
-
- case GNU_PROPERTY_X86_FEATURE_1_AND:
+ return updated;
+ }
+ else if (pr_type >= GNU_PROPERTY_X86_UINT32_AND_LO
+ && pr_type <= GNU_PROPERTY_X86_UINT32_AND_HI)
+ {
/* Only one of APROP and BPROP can be NULL:
1. APROP & BPROP when both APROP and BPROP aren't NULL.
2. If APROP is NULL, remove x86 feature.
updated = TRUE;
}
}
- break;
-
- default:
+ return updated;
+ }
+ else
+ {
/* Never should happen. */
abort ();
}
const struct elf_backend_data *bed;
unsigned int class_align = ABI_64_P (info->output_bfd) ? 3 : 2;
unsigned int got_align;
+ bfd_boolean has_text = FALSE;
features = 0;
if (info->ibt)
if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour
&& bfd_count_sections (pbfd) != 0)
{
+ if (!has_text)
+ {
+ /* Check if there is no non-empty text section. */
+ sec = bfd_get_section_by_name (pbfd, ".text");
+ if (sec != NULL && sec->size != 0)
+ has_text = TRUE;
+ }
+
ebfd = pbfd;
if (elf_properties (pbfd) != NULL)
break;
}
- if (ebfd != NULL && features)
+ bed = get_elf_backend_data (info->output_bfd);
+
+ htab = elf_x86_hash_table (info, bed->target_id);
+ if (htab == NULL)
+ return pbfd;
+
+ if (ebfd != NULL)
{
- /* If features is set, add GNU_PROPERTY_X86_FEATURE_1_IBT and
- GNU_PROPERTY_X86_FEATURE_1_SHSTK. */
- prop = _bfd_elf_get_property (ebfd,
- GNU_PROPERTY_X86_FEATURE_1_AND,
- 4);
- prop->u.number |= features;
- prop->pr_kind = property_number;
+ prop = NULL;
+ if (features)
+ {
+ /* If features is set, add GNU_PROPERTY_X86_FEATURE_1_IBT and
+ GNU_PROPERTY_X86_FEATURE_1_SHSTK. */
+ prop = _bfd_elf_get_property (ebfd,
+ GNU_PROPERTY_X86_FEATURE_1_AND,
+ 4);
+ prop->u.number |= features;
+ prop->pr_kind = property_number;
+ }
+ else if (has_text
+ && elf_tdata (info->output_bfd)->o->build_id.sec == NULL
+ && !htab->elf.dynamic_sections_created
+ && !info->traditional_format
+ && (info->output_bfd->flags & D_PAGED) != 0
+ && info->separate_code)
+ {
+ /* If the separate code program header is needed, make sure
+ that the first read-only PT_LOAD segment has no code by
+ adding a GNU_PROPERTY_X86_FEATURE_2_NEEDED note. */
+ elf_property_list *list;
+ bfd_boolean need_property = TRUE;
+
+ for (list = elf_properties (ebfd); list; list = list->next)
+ {
+ unsigned int pr_type = list->property.pr_type;
+ if (pr_type == GNU_PROPERTY_STACK_SIZE
+ || pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED
+ || pr_type == GNU_PROPERTY_X86_COMPAT_ISA_1_NEEDED
+ || (pr_type >= GNU_PROPERTY_X86_UINT32_OR_LO
+ && pr_type <= GNU_PROPERTY_X86_UINT32_OR_HI))
+ {
+ /* These properties won't be removed during merging. */
+ need_property = FALSE;
+ break;
+ }
+ }
+
+ if (need_property)
+ {
+ prop = _bfd_elf_get_property
+ (ebfd, GNU_PROPERTY_X86_FEATURE_2_NEEDED, 4);
+ prop->u.number = GNU_PROPERTY_X86_FEATURE_2_X86;
+ prop->pr_kind = property_number;
+ }
+ }
/* Create the GNU property note section if needed. */
- if (pbfd == NULL)
+ if (prop != NULL && pbfd == NULL)
{
sec = bfd_make_section_with_flags (ebfd,
NOTE_GNU_PROPERTY_SECTION_NAME,
| SEC_HAS_CONTENTS
| SEC_DATA));
if (sec == NULL)
- info->callbacks->einfo (_("%F: failed to create GNU property section\n"));
+ info->callbacks->einfo (_("%F%P: failed to create GNU property section\n"));
if (!bfd_set_section_alignment (ebfd, sec, class_align))
{
error_alignment:
- info->callbacks->einfo (_("%F%A: failed to align section\n"),
+ info->callbacks->einfo (_("%F%pA: failed to align section\n"),
sec);
}
pbfd = _bfd_elf_link_setup_gnu_properties (info);
- bed = get_elf_backend_data (info->output_bfd);
-
- htab = elf_x86_hash_table (info, bed->target_id);
- if (htab == NULL)
- return pbfd;
-
htab->r_info = init_table->r_info;
htab->r_sym = init_table->r_sym;
abfd = abfd->link.next)
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
&& (abfd->flags
- & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+ & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0
+ && bed->relocs_compatible (abfd->xvec,
+ info->output_bfd->xvec))
{
htab->elf.dynobj = abfd;
dynobj = abfd;
&& !elf_vxworks_create_dynamic_sections (dynobj, info,
&htab->srelplt2))
{
- info->callbacks->einfo (_("%F: failed to create VxWorks dynamic sections\n"));
+ info->callbacks->einfo (_("%F%P: failed to create VxWorks dynamic sections\n"));
return pbfd;
}
don't need to do it in check_relocs. */
if (htab->elf.sgot == NULL
&& !_bfd_elf_create_got_section (dynobj, info))
- info->callbacks->einfo (_("%F: failed to create GOT sections\n"));
+ info->callbacks->einfo (_("%F%P: failed to create GOT sections\n"));
got_align = (bed->target_id == X86_64_ELF_DATA) ? 3 : 2;
/* Create the ifunc sections here so that check_relocs can be
simplified. */
if (!_bfd_elf_create_ifunc_sections (dynobj, info))
- info->callbacks->einfo (_("%F: failed to create ifunc sections\n"));
+ info->callbacks->einfo (_("%F%P: failed to create ifunc sections\n"));
plt_alignment = bfd_log2 (htab->plt.plt_entry_size);
".plt.got",
pltflags);
if (sec == NULL)
- info->callbacks->einfo (_("%F: failed to create GOT PLT section\n"));
+ info->callbacks->einfo (_("%F%P: failed to create GOT PLT section\n"));
if (!bfd_set_section_alignment (dynobj, sec,
non_lazy_plt_alignment))
".plt.sec",
pltflags);
if (sec == NULL)
- info->callbacks->einfo (_("%F: failed to create IBT-enabled PLT section\n"));
+ info->callbacks->einfo (_("%F%P: failed to create IBT-enabled PLT section\n"));
if (!bfd_set_section_alignment (dynobj, sec,
plt_alignment))
".plt.sec",
pltflags);
if (sec == NULL)
- info->callbacks->einfo (_("%F: failed to create BND PLT section\n"));
+ info->callbacks->einfo (_("%F%P: failed to create BND PLT section\n"));
if (!bfd_set_section_alignment (dynobj, sec,
non_lazy_plt_alignment))
".eh_frame",
flags);
if (sec == NULL)
- info->callbacks->einfo (_("%F: failed to create PLT .eh_frame section\n"));
+ info->callbacks->einfo (_("%F%P: failed to create PLT .eh_frame section\n"));
if (!bfd_set_section_alignment (dynobj, sec, class_align))
goto error_alignment;
".eh_frame",
flags);
if (sec == NULL)
- info->callbacks->einfo (_("%F: failed to create GOT PLT .eh_frame section\n"));
+ info->callbacks->einfo (_("%F%P: failed to create GOT PLT .eh_frame section\n"));
if (!bfd_set_section_alignment (dynobj, sec, class_align))
goto error_alignment;
".eh_frame",
flags);
if (sec == NULL)
- info->callbacks->einfo (_("%F: failed to create the second PLT .eh_frame section\n"));
+ info->callbacks->einfo (_("%F%P: failed to create the second PLT .eh_frame section\n"));
if (!bfd_set_section_alignment (dynobj, sec, class_align))
goto error_alignment;
return pbfd;
}
+
+/* Fix up x86 GNU properties. */
+
+void
+_bfd_x86_elf_link_fixup_gnu_properties (struct bfd_link_info *info,
+ elf_property_list **listp)
+{
+ elf_property_list *p;
+
+ for (p = *listp; p; p = p->next)
+ {
+ unsigned int type = p->property.pr_type;
+ if (type == GNU_PROPERTY_X86_COMPAT_ISA_1_USED
+ || type == GNU_PROPERTY_X86_COMPAT_ISA_1_NEEDED
+ || (type >= GNU_PROPERTY_X86_UINT32_AND_LO
+ && type <= GNU_PROPERTY_X86_UINT32_AND_HI)
+ || (type >= GNU_PROPERTY_X86_UINT32_OR_LO
+ && type <= GNU_PROPERTY_X86_UINT32_OR_HI)
+ || (type >= GNU_PROPERTY_X86_UINT32_OR_AND_LO
+ && type <= GNU_PROPERTY_X86_UINT32_OR_AND_HI))
+ {
+ if (p->property.u.number == 0)
+ {
+ /* Remove empty property. */
+ *listp = p->next;
+ continue;
+ }
+
+ /* Mark x86-specific properties with X86_UINT32_VALID for
+ non-relocatable output. */
+ if (!bfd_link_relocatable (info))
+ p->property.u.number |= GNU_PROPERTY_X86_UINT32_VALID;
+
+ listp = &p->next;
+ }
+ else if (type > GNU_PROPERTY_HIPROC)
+ {
+ /* The property list is sorted in order of type. */
+ break;
+ }
+ }
+}