/* ELF linking support for BFD.
- Copyright (C) 1995-2020 Free Software Foundation, Inc.
+ Copyright (C) 1995-2021 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "plugin.h"
#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
/* This struct is used to pass information to routines called via
elf_link_hash_traverse which must return failure. */
const char *name;
size_t indx;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ /* An IR symbol should not be made dynamic. */
+ if (h->root.u.def.section != NULL
+ && h->root.u.def.section->owner != NULL
+ && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)
+ return TRUE;
+ }
+
/* XXX: The ABI draft says the linker must turn hidden and
internal symbols into STB_LOCAL symbols when producing the
DSO. However, if ld.so honors st_other in the dynamic table,
static void
elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
- const Elf_Internal_Sym *isym, asection *sec,
+ unsigned int st_other, asection *sec,
bfd_boolean definition, bfd_boolean dynamic)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
/* If st_other has a processor-specific meaning, specific
code might be needed here. */
if (bed->elf_backend_merge_symbol_attribute)
- (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
+ (*bed->elf_backend_merge_symbol_attribute) (h, st_other, definition,
dynamic);
if (!dynamic)
{
- unsigned symvis = ELF_ST_VISIBILITY (isym->st_other);
+ unsigned symvis = ELF_ST_VISIBILITY (st_other);
unsigned hvis = ELF_ST_VISIBILITY (h->other);
/* Keep the most constraining visibility. Leave the remainder
h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1));
}
else if (definition
- && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT
+ && ELF_ST_VISIBILITY (st_other) != STV_DEFAULT
&& (sec->flags & SEC_READONLY) == 0)
h->protected_def = 1;
}
bfd_boolean *pold_weak,
unsigned int *pold_alignment,
bfd_boolean *skip,
- bfd_boolean *override,
+ bfd **override,
bfd_boolean *type_change_ok,
bfd_boolean *size_change_ok,
bfd_boolean *matched)
bfd_boolean default_sym = *matched;
*skip = FALSE;
- *override = FALSE;
+ *override = NULL;
sec = *psec;
bind = ELF_ST_BIND (sym->st_info);
|| (h->root.type == bfd_link_hash_common
&& (newweak || newfunc))))
{
- *override = TRUE;
+ *override = abfd;
newdef = FALSE;
newdyncommon = FALSE;
if (newdyncommon
&& h->root.type == bfd_link_hash_common)
{
- *override = TRUE;
+ *override = oldbfd;
newdef = FALSE;
newdyncommon = FALSE;
*pvalue = sym->st_size;
/* Merge st_other. If the symbol already has a dynamic index,
but visibility says it should not be visible, turn it into a
local symbol. */
- elf_merge_st_other (abfd, h, sym, sec, newdef, newdyn);
+ elf_merge_st_other (abfd, h, sym->st_other, sec, newdef, newdyn);
if (h->dynindx != -1)
switch (ELF_ST_VISIBILITY (h->other))
{
const struct elf_backend_data *bed;
bfd_boolean collect;
bfd_boolean dynamic;
- bfd_boolean override;
+ bfd *override;
char *p;
size_t len, shortlen;
asection *tmp_sec;
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
(*bed->elf_backend_copy_indirect_symbol) (info, ht, hi);
+ /* If we first saw a reference to SHORTNAME with non-default
+ visibility, merge that visibility to the @@VER symbol. */
+ elf_merge_st_other (abfd, ht, hi->other, sec, TRUE, dynamic);
+
/* A reference to the SHORTNAME symbol from a dynamic library
will be satisfied by the versioned symbol at runtime. In
effect, we have a reference to the versioned symbol. */
return FALSE;
if (skip)
- return TRUE;
-
- if (override)
+ {
+ if (!dynamic
+ && h->root.type == bfd_link_hash_defweak
+ && hi->root.type == bfd_link_hash_defined)
+ {
+ /* We are handling a weak sym@@ver and attempting to define
+ a weak sym@ver, but _bfd_elf_merge_symbol said to skip the
+ new weak sym@ver because there is already a strong sym@ver.
+ However, sym@ver and sym@@ver are really the same symbol.
+ The existing strong sym@ver ought to override sym@@ver. */
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = hi->root.u.def.section;
+ h->root.u.def.value = hi->root.u.def.value;
+ hi->root.type = bfd_link_hash_indirect;
+ hi->root.u.i.link = &h->root;
+ }
+ else
+ return TRUE;
+ }
+ else if (override)
{
/* Here SHORTNAME is a versioned name, so we don't expect to see
the type of override we do in the case above unless it is
/* xgettext:c-format */
(_("%pB: unexpected redefinition of indirect versioned symbol `%s'"),
abfd, shortname);
+ return TRUE;
}
else
{
bfd_ind_section_ptr, 0, name, FALSE, collect, &bh)))
return FALSE;
hi = (struct elf_link_hash_entry *) bh;
+ }
- /* If there is a duplicate definition somewhere, then HI may not
- point to an indirect symbol. We will have reported an error
- to the user in that case. */
+ /* If there is a duplicate definition somewhere, then HI may not
+ point to an indirect symbol. We will have reported an error
+ to the user in that case. */
+ if (hi->root.type == bfd_link_hash_indirect)
+ {
+ (*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
+ h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
+ hi->dynamic_def |= h->dynamic_def;
- if (hi->root.type == bfd_link_hash_indirect)
- {
- (*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
- h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
- hi->dynamic_def |= h->dynamic_def;
+ /* If we first saw a reference to @VER symbol with
+ non-default visibility, merge that visibility to the
+ @@VER symbol. */
+ elf_merge_st_other (abfd, h, hi->other, sec, TRUE, dynamic);
- /* See if the new flags lead us to realize that the symbol
- must be dynamic. */
- if (! *dynsym)
+ /* See if the new flags lead us to realize that the symbol
+ must be dynamic. */
+ if (! *dynsym)
+ {
+ if (! dynamic)
{
- if (! dynamic)
- {
- if (! bfd_link_executable (info)
- || hi->ref_dynamic)
- *dynsym = TRUE;
- }
- else
- {
- if (hi->ref_regular)
- *dynsym = TRUE;
- }
+ if (! bfd_link_executable (info)
+ || hi->ref_dynamic)
+ *dynsym = TRUE;
+ }
+ else
+ {
+ if (hi->ref_regular)
+ *dynsym = TRUE;
}
}
}
_bfd_elf_strtab_finalize (dynstr);
size = _bfd_elf_strtab_size (dynstr);
+ /* Allow the linker to examine the dynsymtab now it's fully populated. */
+
+ if (info->callbacks->examine_strtab)
+ info->callbacks->examine_strtab (dynstr);
+
bed = get_elf_backend_data (dynobj);
sdyn = bfd_get_linker_section (dynobj, ".dynamic");
BFD_ASSERT (sdyn != NULL);
h = (struct elf_link_hash_entry *) p;
entsize += htab->root.table.entsize;
if (h->root.type == bfd_link_hash_warning)
- entsize += htab->root.table.entsize;
+ {
+ entsize += htab->root.table.entsize;
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+ if (h->root.type == bfd_link_hash_common)
+ entsize += sizeof (*h->root.u.c.p);
}
}
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
- memcpy (old_ent, p, htab->root.table.entsize);
- old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) p;
+ memcpy (old_ent, h, htab->root.table.entsize);
+ old_ent = (char *) old_ent + htab->root.table.entsize;
if (h->root.type == bfd_link_hash_warning)
{
- memcpy (old_ent, h->root.u.i.link, htab->root.table.entsize);
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ memcpy (old_ent, h, htab->root.table.entsize);
old_ent = (char *) old_ent + htab->root.table.entsize;
}
+ if (h->root.type == bfd_link_hash_common)
+ {
+ memcpy (old_ent, h->root.u.c.p, sizeof (*h->root.u.c.p));
+ old_ent = (char *) old_ent + sizeof (*h->root.u.c.p);
+ }
}
}
}
bfd_boolean type_change_ok;
bfd_boolean new_weak;
bfd_boolean old_weak;
- bfd_boolean override;
+ bfd *override;
bfd_boolean common;
bfd_boolean discarded;
unsigned int old_alignment;
bfd *old_bfd;
bfd_boolean matched;
- override = FALSE;
+ override = NULL;
flags = BSF_NO_FLAGS;
sec = NULL;
}
if (! (_bfd_generic_link_add_one_symbol
- (info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect,
+ (info, override ? override : abfd, name, flags, sec, value,
+ NULL, FALSE, bed->collect,
(struct bfd_link_hash_entry **) sym_hash)))
goto error_free_vers;
object and a shared object. */
bfd_boolean dynsym = FALSE;
- /* Plugin symbols aren't normal. Don't set def_regular or
- ref_regular for them, or make them dynamic. */
+ /* Plugin symbols aren't normal. Don't set def/ref flags. */
if ((abfd->flags & BFD_PLUGIN) != 0)
;
- else if (! dynamic)
+ else if (!dynamic)
{
if (! definition)
{
h->ref_dynamic = 1;
}
}
-
- /* If the indirect symbol has been forced local, don't
- make the real symbol dynamic. */
- if ((h == hi || !hi->forced_local)
- && (bfd_link_dll (info)
- || h->def_dynamic
- || h->ref_dynamic))
- dynsym = TRUE;
}
else
{
h->def_dynamic = 1;
hi->def_dynamic = 1;
}
+ }
- /* If the indirect symbol has been forced local, don't
- make the real symbol dynamic. */
- if ((h == hi || !hi->forced_local)
- && (h->def_regular
- || h->ref_regular
- || (h->is_weakalias
- && weakdef (h)->dynindx != -1)))
+ /* If an indirect symbol has been forced local, don't
+ make the real symbol dynamic. */
+ if (h != hi && hi->forced_local)
+ ;
+ else if (!dynamic)
+ {
+ if (bfd_link_dll (info)
+ || h->def_dynamic
+ || h->ref_dynamic)
+ dynsym = TRUE;
+ }
+ else
+ {
+ if (h->def_regular
+ || h->ref_regular
+ || (h->is_weakalias
+ && weakdef (h)->dynindx != -1))
dynsym = TRUE;
}
/* Check to see if we need to add an indirect symbol for
the default name. */
- if (definition
- || (!override && h->root.type == bfd_link_hash_common))
+ if ((definition
+ || (!override && h->root.type == bfd_link_hash_common))
+ && !(hi != h
+ && hi->versioned == versioned_hidden))
if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
sec, value, &old_bfd, &dynsym))
goto error_free_vers;
}
/* Merge st_other field. */
- elf_merge_st_other (abfd, h, isym, sec, definition, dynamic);
+ elf_merge_st_other (abfd, h, isym->st_other, sec,
+ definition, dynamic);
/* We don't want to make debug symbol dynamic. */
if (definition
break;
}
- /* Don't add DT_NEEDED for references from the dummy bfd nor
- for unmatched symbol. */
if (!add_needed
&& matched
&& definition
&& ((dynsym
- && h->ref_regular_nonweak
- && (old_bfd == NULL
- || (old_bfd->flags & BFD_PLUGIN) == 0))
+ && h->ref_regular_nonweak)
+ || (old_bfd != NULL
+ && (old_bfd->flags & BFD_PLUGIN) != 0
+ && bind != STB_WEAK)
|| (h->ref_dynamic_nonweak
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
&& !on_needed_list (elf_dt_name (abfd),
{
struct bfd_hash_entry *p;
struct elf_link_hash_entry *h;
- bfd_size_type size;
- unsigned int alignment_power;
unsigned int non_ir_ref_dynamic;
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
- h = (struct elf_link_hash_entry *) p;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- /* Preserve the maximum alignment and size for common
- symbols even if this dynamic lib isn't on DT_NEEDED
- since it can still be loaded at run time by another
- dynamic lib. */
- if (h->root.type == bfd_link_hash_common)
- {
- size = h->root.u.c.size;
- alignment_power = h->root.u.c.p->alignment_power;
- }
- else
- {
- size = 0;
- alignment_power = 0;
- }
/* Preserve non_ir_ref_dynamic so that this symbol
will be exported when the dynamic lib becomes needed
in the second pass. */
+ h = (struct elf_link_hash_entry *) p;
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
non_ir_ref_dynamic = h->root.non_ir_ref_dynamic;
- memcpy (p, old_ent, htab->root.table.entsize);
- old_ent = (char *) old_ent + htab->root.table.entsize;
+
h = (struct elf_link_hash_entry *) p;
+ memcpy (h, old_ent, htab->root.table.entsize);
+ old_ent = (char *) old_ent + htab->root.table.entsize;
if (h->root.type == bfd_link_hash_warning)
{
- memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
- old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ memcpy (h, old_ent, htab->root.table.entsize);
+ old_ent = (char *) old_ent + htab->root.table.entsize;
}
if (h->root.type == bfd_link_hash_common)
{
- if (size > h->root.u.c.size)
- h->root.u.c.size = size;
- if (alignment_power > h->root.u.c.p->alignment_power)
- h->root.u.c.p->alignment_power = alignment_power;
+ memcpy (h->root.u.c.p, old_ent, sizeof (*h->root.u.c.p));
+ old_ent = (char *) old_ent + sizeof (*h->root.u.c.p);
}
h->root.non_ir_ref_dynamic = non_ir_ref_dynamic;
}
if (h == NULL)
continue;
- if (h->root.type == bfd_link_hash_common)
+ if (h->root.type == bfd_link_hash_undefined)
+ {
+ /* If the archive element has already been loaded then one
+ of the symbols defined by that element might have been
+ made undefined due to being in a discarded section. */
+ if (h->indx == -3)
+ continue;
+ }
+ else if (h->root.type == bfd_link_hash_common)
{
/* We currently have a common symbol. The archive map contains
a reference to this symbol, so we may want to include it. We
if (! elf_link_is_defined_archive_symbol (abfd, symdef))
continue;
}
- else if (h->root.type != bfd_link_hash_undefined)
+ else
{
if (h->root.type != bfd_link_hash_undefweak)
/* Symbol must be defined. Don't check it again. */
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMENT,
- bed->s->sizeof_sym))
+ bed->s->sizeof_sym)
+ || (info->gnu_flags_1
+ && !_bfd_elf_add_dynamic_entry (info, DT_GNU_FLAGS_1,
+ info->gnu_flags_1)))
return FALSE;
}
}
if (isymbuf1 == NULL)
goto done;
- if (!info->reduce_memory_overheads)
+ if (info != NULL && !info->reduce_memory_overheads)
{
ssymbuf1 = elf_create_symbuf (symcount1, isymbuf1);
elf_tdata (bfd1)->symbuf = ssymbuf1;
if (isymbuf2 == NULL)
goto done;
- if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
+ if (ssymbuf1 != NULL && info != NULL && !info->reduce_memory_overheads)
{
ssymbuf2 = elf_create_symbuf (symcount2, isymbuf2);
elf_tdata (bfd2)->symbuf = ssymbuf2;
Elf_External_Sym_Shndx *symshndxbuf;
/* Number of STT_FILE syms seen. */
size_t filesym_count;
+ /* Local symbol hash table. */
+ struct bfd_hash_table local_hash_table;
+};
+
+struct local_hash_entry
+{
+ /* Base hash table entry structure. */
+ struct bfd_hash_entry root;
+ /* Size of the local symbol name. */
+ size_t size;
+ /* Number of the duplicated local symbol names. */
+ long count;
};
+/* Create an entry in the local symbol hash table. */
+
+static struct bfd_hash_entry *
+local_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (entry == NULL)
+ {
+ entry = bfd_hash_allocate (table,
+ sizeof (struct local_hash_entry));
+ if (entry == NULL)
+ return entry;
+ }
+
+ /* Call the allocation method of the superclass. */
+ entry = bfd_hash_newfunc (entry, table, string);
+ if (entry != NULL)
+ {
+ ((struct local_hash_entry *) entry)->count = 0;
+ ((struct local_hash_entry *) entry)->size = 0;
+ }
+
+ return entry;
+}
+
/* This struct is used to pass information to elf_link_output_extsym. */
struct elf_outext_info
implementation of them consists of two parts: complex symbols, and the
relocations themselves.
- The relocations are use a reserved elf-wide relocation type code (R_RELC
+ The relocations use a reserved elf-wide relocation type code (R_RELC
external / BFD_RELOC_RELC internal) and an encoding of relocation field
information (start bit, end bit, word width, etc) into the addend. This
information is extracted from CGEN-generated operand tables within gas.
- Complex symbols are mangled symbols (BSF_RELC external / STT_RELC
+ Complex symbols are mangled symbols (STT_RELC external / BSF_RELC
internal) representing prefix-notation expressions, including but not
limited to those sorts of expressions normally encoded as addends in the
addend field. The symbol mangling format is:
/* xgettext:c-format */
_bfd_error_handler (_("undefined %s reference in complex symbol: %s"),
reftype, name);
+ bfd_set_error (bfd_error_bad_value);
}
static bfd_boolean
return TRUE; \
}
-#define BINARY_OP(op) \
+#define BINARY_OP_HEAD(op) \
if (strncmp (sym, #op, strlen (#op)) == 0) \
{ \
sym += strlen (#op); \
++*symp; \
if (!eval_symbol (&b, symp, input_bfd, flinfo, dot, \
isymbuf, locsymcount, signed_p)) \
- return FALSE; \
+ return FALSE;
+#define BINARY_OP_TAIL(op) \
if (signed_p) \
*result = ((bfd_signed_vma) a) op ((bfd_signed_vma) b); \
else \
*result = a op b; \
return TRUE; \
}
+#define BINARY_OP(op) BINARY_OP_HEAD(op) BINARY_OP_TAIL(op)
default:
UNARY_OP (0-);
- BINARY_OP (<<);
- BINARY_OP (>>);
+ BINARY_OP_HEAD (<<);
+ if (b >= sizeof (a) * CHAR_BIT)
+ {
+ *result = 0;
+ return TRUE;
+ }
+ signed_p = 0;
+ BINARY_OP_TAIL (<<);
+ BINARY_OP_HEAD (>>);
+ if (b >= sizeof (a) * CHAR_BIT)
+ {
+ *result = signed_p && (bfd_signed_vma) a < 0 ? -1 : 0;
+ return TRUE;
+ }
+ BINARY_OP_TAIL (>>);
BINARY_OP (==);
BINARY_OP (!=);
BINARY_OP (<=);
UNARY_OP (~);
UNARY_OP (!);
BINARY_OP (*);
- BINARY_OP (/);
- BINARY_OP (%);
+ BINARY_OP_HEAD (/);
+ if (b == 0)
+ {
+ _bfd_error_handler (_("division by zero"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ BINARY_OP_TAIL (/);
+ BINARY_OP_HEAD (%);
+ if (b == 0)
+ {
+ _bfd_error_handler (_("division by zero"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ BINARY_OP_TAIL (%);
BINARY_OP (^);
BINARY_OP (|);
BINARY_OP (&);
{
/* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
to get the final offset for st_name. */
+ char *versioned_name = (char *) name;
+ if (h != NULL)
+ {
+ if (h->versioned == versioned && h->def_dynamic)
+ {
+ /* Keep only one '@' for versioned symbols defined in
+ shared objects. */
+ char *version = strrchr (name, ELF_VER_CHR);
+ char *base_end = strchr (name, ELF_VER_CHR);
+ if (version != base_end)
+ {
+ size_t base_len;
+ size_t len = strlen (name);
+ versioned_name = bfd_alloc (flinfo->output_bfd, len);
+ if (versioned_name == NULL)
+ return 0;
+ base_len = base_end - name;
+ memcpy (versioned_name, name, base_len);
+ memcpy (versioned_name + base_len, version,
+ len - base_len);
+ }
+ }
+ }
+ else if (flinfo->info->unique_symbol
+ && ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
+ {
+ struct local_hash_entry *lh;
+ switch (ELF_ST_TYPE (elfsym->st_info))
+ {
+ case STT_FILE:
+ case STT_SECTION:
+ break;
+ default:
+ lh = (struct local_hash_entry *) bfd_hash_lookup
+ (&flinfo->local_hash_table, name, TRUE, FALSE);
+ if (lh == NULL)
+ return 0;
+ if (lh->count)
+ {
+ /* Append ".COUNT" to duplicated local symbols. */
+ size_t count_len;
+ size_t base_len = lh->size;
+ char buf[30];
+ sprintf (buf, "%lx", lh->count);
+ if (!base_len)
+ {
+ base_len = strlen (name);
+ lh->size = base_len;
+ }
+ count_len = strlen (buf);
+ versioned_name = bfd_alloc (flinfo->output_bfd,
+ base_len + count_len + 2);
+ if (versioned_name == NULL)
+ return 0;
+ memcpy (versioned_name, name, base_len);
+ versioned_name[base_len] = '.';
+ memcpy (versioned_name + base_len + 1, buf,
+ count_len + 1);
+ }
+ lh->count++;
+ break;
+ }
+ }
elfsym->st_name
= (unsigned long) _bfd_elf_strtab_add (flinfo->symstrtab,
- name, FALSE);
+ versioned_name, FALSE);
if (elfsym->st_name == (unsigned long) -1)
return 0;
}
}
}
+ /* Now swap out the symbols. */
for (i = 0; i < hash_table->strtabcount; i++)
{
struct elf_sym_strtab *elfsym = &hash_table->strtab[i];
elfsym->sym.st_name
= (unsigned long) _bfd_elf_strtab_offset (flinfo->symstrtab,
elfsym->sym.st_name);
+
+ /* Inform the linker of the addition of this symbol. */
+
+ if (flinfo->info->callbacks->ctf_new_symbol)
+ flinfo->info->callbacks->ctf_new_symbol (elfsym->dest_index,
+ &elfsym->sym);
+
bed->s->swap_symbol_out (flinfo->output_bfd, &elfsym->sym,
((bfd_byte *) symbuf
+ (elfsym->dest_index
+ elfsym->destshndx_index));
}
- /* Allow the linker to examine the strtab and symtab now they are
- populated. */
-
- if (flinfo->info->callbacks->examine_strtab)
- flinfo->info->callbacks->examine_strtab (hash_table->strtab,
- hash_table->strtabcount,
- flinfo->symstrtab);
-
hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
pos = hdr->sh_offset + hdr->sh_size;
amt = hash_table->strtabcount * bed->s->sizeof_sym;
eoinfo->failed = TRUE;
return FALSE;
}
+
+ /* Inform the linker of the addition of this symbol. */
+
+ if (flinfo->info->callbacks->ctf_new_dynsym)
+ flinfo->info->callbacks->ctf_new_dynsym (h->dynindx, &sym);
+
bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0);
if (flinfo->hash_sec != NULL)
{
if ((kept->flags & SEC_GROUP) != 0)
kept = match_group_member (sec, kept, info);
- if (kept != NULL
- && ((sec->rawsize != 0 ? sec->rawsize : sec->size)
- != (kept->rawsize != 0 ? kept->rawsize : kept->size)))
- kept = NULL;
+ if (kept != NULL)
+ {
+ if ((sec->rawsize != 0 ? sec->rawsize : sec->size)
+ != (kept->rawsize != 0 ? kept->rawsize : kept->size))
+ kept = NULL;
+ else
+ {
+ /* Get the real kept section. */
+ asection *next;
+ for (next = kept->kept_section;
+ next != NULL;
+ next = next->kept_section)
+ kept = next;
+ }
+ }
sec->kept_section = kept;
}
return kept;
extsymoff = symtab_hdr->sh_info;
}
+ /* Enable GNU OSABI features in the output BFD that are used in the input
+ BFD. */
+ if (bed->elf_osabi == ELFOSABI_NONE
+ || bed->elf_osabi == ELFOSABI_GNU
+ || bed->elf_osabi == ELFOSABI_FREEBSD)
+ elf_tdata (output_bfd)->has_gnu_osabi
+ |= (elf_tdata (input_bfd)->has_gnu_osabi
+ & (bfd_link_relocatable (flinfo->info)
+ ? -1 : ~elf_gnu_osabi_retain));
+
/* Read the local symbols. */
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL && locsymcount != 0)
const char *std_attrs_section;
struct elf_link_hash_table *htab = elf_hash_table (info);
bfd_boolean sections_removed;
+ bfd_boolean ret;
if (!is_elf_hash_table (htab))
return FALSE;
emit_relocs = (bfd_link_relocatable (info)
|| info->emitrelocations);
+ memset (&flinfo, 0, sizeof (flinfo));
flinfo.info = info;
flinfo.output_bfd = abfd;
flinfo.symstrtab = _bfd_elf_strtab_init ();
/* Note that it is OK if symver_sec is NULL. */
}
- flinfo.contents = NULL;
- flinfo.external_relocs = NULL;
- flinfo.internal_relocs = NULL;
- flinfo.external_syms = NULL;
- flinfo.locsym_shndx = NULL;
- flinfo.internal_syms = NULL;
- flinfo.indices = NULL;
- flinfo.sections = NULL;
- flinfo.symshndxbuf = NULL;
- flinfo.filesym_count = 0;
+ if (info->unique_symbol
+ && !bfd_hash_table_init (&flinfo.local_hash_table,
+ local_hash_newfunc,
+ sizeof (struct local_hash_entry)))
+ return FALSE;
/* The object attributes have been merged. Remove the input
sections from the link, and set the contents of the output
if (info->strip != strip_all || emit_relocs)
{
+ bfd_boolean name_local_sections;
+ const char *name;
+
file_ptr off = elf_next_file_pos (abfd);
_bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
/* Output a symbol for each section. We output these even if we are
discarding local symbols, since they are used for relocs. These
- symbols have no names. We store the index of each one in the
- index field of the section, so that we can find it again when
+ symbols usually have no names. We store the index of each one in
+ the index field of the section, so that we can find it again when
outputting relocs. */
+ name_local_sections
+ = (bed->elf_backend_name_local_section_symbols
+ && bed->elf_backend_name_local_section_symbols (abfd));
+
+ name = NULL;
elfsym.st_size = 0;
elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
elfsym.st_other = 0;
elfsym.st_shndx = i;
if (!bfd_link_relocatable (info))
elfsym.st_value = o->vma;
- if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, o,
+ if (name_local_sections)
+ name = o->name;
+ if (elf_link_output_symstrtab (&flinfo, name, &elfsym, o,
NULL) != 1)
goto error_return;
}
}
}
+ /* On some targets like Irix 5 the symbol split between local and global
+ ones recorded in the sh_info field needs to be done between section
+ and all other symbols. */
+ if (bed->elf_backend_elfsym_local_is_section
+ && bed->elf_backend_elfsym_local_is_section (abfd))
+ symtab_hdr->sh_info = bfd_get_symcount (abfd);
+
/* Allocate some memory to hold information read in from the input
files. */
if (max_contents_size != 0)
}
}
+ ret = TRUE;
+
/* Output any global symbols that got converted to local in a
version script or due to symbol visibility. We do this in a
separate step since ELF requires all local symbols to appear
eoinfo.file_sym_done = FALSE;
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* If backend needs to output some local symbols not present in the hash
table, do it now. */
if (! ((*bed->elf_backend_output_arch_local_syms)
(abfd, info, &flinfo,
(out_sym_func) elf_link_output_symstrtab)))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
/* That wrote out all the local symbols. Finish up the symbol table
converted to local in a version script. */
/* The sh_info field records the index of the first non local symbol. */
- symtab_hdr->sh_info = bfd_get_symcount (abfd);
+ if (!symtab_hdr->sh_info)
+ symtab_hdr->sh_info = bfd_get_symcount (abfd);
if (dynamic
&& htab->dynsym != NULL
BFD_ASSERT (indx > 0);
sym.st_shndx = indx;
if (! check_dynsym (abfd, &sym))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
sym.st_value = s->vma;
dest = dynsym + dynindx * bed->s->sizeof_sym;
+
+ /* Inform the linker of the addition of this symbol. */
+
+ if (info->callbacks->ctf_new_dynsym)
+ info->callbacks->ctf_new_dynsym (dynindx, &sym);
+
bed->s->swap_symbol_out (abfd, &sym, dest, 0);
}
}
the original st_name with the dynstr_index. */
sym = e->isym;
sym.st_other &= ~ELF_ST_VISIBILITY (-1);
+ sym.st_shndx = SHN_UNDEF;
s = bfd_section_from_elf_index (e->input_bfd,
e->isym.st_shndx);
- if (s != NULL)
+ if (s != NULL
+ && s->output_section != NULL
+ && elf_section_data (s->output_section) != NULL)
{
sym.st_shndx =
elf_section_data (s->output_section)->this_idx;
if (! check_dynsym (abfd, &sym))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
sym.st_value = (s->output_section->vma
+ s->output_offset
+ e->isym.st_value);
}
+ /* Inform the linker of the addition of this symbol. */
+
+ if (info->callbacks->ctf_new_dynsym)
+ info->callbacks->ctf_new_dynsym (e->dynindx, &sym);
+
dest = dynsym + e->dynindx * bed->s->sizeof_sym;
bed->s->swap_symbol_out (abfd, &sym, dest, 0);
}
eoinfo.flinfo = &flinfo;
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* If backend needs to output some symbols not present in the hash
table, do it now. */
if (! ((*bed->elf_backend_output_arch_syms)
(abfd, info, &flinfo,
(out_sym_func) elf_link_output_symstrtab)))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
/* Finalize the .strtab section. */
/* Swap out the .strtab section. */
if (!elf_link_swap_symbols_out (&flinfo))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* Now we know the size of the symtab section. */
if (bfd_get_symcount (abfd) > 0)
if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
|| (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
}
if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
|| ! _bfd_elf_strtab_emit (abfd, flinfo.symstrtab))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
if (info->out_implib_bfd && !elf_output_implib (abfd, info))
{
_bfd_error_handler (_("%pB: failed to generate import library"),
info->out_implib_bfd);
- return FALSE;
+ ret = FALSE;
+ goto return_local_hash_table;
}
/* Adjust the relocs to have the correct symbol indices. */
sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o);
if (esdo->rel.hdr != NULL
&& !elf_link_adjust_relocs (abfd, o, &esdo->rel, sort, info))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
if (esdo->rela.hdr != NULL
&& !elf_link_adjust_relocs (abfd, o, &esdo->rela, sort, info))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* Set the reloc_count field to 0 to prevent write_relocs from
trying to swap the relocs out itself. */
{
bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size);
if (contents == NULL)
- return FALSE; /* Bail out and fail. */
+ {
+ /* Bail out and fail. */
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
free (contents);
}
- return TRUE;
+ return_local_hash_table:
+ if (info->unique_symbol)
+ bfd_hash_table_free (&flinfo.local_hash_table);
+ return ret;
error_return:
elf_final_link_free (abfd, &flinfo);
- return FALSE;
+ ret = FALSE;
+ goto return_local_hash_table;
}
\f
/* Initialize COOKIE for input bfd ABFD. */
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && !bfd_is_abs_section (h->root.u.def.section)
- && !bfd_is_und_section (h->root.u.def.section))
+ && !bfd_is_const_section (h->root.u.def.section))
h->root.u.def.section->flags |= SEC_KEEP;
}
}
|| (elf_section_data (o)->this_hdr.sh_type
== SHT_FINI_ARRAY)))
|| (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
- && elf_next_in_group (o) == NULL )))
+ && elf_next_in_group (o) == NULL
+ && elf_linked_to_section (o) == NULL)
+ || ((elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain)
+ && (elf_section_flags (o) & SHF_GNU_RETAIN))))
{
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
flagword flag_value;
} elf_flags_to_name_table;
-static elf_flags_to_name_table elf_flags_to_names [] =
+static const elf_flags_to_name_table elf_flags_to_names [] =
{
{ "SHF_WRITE", SHF_WRITE },
{ "SHF_ALLOC", SHF_ALLOC },
if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
&& ((flags & SEC_GROUP) != 0
|| strcmp (name, l->sec->name) == 0))
- || (l->sec->owner->flags & BFD_PLUGIN) != 0)
+ || (l->sec->owner->flags & BFD_PLUGIN) != 0
+ || (sec->owner->flags & BFD_PLUGIN) != 0)
{
/* The section has already been linked. See if we should
issue a warning. */
ehdest->target_internal = ehsrc->target_internal;
isym.st_other = ehsrc->other;
- elf_merge_st_other (abfd, ehdest, &isym, NULL, TRUE, FALSE);
+ elf_merge_st_other (abfd, ehdest, isym.st_other, NULL, TRUE, FALSE);
}
/* Append a RELA relocation REL to section S in BFD. */
h = elf_link_hash_lookup (elf_hash_table (info), symbol,
FALSE, FALSE, TRUE);
+ /* NB: Common symbols will be turned into definition later. */
if (h != NULL
&& (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak
- || ((h->ref_regular || h->def_dynamic) && !h->def_regular)))
+ || ((h->ref_regular || h->def_dynamic)
+ && !h->def_regular
+ && h->root.type != bfd_link_hash_common)))
{
bfd_boolean was_dynamic = h->ref_dynamic || h->def_dynamic;
+ h->verinfo.verdef = NULL;
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = sec;
h->root.u.def.value = 0;
else
{
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_PROTECTED;
+ h->other = ((h->other & ~ELF_ST_VISIBILITY (-1))
+ | info->start_stop_visibility);
if (was_dynamic)
bfd_elf_link_record_dynamic_symbol (info, h);
}
}
return TRUE;
}
+
+/* Add dynamic tags. */
+
+bfd_boolean
+_bfd_elf_add_dynamic_tags (bfd *output_bfd, struct bfd_link_info *info,
+ bfd_boolean need_dynamic_reloc)
+{
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ if (htab->dynamic_sections_created)
+ {
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in finish_dynamic_sections, but we must add
+ the entries now so that we get the correct size for the
+ .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
+#define add_dynamic_entry(TAG, VAL) \
+ _bfd_elf_add_dynamic_entry (info, TAG, VAL)
+
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (output_bfd);
+
+ if (bfd_link_executable (info))
+ {
+ if (!add_dynamic_entry (DT_DEBUG, 0))
+ return FALSE;
+ }
+
+ if (htab->dt_pltgot_required || htab->splt->size != 0)
+ {
+ /* DT_PLTGOT is used by prelink even if there is no PLT
+ relocation. */
+ if (!add_dynamic_entry (DT_PLTGOT, 0))
+ return FALSE;
+ }
+
+ if (htab->dt_jmprel_required || htab->srelplt->size != 0)
+ {
+ if (!add_dynamic_entry (DT_PLTRELSZ, 0)
+ || !add_dynamic_entry (DT_PLTREL,
+ (bed->rela_plts_and_copies_p
+ ? DT_RELA : DT_REL))
+ || !add_dynamic_entry (DT_JMPREL, 0))
+ return FALSE;
+ }
+
+ if (htab->tlsdesc_plt
+ && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
+ || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
+ return FALSE;
+
+ if (need_dynamic_reloc)
+ {
+ if (bed->rela_plts_and_copies_p)
+ {
+ if (!add_dynamic_entry (DT_RELA, 0)
+ || !add_dynamic_entry (DT_RELASZ, 0)
+ || !add_dynamic_entry (DT_RELAENT,
+ bed->s->sizeof_rela))
+ return FALSE;
+ }
+ else
+ {
+ if (!add_dynamic_entry (DT_REL, 0)
+ || !add_dynamic_entry (DT_RELSZ, 0)
+ || !add_dynamic_entry (DT_RELENT,
+ bed->s->sizeof_rel))
+ 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 (htab, _bfd_elf_maybe_set_textrel,
+ info);
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (htab->ifunc_resolvers)
+ info->callbacks->einfo
+ (_("%P: warning: GNU indirect functions with DT_TEXTREL "
+ "may result in a segfault at runtime; recompile with %s\n"),
+ bfd_link_dll (info) ? "-fPIC" : "-fPIE");
+
+ if (!add_dynamic_entry (DT_TEXTREL, 0))
+ return FALSE;
+ }
+ }
+ }
+#undef add_dynamic_entry
+
+ return TRUE;
+}