/* ELF linking support for BFD.
- Copyright (C) 1995-2018 Free Software Foundation, Inc.
+ Copyright (C) 1995-2019 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "sysdep.h"
#include "bfd.h"
-#include "bfd_stdint.h"
#include "bfdlink.h"
#include "libbfd.h"
#define ARCH_SIZE 0
if ((ibfd->flags
& (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0
&& bfd_get_flavour (ibfd) == bfd_target_elf_flavour
+ && elf_object_id (ibfd) == elf_hash_table_id (hash_table)
&& !((s = ibfd->sections) != NULL
&& s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS))
{
&& !h->def_regular)
h->root.type = bfd_link_hash_undefined;
- /* If this symbol is not being provided by the linker script, and it is
- currently defined by a dynamic object, but not by a regular object,
- then clear out any version information because the symbol will not be
- associated with the dynamic object any more. */
- if (!provide
- && h->def_dynamic
- && !h->def_regular)
+ /* If this symbol is currently defined by a dynamic object, but not
+ by a regular object, then clear out any version information because
+ the symbol will not be associated with the dynamic object any
+ more. */
+ if (h->def_dynamic && !h->def_regular)
h->verinfo.verdef = NULL;
/* Make sure this symbol is not garbage collected. */
for (p = output_bfd->sections; p ; p = p->next)
if ((p->flags & SEC_EXCLUDE) == 0
&& (p->flags & SEC_ALLOC) != 0
+ && elf_hash_table (info)->dynamic_relocs
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
{
++dynsymcount;
if (! bfd_link_relocatable (info))
{
bh = &hi->root;
+ if (bh->type == bfd_link_hash_defined
+ && bh->u.def.section->owner != NULL
+ && (bh->u.def.section->owner->flags & BFD_PLUGIN) != 0)
+ {
+ /* Mark the previous definition from IR object as
+ undefined so that the generic linker will override
+ it. */
+ bh->type = bfd_link_hash_undefined;
+ bh->u.undef.abfd = bh->u.def.section->owner;
+ }
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, shortname, BSF_INDIRECT,
bfd_ind_section_ptr,
return FALSE;
}
+ bed = get_elf_backend_data (info->output_bfd);
+
/* We only need version numbers for symbols defined in regular
objects. */
if (!h->def_regular)
- return TRUE;
+ {
+ /* Hide symbols defined in discarded input sections. */
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && discarded_section (h->root.u.def.section))
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ return TRUE;
+ }
hide = FALSE;
- bed = get_elf_backend_data (info->output_bfd);
p = strchr (h->root.root.string, ELF_VER_CHR);
if (p != NULL && h->verinfo.vertree == NULL)
{
}
erela = (const bfd_byte *) external_relocs;
- erelaend = erela + shdr->sh_size;
+ /* Setting erelaend like this and comparing with <= handles case of
+ a fuzzed object with sh_size not a multiple of sh_entsize. */
+ erelaend = erela + shdr->sh_size - shdr->sh_entsize;
irela = internal_relocs;
- while (erela < erelaend)
+ while (erela <= erelaend)
{
bfd_vma r_symndx;
&& (h->root.u.def.section->owner->flags & (DYNAMIC | BFD_PLUGIN)) == 0)
h->def_regular = 1;
+ /* Symbols defined in discarded sections shouldn't be dynamic. */
+ if (h->root.type == bfd_link_hash_undefined && h->indx == -3)
+ (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
+
/* If a weak undefined symbol has non-default visibility, we also
hide it from the dynamic linker. */
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak)
+ else if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type == bfd_link_hash_undefweak)
(*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
/* A hidden versioned symbol in executable should be forced local if
if (! is_elf_hash_table (hash_table))
return FALSE;
+ if (tag == DT_RELA || tag == DT_REL)
+ hash_table->dynamic_relocs = TRUE;
+
bed = get_elf_backend_data (hash_table->dynobj);
s = bfd_get_linker_section (hash_table->dynobj, ".dynamic");
BFD_ASSERT (s != NULL);
struct elf_link_hash_entry **sym_hash;
bfd_boolean dynamic;
Elf_External_Versym *extversym = NULL;
+ Elf_External_Versym *extversym_end = NULL;
Elf_External_Versym *ever;
struct elf_link_hash_entry *weaks;
struct elf_link_hash_entry **nondeflt_vers = NULL;
all sections contained fully therein. This makes relro
shared library sections appear as they will at run-time. */
phdr = elf_tdata (abfd)->phdr + elf_elfheader (abfd)->e_phnum;
- while (--phdr >= elf_tdata (abfd)->phdr)
+ while (phdr-- > elf_tdata (abfd)->phdr)
if (phdr->p_type == PT_GNU_RELRO)
{
for (s = abfd->sections; s != NULL; s = s->next)
Elf_Internal_Shdr *versymhdr;
versymhdr = &elf_tdata (abfd)->dynversym_hdr;
- extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+ amt = versymhdr->sh_size;
+ extversym = (Elf_External_Versym *) bfd_malloc (amt);
if (extversym == NULL)
goto error_free_sym;
- amt = versymhdr->sh_size;
if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
|| bfd_bread (extversym, amt, abfd) != amt)
goto error_free_vers;
+ extversym_end = extversym + (amt / sizeof (* extversym));
}
}
}
weaks = NULL;
- ever = extversym != NULL ? extversym + extsymoff : NULL;
+ if (extversym == NULL)
+ ever = NULL;
+ else if (extversym + extsymoff < extversym_end)
+ ever = extversym + extsymoff;
+ else
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: invalid version offset %lx (max %lx)"),
+ abfd, (long) extsymoff,
+ (long) (extversym_end - extversym) / sizeof (* extversym));
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
+
for (isym = isymbuf, isymend = isymbuf + extsymcount;
isym < isymend;
isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
else
iver.vs_vers = 0;
}
+ else if (ever >= extversym_end)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: not enough version information"),
+ abfd);
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
else
_bfd_elf_swap_versym_in (abfd, ever, &iver);
(struct bfd_link_hash_entry **) sym_hash)))
goto error_free_vers;
- if ((flags & BSF_GNU_UNIQUE)
- && (abfd->flags & DYNAMIC) == 0
- && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
- elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_unique;
+ if ((abfd->flags & DYNAMIC) == 0
+ && (bfd_get_flavour (info->output_bfd)
+ == bfd_target_elf_flavour))
+ {
+ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+ elf_tdata (info->output_bfd)->has_gnu_symbols
+ |= elf_gnu_symbol_ifunc;
+ if ((flags & BSF_GNU_UNIQUE))
+ elf_tdata (info->output_bfd)->has_gnu_symbols
+ |= elf_gnu_symbol_unique;
+ }
h = *sym_hash;
/* We need to make sure that indirect symbol dynamic flags are
asection *s;
/* Data first, since setting text_index_section changes
- _bfd_elf_link_omit_section_dynsym. */
+ _bfd_elf_omit_section_dynsym_default. */
for (s = output_bfd->sections; s != NULL; s = s->next)
if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
&& !_bfd_elf_omit_section_dynsym_default (output_bfd, info, s))
/* If this symbol should be put in the .dynsym section, then put it
there now. We already know the symbol index. We also fill in
the entry in the .hash section. */
- if (elf_hash_table (flinfo->info)->dynsym != NULL
- && h->dynindx != -1
- && elf_hash_table (flinfo->info)->dynamic_sections_created)
+ if (h->dynindx != -1
+ && elf_hash_table (flinfo->info)->dynamic_sections_created
+ && elf_hash_table (flinfo->info)->dynsym != NULL
+ && !discarded_section (elf_hash_table (flinfo->info)->dynsym))
{
bfd_byte *esym;
if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
{
/* STT_TLS symbols are relative to PT_TLS segment base. */
- BFD_ASSERT (elf_hash_table (flinfo->info)->tls_sec != NULL);
- osym.st_value -= elf_hash_table (flinfo->info)->tls_sec->vma;
+ if (elf_hash_table (flinfo->info)->tls_sec != NULL)
+ osym.st_value -= elf_hash_table (flinfo->info)->tls_sec->vma;
+ else
+ osym.st_info = ELF_ST_INFO (ELF_ST_BIND (osym.st_info),
+ STT_NOTYPE);
}
}
sym.st_value += osec->vma;
if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
{
+ struct elf_link_hash_table *htab
+ = elf_hash_table (flinfo->info);
+
/* STT_TLS symbols are relative to PT_TLS
segment base. */
- BFD_ASSERT (elf_hash_table (flinfo->info)
- ->tls_sec != NULL);
- sym.st_value -= (elf_hash_table (flinfo->info)
- ->tls_sec->vma);
+ if (htab->tls_sec != NULL)
+ sym.st_value -= htab->tls_sec->vma;
+ else
+ sym.st_info
+ = ELF_ST_INFO (ELF_ST_BIND (sym.st_info),
+ STT_NOTYPE);
}
}
std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section;
for (o = abfd->sections; o != NULL; o = o->next)
{
+ bfd_boolean remove_section = FALSE;
+
if ((std_attrs_section && strcmp (o->name, std_attrs_section) == 0)
|| strcmp (o->name, ".gnu.attributes") == 0)
{
}
attr_size = bfd_elf_obj_attr_size (abfd);
+ bfd_set_section_size (abfd, o, attr_size);
+ /* Skip this section later on. */
+ o->map_head.link_order = NULL;
if (attr_size)
- {
- bfd_set_section_size (abfd, o, attr_size);
- attr_section = o;
- /* Skip this section later on. */
- o->map_head.link_order = NULL;
- }
+ attr_section = o;
else
- o->flags |= SEC_EXCLUDE;
+ remove_section = TRUE;
}
else if ((o->flags & SEC_GROUP) != 0 && o->size == 0)
{
/* Remove empty group section from linker output. */
+ remove_section = TRUE;
+ }
+ if (remove_section)
+ {
o->flags |= SEC_EXCLUDE;
bfd_section_list_remove (abfd, o);
abfd->section_count--;