/* 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))
{
elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
}
- if (info->emit_gnu_hash)
+ if (info->emit_gnu_hash && bed->record_xhash_symbol == NULL)
{
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash",
flags | SEC_READONLY);
|| (d != NULL
&& h->non_elf
&& (*d->match) (&d->head, NULL, h->root.root.string)))
- h->dynamic = 1;
+ {
+ h->dynamic = 1;
+ /* NB: If a symbol is made dynamic by --dynamic-list, it has
+ non-IR reference. */
+ h->root.non_ir_ref_dynamic = 1;
+ }
}
/* Record an assignment to a symbol made by a linker script. We need
&& !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. */
|| h->ref_dynamic
|| bfd_link_dll (info)
|| elf_hash_table (info)->is_relocatable_executable)
+ && !h->forced_local
&& h->dynindx == -1)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
SHT_PROGBITS/SHT_NOBITS. */
case SHT_NULL:
htab = elf_hash_table (info);
- if (p == htab->tls_sec)
- return FALSE;
-
if (htab->text_index_section != NULL)
return p != htab->text_index_section && p != htab->data_index_section;
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 TRUE;
}
+/* Return TRUE and set *HIDE to TRUE if the versioned symbol is
+ hidden. Set *T_P to NULL if there is no match. */
+
+static bfd_boolean
+_bfd_elf_link_hide_versioned_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ const char *version_p,
+ struct bfd_elf_version_tree **t_p,
+ bfd_boolean *hide)
+{
+ struct bfd_elf_version_tree *t;
+
+ /* Look for the version. If we find it, it is no longer weak. */
+ for (t = info->version_info; t != NULL; t = t->next)
+ {
+ if (strcmp (t->name, version_p) == 0)
+ {
+ size_t len;
+ char *alc;
+ struct bfd_elf_version_expr *d;
+
+ len = version_p - h->root.root.string;
+ alc = (char *) bfd_malloc (len);
+ if (alc == NULL)
+ return FALSE;
+ memcpy (alc, h->root.root.string, len - 1);
+ alc[len - 1] = '\0';
+ if (alc[len - 2] == ELF_VER_CHR)
+ alc[len - 2] = '\0';
+
+ h->verinfo.vertree = t;
+ t->used = TRUE;
+ d = NULL;
+
+ if (t->globals.list != NULL)
+ d = (*t->match) (&t->globals, NULL, alc);
+
+ /* See if there is anything to force this symbol to
+ local scope. */
+ if (d == NULL && t->locals.list != NULL)
+ {
+ d = (*t->match) (&t->locals, NULL, alc);
+ if (d != NULL
+ && h->dynindx != -1
+ && ! info->export_dynamic)
+ *hide = TRUE;
+ }
+
+ free (alc);
+ break;
+ }
+ }
+
+ *t_p = t;
+
+ return TRUE;
+}
+
+/* Return TRUE if the symbol H is hidden by version script. */
+
+bfd_boolean
+_bfd_elf_link_hide_sym_by_version (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ const char *p;
+ bfd_boolean hide = FALSE;
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (info->output_bfd);
+
+ /* Version script only hides symbols defined in regular objects. */
+ if (!h->def_regular && !ELF_COMMON_DEF_P (h))
+ return TRUE;
+
+ p = strchr (h->root.root.string, ELF_VER_CHR);
+ if (p != NULL && h->verinfo.vertree == NULL)
+ {
+ struct bfd_elf_version_tree *t;
+
+ ++p;
+ if (*p == ELF_VER_CHR)
+ ++p;
+
+ if (*p != '\0'
+ && _bfd_elf_link_hide_versioned_symbol (info, h, p, &t, &hide)
+ && hide)
+ {
+ if (hide)
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ return TRUE;
+ }
+ }
+
+ /* If we don't have a version for this symbol, see if we can find
+ something. */
+ if (h->verinfo.vertree == NULL && info->version_info != NULL)
+ {
+ h->verinfo.vertree
+ = bfd_find_version_for_sym (info->version_info,
+ h->root.root.string, &hide);
+ if (h->verinfo.vertree != NULL && hide)
+ {
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
/* Figure out appropriate versions for all the symbols. We may not
have the version number script until we have read all of the input
files, so until that point we don't know which symbols should be
const struct elf_backend_data *bed;
struct elf_info_failed eif;
char *p;
+ bfd_boolean hide;
sinfo = (struct elf_info_failed *) data;
info = sinfo->info;
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;
+ }
- bed = get_elf_backend_data (info->output_bfd);
+ hide = FALSE;
p = strchr (h->root.root.string, ELF_VER_CHR);
if (p != NULL && h->verinfo.vertree == NULL)
{
if (*p == '\0')
return TRUE;
- /* Look for the version. If we find it, it is no longer weak. */
- for (t = sinfo->info->version_info; t != NULL; t = t->next)
+ if (!_bfd_elf_link_hide_versioned_symbol (info, h, p, &t, &hide))
{
- if (strcmp (t->name, p) == 0)
- {
- size_t len;
- char *alc;
- struct bfd_elf_version_expr *d;
-
- len = p - h->root.root.string;
- alc = (char *) bfd_malloc (len);
- if (alc == NULL)
- {
- sinfo->failed = TRUE;
- return FALSE;
- }
- memcpy (alc, h->root.root.string, len - 1);
- alc[len - 1] = '\0';
- if (alc[len - 2] == ELF_VER_CHR)
- alc[len - 2] = '\0';
-
- h->verinfo.vertree = t;
- t->used = TRUE;
- d = NULL;
-
- if (t->globals.list != NULL)
- d = (*t->match) (&t->globals, NULL, alc);
-
- /* See if there is anything to force this symbol to
- local scope. */
- if (d == NULL && t->locals.list != NULL)
- {
- d = (*t->match) (&t->locals, NULL, alc);
- if (d != NULL
- && h->dynindx != -1
- && ! info->export_dynamic)
- (*bed->elf_backend_hide_symbol) (info, h, TRUE);
- }
-
- free (alc);
- break;
- }
+ sinfo->failed = TRUE;
+ return FALSE;
}
+ if (hide)
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+
/* If we are building an application, we need to create a
version node for this version. */
if (t == NULL && bfd_link_executable (info))
/* If we don't have a version for this symbol, see if we can find
something. */
- if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL)
+ if (!hide
+ && h->verinfo.vertree == NULL
+ && sinfo->info->version_info != NULL)
{
- bfd_boolean hide;
-
h->verinfo.vertree
= bfd_find_version_for_sym (sinfo->info->version_info,
h->root.root.string, &hide);
}
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;
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%pB: bad reloc symbol index (%#Lx >= %#lx)"
- " for offset %#Lx in section `%pA'"),
- abfd, r_symndx, (unsigned long) nsyms,
- irela->r_offset, sec);
+ (_("%pB: bad reloc symbol index (%#" PRIx64 " >= %#lx)"
+ " for offset %#" PRIx64 " in section `%pA'"),
+ abfd, (uint64_t) r_symndx, (unsigned long) nsyms,
+ (uint64_t) irela->r_offset, sec);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%pB: non-zero symbol index (%#Lx)"
- " for offset %#Lx in section `%pA'"
+ (_("%pB: non-zero symbol index (%#" PRIx64 ")"
+ " for offset %#" PRIx64 " in section `%pA'"
" when the object file has no symbol table"),
- abfd, r_symndx,
- irela->r_offset, sec);
+ abfd, (uint64_t) r_symndx,
+ (uint64_t) irela->r_offset, sec);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
&& (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 the real definition is defined by a regular object file,
don't do anything special. See the longer description in
- _bfd_elf_adjust_dynamic_symbol, below. */
- if (def->def_regular)
+ _bfd_elf_adjust_dynamic_symbol, below. If the def is not
+ bfd_link_hash_defined as it was when put on the alias list
+ then it must have originally been a versioned symbol (for
+ which a non-versioned indirect symbol is created) and later
+ a definition for the non-versioned symbol is found. In that
+ case the indirection is flipped with the versioned symbol
+ becoming an indirect pointing at the non-versioned symbol.
+ Thus, not an alias any more. */
+ if (def->def_regular
+ || def->root.type != bfd_link_hash_defined)
{
h = def;
while ((h = h->u.alias) != def)
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak);
BFD_ASSERT (def->def_dynamic);
- BFD_ASSERT (def->root.type == bfd_link_hash_defined);
(*bed->elf_backend_copy_indirect_symbol) (eif->info, def, h);
}
}
|| (info->extern_protected_data < 0
&& !get_elf_backend_data (dynbss->owner)->extern_protected_data)))
info->callbacks->einfo
- (_("%P: copy reloc against protected `%T' is dangerous\n"),
+ (_("%P: copy reloc against protected `%pT' is dangerous\n"),
h->root.root.string);
return TRUE;
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;
&& ehdr->e_machine == bed->elf_machine_alt1)
|| (bed->elf_machine_alt2 != 0
&& ehdr->e_machine == bed->elf_machine_alt2)))
- info->callbacks->einfo
+ _bfd_error_handler
/* xgettext:c-format */
- (_("%P: alternate ELF machine code found (%d) in %pB, expecting %d\n"),
+ (_("alternate ELF machine code found (%d) in %pB, expecting %d"),
ehdr->e_machine, abfd, bed->elf_machine_code);
/* As a GNU extension, any input sections which are named
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
for (extdyn = dynbuf;
- extdyn < dynbuf + s->size;
+ extdyn <= dynbuf + s->size - bed->s->sizeof_dyn;
extdyn += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
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;
+ }
+
+ if (!bfd_link_relocatable (info)
+ && abfd->lto_slim_object)
+ {
+ _bfd_error_handler
+ (_("%pB: plugin needed to handle lto object"), abfd);
+ }
+
for (isym = isymbuf, isymend = isymbuf + extsymcount;
isym < isymend;
isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
bfd_boolean common;
bfd_boolean discarded;
unsigned int old_alignment;
+ unsigned int shindex;
bfd *old_bfd;
bfd_boolean matched;
global symbols follow all local symbols, and that sh_info
point to the first global symbol. Unfortunately, Irix 5
screws this up. */
- continue;
+ if (elf_bad_symtab (abfd))
+ continue;
+
+ /* If we aren't prepared to handle locals within the globals
+ then we'll likely segfault on a NULL symbol hash if the
+ symbol is ever referenced in relocations. */
+ shindex = elf_elfheader (abfd)->e_shstrndx;
+ name = bfd_elf_string_from_elf_section (abfd, shindex, hdr->sh_name);
+ _bfd_error_handler (_("%pB: %s local symbol at index %lu"
+ " (>= sh_info of %lu)"),
+ abfd, name, (long) (isym - isymbuf + extsymoff),
+ (long) extsymoff);
+
+ /* Dynamic object relocations are not processed by ld, so
+ ld won't run into the problem mentioned above. */
+ if (dynamic)
+ continue;
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
case STB_GLOBAL:
if (isym->st_shndx != SHN_UNDEF && !common)
/* Sanity check that all possibilities were handled. */
if (sec == NULL)
- {
- bfd_set_error (bfd_error_bad_value);
- goto error_free_vers;
- }
+ abort ();
/* Silently discard TLS symbols from --just-syms. There's
no way to combine a static TLS block with a new TLS block
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;
-
h = *sym_hash;
/* We need to make sure that indirect symbol dynamic flags are
updated. */
if (normal_bfd == NULL)
_bfd_error_handler
/* xgettext:c-format */
- (_("Warning: alignment %u of common symbol `%s' in %pB is"
+ (_("warning: alignment %u of common symbol `%s' in %pB is"
" greater than the alignment (%u) of its section %pA"),
1 << common_align, name, common_bfd,
1 << normal_align, h->root.u.def.section);
else
_bfd_error_handler
/* xgettext:c-format */
- (_("Warning: alignment %u of symbol `%s' in %pB"
+ (_("warning: alignment %u of symbol `%s' in %pB"
" is smaller than %u in %pB"),
1 << normal_align, name, normal_bfd,
1 << common_align, common_bfd);
&& ! size_change_ok)
_bfd_error_handler
/* xgettext:c-format */
- (_("Warning: size of symbol `%s' changed"
- " from %Lu in %pB to %Lu in %pB"),
- name, h->size, old_bfd, isym->st_size, abfd);
+ (_("warning: size of symbol `%s' changed"
+ " from %" PRIu64 " in %pB to %" PRIu64 " in %pB"),
+ name, (uint64_t) h->size, old_bfd,
+ (uint64_t) isym->st_size, abfd);
h->size = isym->st_size;
}
if (h->type != STT_NOTYPE && ! type_change_ok)
/* xgettext:c-format */
_bfd_error_handler
- (_("Warning: type of symbol `%s' changed"
+ (_("warning: type of symbol `%s' changed"
" from %d to %d in %pB"),
name, h->type, type, abfd);
unsigned long int *counts;
bfd_vma *bitmask;
bfd_byte *contents;
+ bfd_size_type xlat;
long int min_dynindx;
unsigned long int bucketcount;
unsigned long int symindx;
}
/* This function will be called though elf_link_hash_traverse to do
- final dynaminc symbol renumbering. */
+ final dynamic symbol renumbering in case of .gnu.hash.
+ If using .MIPS.xhash, invoke record_xhash_symbol to add symbol index
+ to the translation table. */
static bfd_boolean
-elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
+elf_gnu_hash_process_symidx (struct elf_link_hash_entry *h, void *data)
{
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
unsigned long int bucket;
if (! (*s->bed->elf_hash_symbol) (h))
{
if (h->dynindx >= s->min_dynindx)
- h->dynindx = s->local_indx++;
+ {
+ if (s->bed->record_xhash_symbol != NULL)
+ {
+ (*s->bed->record_xhash_symbol) (h, 0);
+ s->local_indx++;
+ }
+ else
+ h->dynindx = s->local_indx++;
+ }
return TRUE;
}
bfd_put_32 (s->output_bfd, val,
s->contents + (s->indx[bucket] - s->symindx) * 4);
--s->counts[bucket];
- h->dynindx = s->indx[bucket]++;
+ if (s->bed->record_xhash_symbol != NULL)
+ {
+ bfd_vma xlat_loc = s->xlat + (s->indx[bucket]++ - s->symindx) * 4;
+
+ (*s->bed->record_xhash_symbol) (h, xlat_loc);
+ }
+ else
+ h->dynindx = s->indx[bucket]++;
return TRUE;
}
if ((info->emit_hash
&& !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0))
|| (info->emit_gnu_hash
- && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0))
+ && (bed->record_xhash_symbol == NULL
+ && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0)))
|| !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
_bfd_elf_init_1_index_section (bfd *output_bfd, struct bfd_link_info *info)
{
asection *s;
+ asection *found = NULL;
for (s = output_bfd->sections; s != NULL; s = s->next)
if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC
&& !_bfd_elf_omit_section_dynsym_default (output_bfd, info, s))
{
- elf_hash_table (info)->text_index_section = s;
- break;
+ found = s;
+ if ((s->flags & SEC_THREAD_LOCAL) == 0)
+ break;
}
+ elf_hash_table (info)->text_index_section = found;
}
/* Find two non-excluded output sections, one for code, one for data.
_bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info)
{
asection *s;
+ asection *found = NULL;
/* 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)
+ if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC
+ && !(s->flags & SEC_READONLY)
&& !_bfd_elf_omit_section_dynsym_default (output_bfd, info, s))
{
- elf_hash_table (info)->data_index_section = s;
- break;
+ found = s;
+ if ((s->flags & SEC_THREAD_LOCAL) == 0)
+ break;
}
+ elf_hash_table (info)->data_index_section = found;
for (s = output_bfd->sections; s != NULL; s = s->next)
- if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
- == (SEC_ALLOC | SEC_READONLY))
+ if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC
+ && (s->flags & SEC_READONLY)
&& !_bfd_elf_omit_section_dynsym_default (output_bfd, info, s))
{
- elf_hash_table (info)->text_index_section = s;
+ found = s;
break;
}
-
- if (elf_hash_table (info)->text_index_section == NULL)
- elf_hash_table (info)->text_index_section
- = elf_hash_table (info)->data_index_section;
+ elf_hash_table (info)->text_index_section = found;
}
+#define GNU_HASH_SECTION_NAME(bed) \
+ (bed)->record_xhash_symbol != NULL ? ".MIPS.xhash" : ".gnu.hash"
+
bfd_boolean
bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
{
return FALSE;
}
- s = bfd_get_linker_section (dynobj, ".gnu.hash");
+ s = bfd_get_linker_section (dynobj, GNU_HASH_SECTION_NAME (bed));
BFD_ASSERT (s != NULL);
if (cinfo.nsyms == 0)
{
- /* Empty .gnu.hash section is special. */
+ /* Empty .gnu.hash or .MIPS.xhash section is special. */
BFD_ASSERT (cinfo.min_dynindx == -1);
free (cinfo.hashcodes);
s->size = 5 * 4 + bed->s->arch_size / 8;
s->size = (4 + bucketcount + cinfo.nsyms) * 4;
s->size += cinfo.maskbits / 8;
+ if (bed->record_xhash_symbol != NULL)
+ s->size += cinfo.nsyms * 4;
contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
if (contents == NULL)
{
cinfo.contents = contents;
- /* Renumber dynamic symbols, populate .gnu.hash section. */
+ cinfo.xlat = contents + cinfo.nsyms * 4 - s->contents;
+ /* Renumber dynamic symbols, if populating .gnu.hash section.
+ If using .MIPS.xhash, populate the translation table. */
elf_link_hash_traverse (elf_hash_table (info),
- elf_renumber_gnu_hash_syms, &cinfo);
+ elf_gnu_hash_process_symidx, &cinfo);
contents = s->contents + 16;
for (i = 0; i < maskwords; ++i)
}
}
+/* Hide a symbol. */
+
+void
+_bfd_elf_link_hide_symbol (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h)
+{
+ if (is_elf_hash_table (info->hash))
+ {
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (output_bfd);
+ struct elf_link_hash_entry *eh
+ = (struct elf_link_hash_entry *) h;
+ bed->elf_backend_hide_symbol (info, eh, TRUE);
+ eh->def_dynamic = 0;
+ eh->ref_dynamic = 0;
+ eh->dynamic_def = 0;
+ }
+}
+
/* Initialize an ELF linker hash table. *TABLE has been zeroed by our
caller. */
&& ! info->gc_keep_exported)
{
/* PR 21524: Let the user know if a symbol was removed by garbage collection. */
- _bfd_error_handler (_("%pB:%pA: error: relocation references symbol %s which was removed by garbage collection."),
+ _bfd_error_handler (_("%pB:%pA: error: relocation references symbol %s which was removed by garbage collection"),
abfd, sec,
(*rel_hash)->root.root.string);
- _bfd_error_handler (_("%pB:%pA: error: try relinking with --gc-keep-exported enabled."),
+ _bfd_error_handler (_("%pB:%pA: error: try relinking with --gc-keep-exported enabled"),
abfd, sec);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
/* Section size is only divisible by rela. */
if (use_rela_initialised && !use_rela)
{
- _bfd_error_handler (_("%pB: Unable to sort relocs - "
+ _bfd_error_handler (_("%pB: unable to sort relocs - "
"they are in more than one size"),
abfd);
bfd_set_error (bfd_error_invalid_operation);
/* Section size is only divisible by rel. */
if (use_rela_initialised && use_rela)
{
- _bfd_error_handler (_("%pB: Unable to sort relocs - "
+ _bfd_error_handler (_("%pB: unable to sort relocs - "
"they are in more than one size"),
abfd);
bfd_set_error (bfd_error_invalid_operation);
{
/* The section size is not divisible by either -
something is wrong. */
- _bfd_error_handler (_("%pB: Unable to sort relocs - "
+ _bfd_error_handler (_("%pB: unable to sort relocs - "
"they are of an unknown size"), abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
/* Section size is only divisible by rela. */
if (use_rela_initialised && !use_rela)
{
- _bfd_error_handler (_("%pB: Unable to sort relocs - "
+ _bfd_error_handler (_("%pB: unable to sort relocs - "
"they are in more than one size"),
abfd);
bfd_set_error (bfd_error_invalid_operation);
/* Section size is only divisible by rel. */
if (use_rela_initialised && use_rela)
{
- _bfd_error_handler (_("%pB: Unable to sort relocs - "
+ _bfd_error_handler (_("%pB: unable to sort relocs - "
"they are in more than one size"),
abfd);
bfd_set_error (bfd_error_invalid_operation);
{
/* The section size is not divisible by either -
something is wrong. */
- _bfd_error_handler (_("%pB: Unable to sort relocs - "
+ _bfd_error_handler (_("%pB: unable to sort relocs - "
"they are of an unknown size"), abfd);
bfd_set_error (bfd_error_invalid_operation);
return 0;
if (sort == NULL)
{
(*info->callbacks->warning)
- (info, _("Not enough memory to sort relocations"), 0, abfd, 0, 0);
+ (info, _("not enough memory to sort relocations"), 0, abfd, 0, 0);
return 0;
}
return ret;
}
+ if (ELF_ST_TYPE (elfsym->st_info) == STT_GNU_IFUNC)
+ elf_tdata (flinfo->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_ifunc;
+ if (ELF_ST_BIND (elfsym->st_info) == STB_GNU_UNIQUE)
+ elf_tdata (flinfo->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_unique;
+
if (name == NULL
|| *name == '\0'
|| (input_sec->flags & SEC_EXCLUDE))
beyond 64k. */
_bfd_error_handler
/* xgettext:c-format */
- (_("%pB: Too many sections: %d (>= %d)"),
+ (_("%pB: too many sections: %d (>= %d)"),
abfd, bfd_count_sections (abfd), SHN_LORESERVE & 0xffff);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
/* If we are reporting errors for this situation then do so now. */
if (!ignore_undef
- && h->ref_dynamic
+ && h->ref_dynamic_nonweak
&& (!h->ref_regular || flinfo->info->gc_sections)
&& !elf_link_check_versioned_symbol (flinfo->info, bed, h)
&& flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
/* 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;
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%pB: No symbol version section for versioned symbol `%s'"),
+ (_("%pB: no symbol version section for versioned symbol `%s'"),
flinfo->output_bfd, h->root.root.string);
eoinfo->failed = TRUE;
return FALSE;
{
/* Don't attempt to output symbols with st_shnx in the
reserved range other than SHN_ABS and SHN_COMMON. */
- *ppsection = NULL;
- continue;
+ isec = bfd_und_section_ptr;
}
else if (isec->sec_info_type == SEC_INFO_TYPE_MERGE
&& ELF_ST_TYPE (isym->st_info) != STT_SECTION)
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);
}
}
{
_bfd_error_handler
/* xgettext:c-format */
- (_("error: %pB contains a reloc (%#Lx) for section %pA "
+ (_("error: %pB contains a reloc (%#" PRIx64 ") for section %pA "
"that references a non-existent global symbol"),
- input_bfd, rel->r_info, o);
+ input_bfd, (uint64_t) rel->r_info, o);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
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);
}
}
free (flinfo->indices);
if (flinfo->sections != NULL)
free (flinfo->sections);
- if (flinfo->symshndxbuf != NULL)
+ if (flinfo->symshndxbuf != NULL
+ && flinfo->symshndxbuf != (Elf_External_Sym_Shndx *) -1)
free (flinfo->symshndxbuf);
for (o = obfd->sections; o != NULL; o = o->next)
{
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--;
{
if (info->error_textrel)
info->callbacks->einfo
- (_("%P%X: read-only segment has dynamic relocations.\n"));
+ (_("%P%X: read-only segment has dynamic relocations\n"));
else
info->callbacks->einfo
- (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
+ (_("%P: warning: creating a DT_TEXTREL in a shared object\n"));
break;
}
}
elf_final_link_free (abfd, &flinfo);
- elf_linker (abfd) = TRUE;
-
if (attr_section)
{
bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size);
return NULL;
}
-/* Return the global debug definition section. */
+/* Return the debug definition section. */
static asection *
elf_gc_mark_debug_section (asection *sec ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED,
Elf_Internal_Rela *rel ATTRIBUTE_UNUSED,
struct elf_link_hash_entry *h,
- Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
+ Elf_Internal_Sym *sym)
{
- if (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && (h->root.u.def.section->flags & SEC_DEBUGGING) != 0)
- return h->root.u.def.section;
+ if (h != NULL)
+ {
+ /* Return the global debug definition section. */
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && (h->root.u.def.section->flags & SEC_DEBUGGING) != 0)
+ return h->root.u.def.section;
+ }
+ else
+ {
+ /* Return the local debug definition section. */
+ asection *isec = bfd_section_from_elf_index (sec->owner,
+ sym->st_shndx);
+ if ((isec->flags & SEC_DEBUGGING) != 0)
+ return isec;
+ }
return NULL;
}
if (info->print_gc_sections && o->size != 0)
/* xgettext:c-format */
- _bfd_error_handler (_("Removing unused section '%pA' in file '%pB'"),
+ _bfd_error_handler (_("removing unused section '%pA' in file '%pB'"),
o, sub);
}
}
if (!bed->can_gc_sections
|| !is_elf_hash_table (info->hash))
{
- _bfd_error_handler(_("Warning: gc-sections option ignored"));
+ _bfd_error_handler(_("warning: gc-sections option ignored"));
return TRUE;
}
}
/* xgettext:c-format */
- _bfd_error_handler (_("%pB: %pA+%#Lx: No symbol found for INHERIT"),
- abfd, sec, offset);
+ _bfd_error_handler (_("%pB: %pA+%#" PRIx64 ": no symbol found for INHERIT"),
+ abfd, sec, (uint64_t) offset);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
/* Called from check_relocs to record the existence of a VTENTRY reloc. */
bfd_boolean
-bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec ATTRIBUTE_UNUSED,
+bfd_elf_gc_record_vtentry (bfd *abfd, asection *sec,
struct elf_link_hash_entry *h,
bfd_vma addend)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
unsigned int log_file_align = bed->s->log_file_align;
+ if (!h)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: section '%pA': corrupt VTENTRY entry"),
+ abfd, sec);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
if (!h->u2.vtable)
{
h->u2.vtable = ((struct elf_link_virtual_table_entry *)
if (!tf->valid)
{
info->callbacks->einfo
- (_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name);
+ (_("unrecognized INPUT_SECTION_FLAG %s\n"), tf->name);
return FALSE;
}
}