Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
-This file is part of BFD, the Binary File Descriptor library.
+ This file is part of BFD, the Binary File Descriptor library.
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
return FALSE;
}
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED);
+ flags = bed->dynamic_sec_flags;
s = bfd_make_section (abfd, ".got");
if (s == NULL
bed->got_symbol_offset, NULL, FALSE, bed->collect, &bh)))
return FALSE;
h = (struct elf_link_hash_entry *) bh;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
h->type = STT_OBJECT;
if (! info->executable
else
abfd = elf_hash_table (info)->dynobj;
- /* Note that we set the SEC_IN_MEMORY flag for all of these
- sections. */
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ bed = get_elf_backend_data (abfd);
+
+ flags = bed->dynamic_sec_flags;
/* A dynamically linked executable has a .interp section, but a
shared library does not. */
elf_hash_table (info)->eh_info.hdr_sec = s;
}
- bed = get_elf_backend_data (abfd);
-
/* Create sections to hold version informations. These are removed
if they are not needed. */
s = bfd_make_section (abfd, ".gnu.version_d");
get_elf_backend_data (abfd)->collect, &bh)))
return FALSE;
h = (struct elf_link_hash_entry *) bh;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
h->type = STT_OBJECT;
if (! info->executable
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
.rel[a].bss sections. */
-
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED);
+ flags = bed->dynamic_sec_flags;
pltflags = flags;
- pltflags |= SEC_CODE;
if (bed->plt_not_loaded)
+ /* We do not clear SEC_ALLOC here because we still want the OS to
+ allocate space for the section; it's just that there's nothing
+ to read in from the object file. */
pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
+ else
+ pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD;
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
FALSE, get_elf_backend_data (abfd)->collect, &bh)))
return FALSE;
h = (struct elf_link_hash_entry *) bh;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
h->type = STT_OBJECT;
if (! info->executable
if (h->root.type != bfd_link_hash_undefined
&& h->root.type != bfd_link_hash_undefweak)
{
- h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+ h->forced_local = 1;
return TRUE;
}
/* Since we're defining the symbol, don't let it seem to have not
been defined. record_dynamic_symbol and size_dynamic_sections
- may depend on this. */
+ may depend on this.
+ ??? Changing bfd_link_hash_undefined to bfd_link_hash_new (or
+ to bfd_link_hash_undefweak, see linker.c:link_action) runs the risk
+ of some later symbol manipulation setting the symbol back to
+ bfd_link_hash_undefined, and the linker trying to add the symbol to
+ the undefs list twice. */
if (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_undefined)
h->root.type = bfd_link_hash_new;
if (h->root.type == bfd_link_hash_new)
- h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+ h->non_elf = 0;
/* If this symbol is being provided by the linker script, and it is
currently defined by a dynamic object, but not by a regular
object, then mark it as undefined so that the generic linker will
force the correct value. */
if (provide
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ && h->def_dynamic
+ && !h->def_regular)
h->root.type = bfd_link_hash_undefined;
/* If this symbol is not being provided by the linker script, and it is
then clear out any version information because the symbol will not be
associated with the dynamic object any more. */
if (!provide
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ && h->def_dynamic
+ && !h->def_regular)
h->verinfo.verdef = NULL;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
- if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC
- | ELF_LINK_HASH_REF_DYNAMIC)) != 0
+ if ((h->def_dynamic
+ || h->ref_dynamic
|| info->shared)
&& h->dynindx == -1)
{
/* If this is a weak defined symbol, and we know a corresponding
real symbol from the same dynamic object, make sure the real
symbol is also made into a dynamic symbol. */
- if (h->weakdef != NULL
- && h->weakdef->dynindx == -1)
+ if (h->u.weakdef != NULL
+ && h->u.weakdef->dynindx == -1)
{
- if (! bfd_elf_link_record_dynamic_symbol (info, h->weakdef))
+ if (! bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef))
return FALSE;
}
}
bfd *dynobj = elf_hash_table (info)->dynobj;
if (dynobj != NULL
- && (ip = bfd_get_section_by_name (dynobj, p->name))
- != NULL
+ && (ip = bfd_get_section_by_name (dynobj, p->name)) != NULL
&& (ip->flags & SEC_LINKER_CREATED)
&& ip->output_section == p)
return TRUE;
bfd_boolean *type_change_ok,
bfd_boolean *size_change_ok)
{
- asection *sec;
+ asection *sec, *oldsec;
struct elf_link_hash_entry *h;
struct elf_link_hash_entry *flip;
int bind;
if (h->root.type == bfd_link_hash_new)
{
- h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF;
+ h->non_elf = 0;
return TRUE;
}
- /* OLDBFD is a BFD associated with the existing symbol. */
+ /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the
+ existing symbol. */
switch (h->root.type)
{
default:
oldbfd = NULL;
+ oldsec = NULL;
break;
case bfd_link_hash_undefined:
case bfd_link_hash_undefweak:
oldbfd = h->root.u.undef.abfd;
+ oldsec = NULL;
break;
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
oldbfd = h->root.u.def.section->owner;
+ oldsec = h->root.u.def.section;
break;
case bfd_link_hash_common:
oldbfd = h->root.u.c.p->section->owner;
+ oldsec = h->root.u.c.p->section;
break;
}
dynamic object, which we do want to handle here. */
if (abfd == oldbfd
&& ((abfd->flags & DYNAMIC) == 0
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ || !h->def_regular))
return TRUE;
/* NEWDYN and OLDDYN indicate whether the new or old symbol,
else
olddef = TRUE;
+ /* Check TLS symbol. */
+ if ((ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)
+ && ELF_ST_TYPE (sym->st_info) != h->type)
+ {
+ bfd *ntbfd, *tbfd;
+ bfd_boolean ntdef, tdef;
+ asection *ntsec, *tsec;
+
+ if (h->type == STT_TLS)
+ {
+ ntbfd = abfd;
+ ntsec = sec;
+ ntdef = newdef;
+ tbfd = oldbfd;
+ tsec = oldsec;
+ tdef = olddef;
+ }
+ else
+ {
+ ntbfd = oldbfd;
+ ntsec = oldsec;
+ ntdef = olddef;
+ tbfd = abfd;
+ tsec = sec;
+ tdef = newdef;
+ }
+
+ if (tdef && ntdef)
+ (*_bfd_error_handler)
+ (_("%s: TLS definition in %B section %A mismatches non-TLS definition in %B section %A"),
+ tbfd, tsec, ntbfd, ntsec, h->root.root.string);
+ else if (!tdef && !ntdef)
+ (*_bfd_error_handler)
+ (_("%s: TLS reference in %B mismatches non-TLS reference in %B"),
+ tbfd, ntbfd, h->root.root.string);
+ else if (tdef)
+ (*_bfd_error_handler)
+ (_("%s: TLS definition in %B section %A mismatches non-TLS reference in %B"),
+ tbfd, tsec, ntbfd, h->root.root.string);
+ else
+ (*_bfd_error_handler)
+ (_("%s: TLS reference in %B mismatches non-TLS definition in %B section %A"),
+ tbfd, ntbfd, ntsec, h->root.root.string);
+
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
/* We need to remember if a symbol has a definition in a dynamic
object or is weak in all dynamic objects. Internal and hidden
visibility will make it unavailable to dynamic objects. */
- if (newdyn && (h->elf_link_hash_flags & ELF_LINK_DYNAMIC_DEF) == 0)
+ if (newdyn && !h->dynamic_def)
{
if (!bfd_is_und_section (sec))
- h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_DEF;
+ h->dynamic_def = 1;
else
{
/* Check if this symbol is weak in all dynamic objects. If it
is the first time we see it in a dynamic object, we mark
if it is weak. Otherwise, we clear it. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
+ if (!h->ref_dynamic)
{
if (bind == STB_WEAK)
- h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_WEAK;
+ h->dynamic_weak = 1;
}
else if (bind != STB_WEAK)
- h->elf_link_hash_flags &= ~ELF_LINK_DYNAMIC_WEAK;
+ h->dynamic_weak = 0;
}
}
{
*skip = TRUE;
/* Make sure this symbol is dynamic. */
- h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+ h->ref_dynamic = 1;
/* A protected symbol has external availability. Make sure it is
recorded as dynamic.
}
else if (!newdyn
&& ELF_ST_VISIBILITY (sym->st_other) != STV_DEFAULT
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+ && h->def_dynamic)
{
/* If the new symbol with non-default visibility comes from a
relocatable file and the old definition comes from a dynamic
if ((*sym_hash)->root.type == bfd_link_hash_indirect)
h = *sym_hash;
- if ((h->root.und_next || info->hash->undefs_tail == &h->root)
+ if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root)
&& bfd_is_und_section (sec))
{
/* If the new symbol is undefined and the old symbol was
also undefined before, we need to make sure
_bfd_generic_link_add_one_symbol doesn't mess
- up the linker hash table undefs list. Since the old
+ up the linker hash table undefs list. Since the old
definition came from a dynamic object, it is still on the
undefs list. */
h->root.type = bfd_link_hash_undefined;
- /* FIXME: What if the new symbol is weak undefined? */
h->root.u.undef.abfd = abfd;
}
else
h->root.u.undef.abfd = NULL;
}
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+ if (h->def_dynamic)
{
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC;
- h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_DYNAMIC
- | ELF_LINK_DYNAMIC_DEF);
+ h->def_dynamic = 0;
+ h->ref_dynamic = 1;
+ h->dynamic_def = 1;
}
/* FIXME: Should we check type and size for protected symbol? */
h->size = 0;
if (olddyn
&& olddef
&& h->root.type == bfd_link_hash_defined
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ && h->def_dynamic
&& (h->root.u.def.section->flags & SEC_ALLOC) != 0
&& (h->root.u.def.section->flags & SEC_LOAD) == 0
&& h->size > 0
|| h->type == STT_FUNC)))
&& olddyn
&& olddef
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+ && h->def_dynamic)
{
/* Change the hash table entry to undefined, and let
_bfd_generic_link_add_one_symbol do the right thing with the
h->root.u.i.link = (struct bfd_link_hash_entry *) flip;
(*bed->elf_backend_copy_indirect_symbol) (bed, flip, h);
flip->root.u.undef.abfd = h->root.u.undef.abfd;
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+ if (h->def_dynamic)
{
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC;
- flip->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+ h->def_dynamic = 0;
+ flip->ref_dynamic = 1;
}
}
h->root.type = bfd_link_hash_indirect;
h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+ if (h->def_dynamic)
{
- h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
- hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
- if (hi->elf_link_hash_flags
- & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR))
+ h->def_dynamic = 0;
+ hi->ref_dynamic = 1;
+ if (hi->ref_regular
+ || hi->def_regular)
{
if (! bfd_elf_link_record_dynamic_symbol (info, hi))
return FALSE;
if (! dynamic)
{
if (info->shared
- || ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+ || hi->ref_dynamic)
*dynsym = TRUE;
}
else
{
- if ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0)
+ if (hi->ref_regular)
*dynsym = TRUE;
}
}
if (hi->root.type != bfd_link_hash_defined
&& hi->root.type != bfd_link_hash_defweak)
(*_bfd_error_handler)
- (_("%s: warning: unexpected redefinition of indirect versioned symbol `%s'"),
- bfd_archive_filename (abfd), shortname);
+ (_("%B: unexpected redefinition of indirect versioned symbol `%s'"),
+ abfd, shortname);
}
else
{
if (! dynamic)
{
if (info->shared
- || ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+ || hi->ref_dynamic)
*dynsym = TRUE;
}
else
{
- if ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0)
+ if (hi->ref_regular)
*dynsym = TRUE;
}
}
h = (struct elf_link_hash_entry *) h->root.u.i.link;
if (h->dynindx == -1
- && (h->elf_link_hash_flags
- & (ELF_LINK_HASH_DEF_REGULAR | ELF_LINK_HASH_REF_REGULAR)) != 0)
+ && (h->def_regular
+ || h->ref_regular))
{
struct bfd_elf_version_tree *t;
struct bfd_elf_version_expr *d;
/* We only care about symbols defined in shared objects with version
information. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ if (!h->def_dynamic
+ || h->def_regular
|| h->dynindx == -1
|| h->verinfo.verdef == NULL)
return TRUE;
/* We only need version numbers for symbols defined in regular
objects. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (!h->def_regular)
return TRUE;
bed = get_elf_backend_data (sinfo->output_bfd);
if (*p == '\0')
{
if (hidden)
- h->elf_link_hash_flags |= ELF_LINK_HIDDEN;
+ h->hidden = 1;
return TRUE;
}
/* We could not find the version for a symbol when
generating a shared archive. Return an error. */
(*_bfd_error_handler)
- (_("%s: undefined versioned symbol name %s"),
- bfd_get_filename (sinfo->output_bfd), h->root.root.string);
+ (_("%B: undefined versioned symbol name %s"),
+ sinfo->output_bfd, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
sinfo->failed = TRUE;
return FALSE;
}
if (hidden)
- h->elf_link_hash_flags |= ELF_LINK_HIDDEN;
+ h->hidden = 1;
}
/* If we don't have a version for this symbol, see if we can find
if ((size_t) r_symndx >= nsyms)
{
(*_bfd_error_handler)
- (_("%s: bad reloc symbol index (0x%lx >= 0x%lx) for offset 0x%lx in section `%s'"),
- bfd_archive_filename (abfd), (unsigned long) r_symndx,
- (unsigned long) nsyms, irela->r_offset, sec->name);
+ (_("%B: bad reloc symbol index (0x%lx >= 0x%lx)"
+ " for offset 0x%lx in section `%A'"),
+ abfd, sec,
+ (unsigned long) r_symndx, (unsigned long) nsyms, irela->r_offset);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
else
{
(*_bfd_error_handler)
- (_("%s: relocation size mismatch in %s section %s"),
- bfd_get_filename (output_bfd),
- bfd_archive_filename (input_section->owner),
- input_section->name);
+ (_("%B: relocation size mismatch in %B section %A"),
+ output_bfd, input_section->owner, input_section);
bfd_set_error (bfd_error_wrong_object_format);
return FALSE;
}
DEF_REGULAR and REF_REGULAR correctly. This is the only way to
permit a non-ELF file to correctly refer to a symbol defined in
an ELF dynamic object. */
- if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
+ if (h->non_elf)
{
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_defined
&& h->root.type != bfd_link_hash_defweak)
- h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK);
+ {
+ h->ref_regular = 1;
+ h->ref_regular_nonweak = 1;
+ }
else
{
if (h->root.u.def.section->owner != NULL
&& (bfd_get_flavour (h->root.u.def.section->owner)
== bfd_target_elf_flavour))
- h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK);
+ {
+ h->ref_regular = 1;
+ h->ref_regular_nonweak = 1;
+ }
else
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
}
if (h->dynindx == -1
- && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+ && (h->def_dynamic
+ || h->ref_dynamic))
{
if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
{
}
else
{
- /* Unfortunately, ELF_LINK_NON_ELF is only correct if the symbol
+ /* Unfortunately, NON_ELF is only correct if the symbol
was first seen in a non-ELF file. Fortunately, if the symbol
was first seen in an ELF file, we're probably OK unless the
symbol was defined in a non-ELF file. Catch that case here.
a dynamic object, and then later in a non-ELF regular object. */
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ && !h->def_regular
&& (h->root.u.def.section->owner != NULL
? (bfd_get_flavour (h->root.u.def.section->owner)
!= bfd_target_elf_flavour)
: (bfd_is_abs_section (h->root.u.def.section)
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) == 0)))
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ && !h->def_dynamic)))
+ h->def_regular = 1;
}
/* If this is a final link, and the symbol was defined as a common
symbol in a regular object file, and there was no definition in
any dynamic object, then the linker will have allocated space for
- the symbol in a common section but the ELF_LINK_HASH_DEF_REGULAR
+ the symbol in a common section but the DEF_REGULAR
flag will not have been set. */
if (h->root.type == bfd_link_hash_defined
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+ && !h->def_regular
+ && h->ref_regular
+ && !h->def_dynamic
&& (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
/* If -Bsymbolic was used (which means to bind references to global
symbols to the definition within the shared object), and this
need a PLT entry. Likewise, if the symbol has non-default
visibility. If the symbol has hidden or internal visibility, we
will force it local. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
+ if (h->needs_plt
&& eif->info->shared
&& is_elf_hash_table (eif->info->hash)
&& (eif->info->symbolic
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+ && h->def_regular)
{
const struct elf_backend_data *bed;
bfd_boolean force_local;
/* If this is a weak defined symbol in a dynamic object, and we know
the real definition in the dynamic object, copy interesting flags
over to the real definition. */
- if (h->weakdef != NULL)
+ if (h->u.weakdef != NULL)
{
struct elf_link_hash_entry *weakdef;
- weakdef = h->weakdef;
+ weakdef = h->u.weakdef;
if (h->root.type == bfd_link_hash_indirect)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|| h->root.type == bfd_link_hash_defweak);
BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
|| weakdef->root.type == bfd_link_hash_defweak);
- BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
+ BFD_ASSERT (weakdef->def_dynamic);
/* 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 ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
- h->weakdef = NULL;
+ if (weakdef->def_regular)
+ h->u.weakdef = NULL;
else
{
const struct elf_backend_data *bed;
to the dynamic symbol table. FIXME: Do we normally need to worry
about symbols which are defined by one dynamic object and
referenced by another one? */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0
- && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
- || ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0
- && (h->weakdef == NULL || h->weakdef->dynindx == -1))))
+ if (!h->needs_plt
+ && (h->def_regular
+ || !h->def_dynamic
+ || (!h->ref_regular
+ && (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1))))
{
h->plt = elf_hash_table (eif->info)->init_offset;
return TRUE;
/* If we've already adjusted this symbol, don't do it again. This
can happen via a recursive call. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0)
+ if (h->dynamic_adjusted)
return TRUE;
/* Don't look at this symbol again. Note that we must set this
after checking the above conditions, because we may look at a
symbol once, decide not to do anything, and then get called
recursively later after REF_REGULAR is set below. */
- h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED;
+ h->dynamic_adjusted = 1;
/* If this is a weak definition, and we know a real definition, and
the real symbol is not itself defined by a regular object file,
wind up at different memory locations. The tzset call will set
_timezone, leaving timezone unchanged. */
- if (h->weakdef != NULL)
+ if (h->u.weakdef != NULL)
{
/* If we get to this point, we know there is an implicit
reference by a regular object file via the weak symbol H.
FIXME: Is this really true? What if the traversal finds
- H->WEAKDEF before it finds H? */
- h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+ H->U.WEAKDEF before it finds H? */
+ h->u.weakdef->ref_regular = 1;
- if (! _bfd_elf_adjust_dynamic_symbol (h->weakdef, eif))
+ if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif))
return FALSE;
}
code, and the assembly code fails to set the symbol type. */
if (h->size == 0
&& h->type == STT_NOTYPE
- && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0)
+ && !h->needs_plt)
(*_bfd_error_handler)
(_("warning: type and size of dynamic symbol `%s' are not defined"),
h->root.root.string);
/* If it was forced local, then clearly it's not dynamic. */
if (h->dynindx == -1)
return FALSE;
- if (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)
+ if (h->forced_local)
return FALSE;
/* Identify the cases where name binding rules say that a
}
/* If it isn't defined locally, then clearly it's dynamic. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (!h->def_regular)
return TRUE;
/* Otherwise, the symbol is dynamic if binding rules don't tell
if (h == NULL)
return TRUE;
+ /* Common symbols that become definitions don't get the DEF_REGULAR
+ flag set, so test it first, and don't bail out. */
+ if (ELF_COMMON_DEF_P (h))
+ /* Do nothing. */;
/* If we don't have a definition in a regular file, then we can't
resolve locally. The sym is either undefined or dynamic. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ else if (!h->def_regular)
return FALSE;
/* Forced local symbols resolve locally. */
- if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+ if (h->forced_local)
return TRUE;
/* As do non-dynamic symbols. */
if (! is_elf_hash_table (hash_table))
return FALSE;
+ if (info->warn_shared_textrel && info->shared && tag == DT_TEXTREL)
+ _bfd_error_handler
+ (_("warning: creating a DT_TEXTREL in a shared object."));
+
bed = get_elf_backend_data (hash_table->dynobj);
s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
BFD_ASSERT (s != NULL);
const char **, flagword *, asection **, bfd_vma *);
bfd_boolean (*check_relocs)
(bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
+ bfd_boolean (*check_directives)
+ (bfd *, struct bfd_link_info *);
bfd_boolean collect;
Elf_Internal_Shdr *hdr;
bfd_size_type symcount;
|| !is_elf_hash_table (hash_table)
|| hash_table->root.creator != abfd->xvec)
{
- bfd_set_error (bfd_error_invalid_operation);
+ if (info->relocatable)
+ bfd_set_error (bfd_error_invalid_operation);
+ else
+ bfd_set_error (bfd_error_wrong_format);
goto error_return;
}
}
/* If this dynamic lib was specified on the command line with
--as-needed in effect, then we don't want to add a DT_NEEDED
tag unless the lib is actually used. Similary for libs brought
- in by another lib's DT_NEEDED. */
- add_needed = elf_dyn_lib_class (abfd) == DYN_NORMAL;
+ in by another lib's DT_NEEDED. When --no-add-needed is used
+ on a dynamic lib, we don't want to add a DT_NEEDED entry for
+ any dynamic library in DT_NEEDED tags in the dynamic lib at
+ all. */
+ add_needed = (elf_dyn_lib_class (abfd)
+ & (DYN_AS_NEEDED | DYN_DT_NEEDED
+ | DYN_NO_NEEDED)) == 0;
s = bfd_get_section_by_name (abfd, ".dynamic");
if (s != NULL)
if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info)
{
(*_bfd_error_handler)
- (_("%s: %s: invalid version %u (max %d)"),
- bfd_archive_filename (abfd), name, vernum,
+ (_("%B: %s: invalid version %u (max %d)"),
+ abfd, name, vernum,
elf_tdata (abfd)->dynverdef_hdr.sh_info);
bfd_set_error (bfd_error_bad_value);
goto error_free_vers;
if (verstr == NULL)
{
(*_bfd_error_handler)
- (_("%s: %s: invalid needed version %d"),
- bfd_archive_filename (abfd), name, vernum);
+ (_("%B: %s: invalid needed version %d"),
+ abfd, name, vernum);
bfd_set_error (bfd_error_bad_value);
goto error_free_vers;
}
&& (flags & BSF_WEAK) != 0
&& ELF_ST_TYPE (isym->st_info) != STT_FUNC
&& is_elf_hash_table (hash_table)
- && h->weakdef == NULL)
+ && h->u.weakdef == NULL)
{
/* Keep a list of all weak defined non function symbols from
a dynamic object, using the weakdef field. Later in this
dynamic object, and we will be using that previous
definition anyhow. */
- h->weakdef = weaks;
+ h->u.weakdef = weaks;
weaks = h;
new_weakdef = TRUE;
}
if (is_elf_hash_table (hash_table))
{
- int old_flags;
bfd_boolean dynsym;
- int new_flag;
/* Check the alignment when a common symbol is involved. This
can change when a common symbol is overridden by a normal
if (normal_align < common_align)
(*_bfd_error_handler)
- (_("Warning: alignment %u of symbol `%s' in %s is smaller than %u in %s"),
- 1 << normal_align,
- name,
- bfd_archive_filename (normal_bfd),
- 1 << common_align,
- bfd_archive_filename (common_bfd));
+ (_("Warning: alignment %u of symbol `%s' in %B"
+ " is smaller than %u in %B"),
+ normal_bfd, common_bfd,
+ 1 << normal_align, name, 1 << common_align);
}
/* Remember the symbol size and type. */
{
if (h->size != 0 && h->size != isym->st_size && ! size_change_ok)
(*_bfd_error_handler)
- (_("Warning: size of symbol `%s' changed from %lu in %s to %lu in %s"),
+ (_("Warning: size of symbol `%s' changed"
+ " from %lu in %B to %lu in %B"),
+ old_bfd, abfd,
name, (unsigned long) h->size,
- bfd_archive_filename (old_bfd),
- (unsigned long) isym->st_size,
- bfd_archive_filename (abfd));
+ (unsigned long) isym->st_size);
h->size = isym->st_size;
}
&& h->type != ELF_ST_TYPE (isym->st_info)
&& ! type_change_ok)
(*_bfd_error_handler)
- (_("Warning: type of symbol `%s' changed from %d to %d in %s"),
- name, h->type, ELF_ST_TYPE (isym->st_info),
- bfd_archive_filename (abfd));
+ (_("Warning: type of symbol `%s' changed"
+ " from %d to %d in %B"),
+ abfd, name, h->type, ELF_ST_TYPE (isym->st_info));
h->type = ELF_ST_TYPE (isym->st_info);
}
(*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
dynamic);
+ /* If this symbol has default visibility and the user has requested
+ we not re-export it, then mark it as hidden. */
+ if (definition && !dynamic
+ && (abfd->no_export
+ || (abfd->my_archive && abfd->my_archive->no_export))
+ && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
+ isym->st_other = STV_HIDDEN | (isym->st_other & ~ ELF_ST_VISIBILITY (-1));
+
if (isym->st_other != 0 && !dynamic)
{
unsigned char hvis, symvis, other, nvis;
the number of dynamic symbols we find. A dynamic symbol
is one which is referenced or defined by both a regular
object and a shared object. */
- old_flags = h->elf_link_hash_flags;
dynsym = FALSE;
if (! dynamic)
{
if (! definition)
{
- new_flag = ELF_LINK_HASH_REF_REGULAR;
+ h->ref_regular = 1;
if (bind != STB_WEAK)
- new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
+ h->ref_regular_nonweak = 1;
}
else
- new_flag = ELF_LINK_HASH_DEF_REGULAR;
+ h->def_regular = 1;
if (! info->executable
- || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
- | ELF_LINK_HASH_REF_DYNAMIC)) != 0)
+ || h->def_dynamic
+ || h->ref_dynamic)
dynsym = TRUE;
}
else
{
if (! definition)
- new_flag = ELF_LINK_HASH_REF_DYNAMIC;
+ h->ref_dynamic = 1;
else
- new_flag = ELF_LINK_HASH_DEF_DYNAMIC;
- if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR)) != 0
- || (h->weakdef != NULL
+ h->def_dynamic = 1;
+ if (h->def_regular
+ || h->ref_regular
+ || (h->u.weakdef != NULL
&& ! new_weakdef
- && h->weakdef->dynindx != -1))
+ && h->u.weakdef->dynindx != -1))
dynsym = TRUE;
}
- h->elf_link_hash_flags |= new_flag;
-
/* Check to see if we need to add an indirect symbol for
the default name. */
if (definition || h->root.type == bfd_link_hash_common)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
goto error_free_vers;
- if (h->weakdef != NULL
+ if (h->u.weakdef != NULL
&& ! new_weakdef
- && h->weakdef->dynindx == -1)
+ && h->u.weakdef->dynindx == -1)
{
- if (! bfd_elf_link_record_dynamic_symbol (info, h->weakdef))
+ if (! bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef))
goto error_free_vers;
}
}
if (!add_needed
&& definition
&& dynsym
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0)
+ && h->ref_regular)
{
int ret;
const char *soname = elf_dt_name (abfd);
/* A symbol from a library loaded via DT_NEEDED of some
other library is referenced by a regular object.
- Add a DT_NEEDED entry for it. */
+ Add a DT_NEEDED entry for it. Issue an error if
+ --no-add-needed is used. */
+ if ((elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
+ {
+ (*_bfd_error_handler)
+ (_("%s: invalid DSO for symbol `%s' definition"),
+ abfd, name);
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
+
add_needed = TRUE;
ret = elf_add_dt_needed_tag (info, soname, add_needed);
if (ret < 0)
size_t i, j, idx;
hlook = weaks;
- weaks = hlook->weakdef;
- hlook->weakdef = NULL;
+ weaks = hlook->u.weakdef;
+ hlook->u.weakdef = NULL;
BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
|| hlook->root.type == bfd_link_hash_defweak
break;
else if (h != hlook)
{
- hlook->weakdef = h;
+ hlook->u.weakdef = h;
/* If the weak definition is in the list of dynamic
symbols, make sure the real definition is put
free (sorted_sym_hash);
}
+ check_directives = get_elf_backend_data (abfd)->check_directives;
+ if (check_directives)
+ check_directives (abfd, info);
+
/* If this object is the same format as the output object, and it is
not a shared library, then let the backend look through the
relocs.
return FALSE;
}
+/* Return the linker hash table entry of a symbol that might be
+ satisfied by an archive symbol. Return -1 on error. */
+
+struct elf_link_hash_entry *
+_bfd_elf_archive_symbol_lookup (bfd *abfd,
+ struct bfd_link_info *info,
+ const char *name)
+{
+ struct elf_link_hash_entry *h;
+ char *p, *copy;
+ size_t len, first;
+
+ h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+ if (h != NULL)
+ return h;
+
+ /* If this is a default version (the name contains @@), look up the
+ symbol again with only one `@' as well as without the version.
+ The effect is that references to the symbol with and without the
+ version will be matched by the default symbol in the archive. */
+
+ p = strchr (name, ELF_VER_CHR);
+ if (p == NULL || p[1] != ELF_VER_CHR)
+ return h;
+
+ /* First check with only one `@'. */
+ len = strlen (name);
+ copy = bfd_alloc (abfd, len);
+ if (copy == NULL)
+ return (struct elf_link_hash_entry *) 0 - 1;
+
+ first = p - name + 1;
+ memcpy (copy, name, first);
+ memcpy (copy + first, name + first + 1, len - first);
+
+ h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, FALSE);
+ if (h == NULL)
+ {
+ /* We also need to check references to the symbol without the
+ version. */
+ copy[first - 1] = '\0';
+ h = elf_link_hash_lookup (elf_hash_table (info), copy,
+ FALSE, FALSE, FALSE);
+ }
+
+ bfd_release (abfd, copy);
+ return h;
+}
+
/* Add symbols from an ELF archive file to the linker hash table. We
don't use _bfd_generic_link_add_archive_symbols because of a
problem which arises on UnixWare. The UnixWare libc.so is an
carsym *symdefs;
bfd_boolean loop;
bfd_size_type amt;
+ const struct elf_backend_data *bed;
+ struct elf_link_hash_entry * (*archive_symbol_lookup)
+ (bfd *, struct bfd_link_info *, const char *);
if (! bfd_has_map (abfd))
{
goto error_return;
symdefs = bfd_ardata (abfd)->symdefs;
+ bed = get_elf_backend_data (abfd);
+ archive_symbol_lookup = bed->elf_backend_archive_symbol_lookup;
do
{
continue;
}
- h = elf_link_hash_lookup (elf_hash_table (info), symdef->name,
- FALSE, FALSE, FALSE);
-
- if (h == NULL)
- {
- char *p, *copy;
- size_t len, first;
-
- /* If this is a default version (the name contains @@),
- look up the symbol again with only one `@' as well
- as without the version. The effect is that references
- to the symbol with and without the version will be
- matched by the default symbol in the archive. */
-
- p = strchr (symdef->name, ELF_VER_CHR);
- if (p == NULL || p[1] != ELF_VER_CHR)
- continue;
-
- /* First check with only one `@'. */
- len = strlen (symdef->name);
- copy = bfd_alloc (abfd, len);
- if (copy == NULL)
- goto error_return;
- first = p - symdef->name + 1;
- memcpy (copy, symdef->name, first);
- memcpy (copy + first, symdef->name + first + 1, len - first);
-
- h = elf_link_hash_lookup (elf_hash_table (info), copy,
- FALSE, FALSE, FALSE);
-
- if (h == NULL)
- {
- /* We also need to check references to the symbol
- without the version. */
-
- copy[first - 1] = '\0';
- h = elf_link_hash_lookup (elf_hash_table (info),
- copy, FALSE, FALSE, FALSE);
- }
-
- bfd_release (abfd, copy);
- }
+ h = archive_symbol_lookup (abfd, info, symdef->name);
+ if (h == (struct elf_link_hash_entry *) 0 - 1)
+ goto error_return;
if (h == NULL)
continue;
/* And store it in the struct so that we can put it in the hash table
later. */
- h->elf_hash_value = ha;
+ h->u.elf_hash_value = ha;
if (alc != NULL)
free (alc);
/* Mark this version if there is a definition and it is
not defined in a shared object. */
if (newh != NULL
- && ((newh->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) == 0)
+ && !newh->def_dynamic
&& (newh->root.type == bfd_link_hash_defined
|| newh->root.type == bfd_link_hash_defweak))
d->symver = 1;
return FALSE;
/* Add some entries to the .dynamic section. We fill in some of the
- values later, in elf_bfd_final_link, but we must add the entries
+ values later, in bfd_elf_final_link, but we must add the entries
now so that we know the final size of the .dynamic section. */
/* If there are initialization and/or finalization functions to
FALSE, FALSE)
: NULL);
if (h != NULL
- && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR)) != 0)
+ && (h->ref_regular
+ || h->def_regular))
{
if (!_bfd_elf_add_dynamic_entry (info, DT_INIT, 0))
return FALSE;
FALSE, FALSE)
: NULL);
if (h != NULL
- && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR)) != 0)
+ && (h->ref_regular
+ || h->def_regular))
{
if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0))
return FALSE;
== SHT_PREINIT_ARRAY)
{
(*_bfd_error_handler)
- (_("%s: .preinit_array section is not allowed in DSO"),
- bfd_archive_filename (sub));
+ (_("%B: .preinit_array section is not allowed in DSO"),
+ sub);
break;
}
get_elf_backend_data (dynobj)->collect, &bh)))
return FALSE;
h = (struct elf_link_hash_entry *) bh;
- h->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->non_elf = 0;
+ h->def_regular = 1;
h->type = STT_OBJECT;
h->verinfo.vertree = t;
bfd_byte *erel, *erelend;
asection *o = lo->u.indirect.section;
+ if (o->contents == NULL && o->size != 0)
+ {
+ /* This is a reloc section that is being handled as a normal
+ section. See bfd_section_from_shdr. We can't combine
+ relocs in this case. */
+ free (sort);
+ return 0;
+ }
erel = o->contents;
erelend = o->contents + o->size;
p = sort + o->output_offset / ext_size * sort_elt;
case bfd_link_hash_undefweak:
abfd = h->root.u.undef.abfd;
if ((abfd->flags & DYNAMIC) == 0
- || elf_dyn_lib_class (abfd) != DYN_DT_NEEDED)
+ || (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) == 0)
return FALSE;
break;
/* Decide whether to output this symbol in this pass. */
if (eoinfo->localsyms)
{
- if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ if (!h->forced_local)
return TRUE;
}
else
{
- if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+ if (h->forced_local)
return TRUE;
}
references in regular files have already been handled). If we
are reporting errors for this situation then do so now. */
if (h->root.type == bfd_link_hash_undefined
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0
+ && h->ref_dynamic
+ && !h->ref_regular
&& ! elf_link_check_versioned_symbol (finfo->info, bed, h)
&& finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
{
shared libraries. */
if (! finfo->info->relocatable
&& (! finfo->info->shared)
- && (h->elf_link_hash_flags
- & (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK))
- == (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC)
+ && h->forced_local
+ && h->ref_dynamic
+ && !h->dynamic_def
+ && !h->dynamic_weak
&& ! elf_link_check_versioned_symbol (finfo->info, bed, h))
{
(*_bfd_error_handler)
- (_("%s: %s symbol `%s' in %s is referenced by DSO"),
- bfd_get_filename (finfo->output_bfd),
+ (_("%B: %s symbol `%s' in %B is referenced by DSO"),
+ finfo->output_bfd, h->root.u.def.section->owner,
ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
? "internal"
: ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
- ? "hidden" : "local",
- h->root.root.string,
- bfd_archive_filename (h->root.u.def.section->owner));
+ ? "hidden" : "local",
+ h->root.root.string);
eoinfo->failed = TRUE;
return FALSE;
}
output it. */
if (h->indx == -2)
strip = FALSE;
- else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0)
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
+ else if ((h->def_dynamic
+ || h->ref_dynamic)
+ && !h->def_regular
+ && !h->ref_regular)
strip = TRUE;
else if (finfo->info->strip == strip_all)
strip = TRUE;
nothing else to do unless it is a forced local symbol. */
if (strip
&& h->dynindx == -1
- && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ && !h->forced_local)
return TRUE;
sym.st_value = 0;
sym.st_size = h->size;
sym.st_other = h->other;
- if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+ if (h->forced_local)
sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
else if (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_defweak)
if (sym.st_shndx == SHN_BAD)
{
(*_bfd_error_handler)
- (_("%s: could not find output section %s for input section %s"),
- bfd_get_filename (finfo->output_bfd),
- input_sec->output_section->name,
- input_sec->name);
+ (_("%B: could not find output section %A for input section %A"),
+ finfo->output_bfd, input_sec->output_section, input_sec);
eoinfo->failed = TRUE;
return FALSE;
}
symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for
forced local syms when non-shared is due to a historical quirk. */
if ((h->dynindx != -1
- || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+ || h->forced_local)
&& ((finfo->info->shared
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
- || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ || !h->forced_local)
&& elf_hash_table (finfo->info)->dynamic_sections_created)
{
if (! ((*bed->elf_backend_finish_dynamic_symbol)
because it might not be marked as undefined until the
finish_dynamic_symbol routine gets through with it. */
if (sym.st_shndx == SHN_UNDEF
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
+ && h->ref_regular
&& (ELF_ST_BIND (sym.st_info) == STB_GLOBAL
|| ELF_ST_BIND (sym.st_info) == STB_WEAK))
{
int bindtype;
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0)
+ if (h->ref_regular_nonweak)
bindtype = STB_GLOBAL;
else
bindtype = STB_WEAK;
&& ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
&& ELF_ST_BIND (sym.st_info) != STB_WEAK
&& h->root.type == bfd_link_hash_undefined
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ && !h->def_regular)
{
(*_bfd_error_handler)
- (_("%s: %s symbol `%s' isn't defined"),
- bfd_get_filename (finfo->output_bfd),
- ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED
- ? "protected"
- : ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL
- ? "internal" : "hidden",
- h->root.root.string);
+ (_("%B: %s symbol `%s' isn't defined"),
+ finfo->output_bfd,
+ ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED
+ ? "protected"
+ : ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL
+ ? "internal" : "hidden",
+ h->root.root.string);
eoinfo->failed = TRUE;
return FALSE;
}
bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0);
bucketcount = elf_hash_table (finfo->info)->bucketcount;
- bucket = h->elf_hash_value % bucketcount;
+ bucket = h->u.elf_hash_value % bucketcount;
hash_entry_size
= elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
bucketpos = ((bfd_byte *) finfo->hash_sec->contents
Elf_Internal_Versym iversym;
Elf_External_Versym *eversym;
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (!h->def_regular)
{
if (h->verinfo.verdef == NULL)
iversym.vs_vers = 0;
iversym.vs_vers = h->verinfo.vertree->vernum + 1;
}
- if ((h->elf_link_hash_flags & ELF_LINK_HIDDEN) != 0)
+ if (h->hidden)
iversym.vs_vers |= VERSYM_HIDDEN;
eversym = (Elf_External_Versym *) finfo->symver_sec->contents;
return TRUE;
}
+/* Return TRUE if special handling is done for relocs in SEC against
+ symbols defined in discarded sections. */
+
static bfd_boolean
elf_section_ignore_discarded_relocs (asection *sec)
{
const struct elf_backend_data *bed;
- if (strncmp (".stab", sec->name, 5) == 0
- && (!sec->name[5] ||
- (sec->name[5] == '.' && ISDIGIT (sec->name[6]))))
- return TRUE;
-
- if (strcmp (".eh_frame", sec->name) == 0)
- return TRUE;
+ switch (sec->sec_info_type)
+ {
+ case ELF_INFO_TYPE_STABS:
+ case ELF_INFO_TYPE_EH_FRAME:
+ return TRUE;
+ default:
+ break;
+ }
bed = get_elf_backend_data (sec->owner);
if (bed->elf_backend_ignore_discarded_relocs != NULL
return FALSE;
}
+enum action_discarded
+ {
+ COMPLAIN = 1,
+ PRETEND = 2
+ };
+
+/* Return a mask saying how ld should treat relocations in SEC against
+ symbols defined in discarded sections. If this function returns
+ COMPLAIN set, ld will issue a warning message. If this function
+ returns PRETEND set, and the discarded section was link-once and the
+ same size as the kept link-once section, ld will pretend that the
+ symbol was actually defined in the kept section. Otherwise ld will
+ zero the reloc (at least that is the intent, but some cooperation by
+ the target dependent code is needed, particularly for REL targets). */
+
+static unsigned int
+elf_action_discarded (asection *sec)
+{
+ if (sec->flags & SEC_DEBUGGING)
+ return PRETEND;
+
+ if (strcmp (".eh_frame", sec->name) == 0)
+ return 0;
+
+ if (strcmp (".gcc_except_table", sec->name) == 0)
+ return 0;
+
+ if (strcmp (".PARISC.unwind", sec->name) == 0)
+ return 0;
+
+ if (strcmp (".fixup", sec->name) == 0)
+ return 0;
+
+ return COMPLAIN | PRETEND;
+}
+
+/* Find a match between a section and a member of a section group. */
+
+static asection *
+match_group_member (asection *sec, asection *group)
+{
+ asection *first = elf_next_in_group (group);
+ asection *s = first;
+
+ while (s != NULL)
+ {
+ if (bfd_elf_match_symbols_in_sections (s, sec))
+ return s;
+
+ if (s == first)
+ break;
+ }
+
+ return NULL;
+}
+
/* Link an input file into the linker output file. This function
handles all the sections and relocations of the input file at once.
This is so that we only have to read the local symbols once, and
if (!elf_section_ignore_discarded_relocs (o))
{
Elf_Internal_Rela *rel, *relend;
+ unsigned int action = elf_action_discarded (o);
rel = internal_relocs;
relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
for ( ; rel < relend; rel++)
{
unsigned long r_symndx = rel->r_info >> r_sym_shift;
- asection *sec;
+ asection **ps, *sec;
+ struct elf_link_hash_entry *h = NULL;
+ const char *sym_name;
+
+ if (r_symndx == STN_UNDEF)
+ continue;
if (r_symndx >= locsymcount
|| (elf_bad_symtab (input_bfd)
&& finfo->sections[r_symndx] == NULL))
{
- struct elf_link_hash_entry *h;
-
h = sym_hashes[r_symndx - extsymoff];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- /* Complain if the definition comes from a
- discarded section. */
- sec = h->root.u.def.section;
- if ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && elf_discarded_section (sec))
- {
- if ((o->flags & SEC_DEBUGGING) != 0)
- {
- BFD_ASSERT (r_symndx != 0);
- /* Try to preserve debug information. */
- if ((o->flags & SEC_DEBUGGING) != 0
- && sec->kept_section != NULL
- && sec->size == sec->kept_section->size)
- h->root.u.def.section
- = sec->kept_section;
- else
- memset (rel, 0, sizeof (*rel));
- }
- else
- finfo->info->callbacks->error_handler
- (LD_DEFINITION_IN_DISCARDED_SECTION,
- _("%T: discarded in section `%s' from %s\n"),
- h->root.root.string,
- h->root.root.string,
- h->root.u.def.section->name,
- bfd_archive_filename (h->root.u.def.section->owner));
- }
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ continue;
+
+ ps = &h->root.u.def.section;
+ sym_name = h->root.root.string;
}
else
{
- sec = finfo->sections[r_symndx];
+ Elf_Internal_Sym *sym = isymbuf + r_symndx;
+ ps = &finfo->sections[r_symndx];
+ sym_name = bfd_elf_local_sym_name (input_bfd, sym);
+ }
+
+ /* Complain if the definition comes from a
+ discarded section. */
+ if ((sec = *ps) != NULL && elf_discarded_section (sec))
+ {
+ asection *kept;
- if (sec != NULL && elf_discarded_section (sec))
+ BFD_ASSERT (r_symndx != 0);
+ if (action & COMPLAIN)
{
- if ((o->flags & SEC_DEBUGGING) != 0
- || (sec->flags & SEC_LINK_ONCE) != 0)
- {
- BFD_ASSERT (r_symndx != 0);
- /* Try to preserve debug information. */
- if ((o->flags & SEC_DEBUGGING) != 0
- && sec->kept_section != NULL
- && sec->size == sec->kept_section->size)
- finfo->sections[r_symndx]
- = sec->kept_section;
- else
- {
- rel->r_info &= r_type_mask;
- rel->r_addend = 0;
- }
- }
- else
+ (*_bfd_error_handler)
+ (_("`%s' referenced in section `%A' of %B: "
+ "defined in discarded section `%A' of %B\n"),
+ o, input_bfd, sec, sec->owner, sym_name);
+ }
+
+ /* Try to do the best we can to support buggy old
+ versions of gcc. If we've warned, or this is
+ debugging info, pretend that the symbol is
+ really defined in the kept linkonce section.
+ FIXME: This is quite broken. Modifying the
+ symbol here means we will be changing all later
+ uses of the symbol, not just in this section.
+ The only thing that makes this half reasonable
+ is that we warn in non-debug sections, and
+ debug sections tend to come after other
+ sections. */
+ kept = sec->kept_section;
+ if (kept != NULL && (action & PRETEND))
+ {
+ if (elf_sec_group (sec) != NULL)
+ kept = match_group_member (sec, kept);
+ if (kept != NULL
+ && sec->size == kept->size)
{
- static int count;
- int ok;
- char *buf;
-
- ok = asprintf (&buf, "local symbol %d",
- count++);
- if (ok <= 0)
- buf = (char *) "local symbol";
- finfo->info->callbacks->error_handler
- (LD_DEFINITION_IN_DISCARDED_SECTION,
- _("%T: discarded in section `%s' from %s\n"),
- buf, buf, sec->name,
- bfd_archive_filename (input_bfd));
- if (ok != -1)
- free (buf);
+ *ps = kept;
+ continue;
}
}
+
+ /* Remove the symbol reference from the reloc, but
+ don't kill the reloc completely. This is so that
+ a zero value will be written into the section,
+ which may have non-zero contents put there by the
+ assembler. Zero in things like an eh_frame fde
+ pc_begin allows stack unwinders to recognize the
+ fde as bogus. */
+ rel->r_info &= r_type_mask;
+ rel->r_addend = 0;
}
}
}
symbol. We set the rel_hash entry for this
reloc to point to the global hash table entry
for this symbol. The symbol index is then
- set at the end of elf_bfd_final_link. */
+ set at the end of bfd_elf_final_link. */
indx = r_symndx - extsymoff;
rh = elf_sym_hashes (input_bfd)[indx];
while (rh->root.type == bfd_link_hash_indirect
else
sym_name = link_order->u.reloc.p->u.name;
if (! ((*info->callbacks->reloc_overflow)
- (info, sym_name, howto->name, addend, NULL, NULL, 0)))
+ (info, NULL, sym_name, howto->name, addend, NULL,
+ NULL, (bfd_vma) 0)))
{
free (buf);
return FALSE;
return TRUE;
}
+
+/* Get the output vma of the section pointed to by the sh_link field. */
+
+static bfd_vma
+elf_get_linked_section_vma (struct bfd_link_order *p)
+{
+ Elf_Internal_Shdr **elf_shdrp;
+ asection *s;
+ int elfsec;
+
+ s = p->u.indirect.section;
+ elf_shdrp = elf_elfsections (s->owner);
+ elfsec = _bfd_elf_section_from_bfd_section (s->owner, s);
+ elfsec = elf_shdrp[elfsec]->sh_link;
+ /* PR 290:
+ The Intel C compiler generates SHT_IA_64_UNWIND with
+ SHF_LINK_ORDER. But it doesn't set theh sh_link or
+ sh_info fields. Hence we could get the situation
+ where elfsec is 0. */
+ if (elfsec == 0)
+ {
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (s->owner);
+ if (bed->link_order_error_handler)
+ bed->link_order_error_handler
+ (_("%B: warning: sh_link not set for section `%A'"), s->owner, s);
+ return 0;
+ }
+ else
+ {
+ s = elf_shdrp[elfsec]->bfd_section;
+ return s->output_section->vma + s->output_offset;
+ }
+}
+
+
+/* Compare two sections based on the locations of the sections they are
+ linked to. Used by elf_fixup_link_order. */
+
+static int
+compare_link_order (const void * a, const void * b)
+{
+ bfd_vma apos;
+ bfd_vma bpos;
+
+ apos = elf_get_linked_section_vma (*(struct bfd_link_order **)a);
+ bpos = elf_get_linked_section_vma (*(struct bfd_link_order **)b);
+ if (apos < bpos)
+ return -1;
+ return apos > bpos;
+}
+
+
+/* Looks for sections with SHF_LINK_ORDER set. Rearranges them into the same
+ order as their linked sections. Returns false if this could not be done
+ because an output section includes both ordered and unordered
+ sections. Ideally we'd do this in the linker proper. */
+
+static bfd_boolean
+elf_fixup_link_order (bfd *abfd, asection *o)
+{
+ int seen_linkorder;
+ int seen_other;
+ int n;
+ struct bfd_link_order *p;
+ bfd *sub;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ int elfsec;
+ struct bfd_link_order **sections;
+ asection *s;
+ bfd_vma offset;
+
+ seen_other = 0;
+ seen_linkorder = 0;
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour ((sub = p->u.indirect.section->owner))
+ == bfd_target_elf_flavour)
+ && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass)
+ {
+ s = p->u.indirect.section;
+ elfsec = _bfd_elf_section_from_bfd_section (sub, s);
+ if (elfsec != -1
+ && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER)
+ seen_linkorder++;
+ else
+ seen_other++;
+ }
+ else
+ seen_other++;
+ }
+
+ if (!seen_linkorder)
+ return TRUE;
+
+ if (seen_other && seen_linkorder)
+ {
+ (*_bfd_error_handler) (_("%A has both ordered and unordered sections"),
+ o);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ sections = (struct bfd_link_order **)
+ xmalloc (seen_linkorder * sizeof (struct bfd_link_order *));
+ seen_linkorder = 0;
+
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ sections[seen_linkorder++] = p;
+ }
+ /* Sort the input sections in the order of their linked section. */
+ qsort (sections, seen_linkorder, sizeof (struct bfd_link_order *),
+ compare_link_order);
+
+ /* Change the offsets of the sections. */
+ offset = 0;
+ for (n = 0; n < seen_linkorder; n++)
+ {
+ s = sections[n]->u.indirect.section;
+ offset &= ~(bfd_vma)((1 << s->alignment_power) - 1);
+ s->output_offset = offset;
+ sections[n]->offset = offset;
+ offset += sections[n]->size;
+ }
+
+ return TRUE;
+}
+
+
/* Do the final step of an ELF link. */
bfd_boolean
if (! _bfd_elf_compute_section_file_positions (abfd, info))
goto error_return;
- /* That created the reloc sections. Set their sizes, and assign
- them file positions, and allocate some buffers. */
+ /* Set sizes, and assign file positions for reloc sections. */
for (o = abfd->sections; o != NULL; o = o->next)
{
if ((o->flags & SEC_RELOC) != 0)
elf_hash_table (info)->tls_size = end - base;
}
+ /* Reorder SHF_LINK_ORDER sections. */
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if (!elf_fixup_link_order (abfd, o))
+ return FALSE;
+ }
+
/* Since ELF permits relocations to be against local symbols, we
must have the local symbols available when we do the relocations.
Since we would rather only read the local symbols once, and we
if (o == NULL)
{
(*_bfd_error_handler)
- (_("%s: could not find output section %s"),
- bfd_get_filename (abfd), name);
+ (_("%B: could not find output section %s"), abfd, name);
goto error_return;
}
if (o->size == 0)
if (o == NULL)
{
(*_bfd_error_handler)
- (_("%s: could not find output section %s"),
- bfd_get_filename (abfd), name);
+ (_("%B: could not find output section %s"), abfd, name);
goto error_return;
}
dyn.d_un.d_ptr = o->vma;
(asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *);
-static bfd_boolean
-elf_gc_mark (struct bfd_link_info *info,
- asection *sec,
- gc_mark_hook_fn gc_mark_hook)
+bfd_boolean
+_bfd_elf_gc_mark (struct bfd_link_info *info,
+ asection *sec,
+ gc_mark_hook_fn gc_mark_hook)
{
bfd_boolean ret;
asection *group_sec;
/* Mark all the sections in the group. */
group_sec = elf_section_data (sec)->next_in_group;
if (group_sec && !group_sec->gc_mark)
- if (!elf_gc_mark (info, group_sec, gc_mark_hook))
+ if (!_bfd_elf_gc_mark (info, group_sec, gc_mark_hook))
return FALSE;
/* Look through the section relocs. */
{
if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
rsec->gc_mark = 1;
- else if (!elf_gc_mark (info, rsec, gc_mark_hook))
+ else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
{
ret = FALSE;
goto out2;
for (o = sub->sections; o != NULL; o = o->next)
{
- /* Keep special sections. Keep .debug sections. */
- if ((o->flags & SEC_LINKER_CREATED)
- || (o->flags & SEC_DEBUGGING))
+ /* Keep debug and special sections. */
+ if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
+ || (o->flags & (SEC_ALLOC | SEC_LOAD)) == 0)
o->gc_mark = 1;
if (o->gc_mark)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
/* Those that are not vtables. */
- if (h->vtable_parent == NULL)
+ if (h->vtable == NULL || h->vtable->parent == NULL)
return TRUE;
/* Those vtables that do not have parents, we cannot merge. */
- if (h->vtable_parent == (struct elf_link_hash_entry *) -1)
+ if (h->vtable->parent == (struct elf_link_hash_entry *) -1)
return TRUE;
/* If we've already been done, exit. */
- if (h->vtable_entries_used && h->vtable_entries_used[-1])
+ if (h->vtable->used && h->vtable->used[-1])
return TRUE;
/* Make sure the parent's table is up to date. */
- elf_gc_propagate_vtable_entries_used (h->vtable_parent, okp);
+ elf_gc_propagate_vtable_entries_used (h->vtable->parent, okp);
- if (h->vtable_entries_used == NULL)
+ if (h->vtable->used == NULL)
{
/* None of this table's entries were referenced. Re-use the
parent's table. */
- h->vtable_entries_used = h->vtable_parent->vtable_entries_used;
- h->vtable_entries_size = h->vtable_parent->vtable_entries_size;
+ h->vtable->used = h->vtable->parent->vtable->used;
+ h->vtable->size = h->vtable->parent->vtable->size;
}
else
{
bfd_boolean *cu, *pu;
/* Or the parent's entries into ours. */
- cu = h->vtable_entries_used;
+ cu = h->vtable->used;
cu[-1] = TRUE;
- pu = h->vtable_parent->vtable_entries_used;
+ pu = h->vtable->parent->vtable->used;
if (pu != NULL)
{
const struct elf_backend_data *bed;
bed = get_elf_backend_data (h->root.u.def.section->owner);
log_file_align = bed->s->log_file_align;
- n = h->vtable_parent->vtable_entries_size >> log_file_align;
+ n = h->vtable->parent->vtable->size >> log_file_align;
while (n--)
{
if (*pu)
/* Take care of both those symbols that do not describe vtables as
well as those that are not loaded. */
- if (h->vtable_parent == NULL)
+ if (h->vtable == NULL || h->vtable->parent == NULL)
return TRUE;
BFD_ASSERT (h->root.type == bfd_link_hash_defined
if (rel->r_offset >= hstart && rel->r_offset < hend)
{
/* If the entry is in use, do nothing. */
- if (h->vtable_entries_used
- && (rel->r_offset - hstart) < h->vtable_entries_size)
+ if (h->vtable->used
+ && (rel->r_offset - hstart) < h->vtable->size)
{
bfd_vma entry = (rel->r_offset - hstart) >> log_file_align;
- if (h->vtable_entries_used[entry])
+ if (h->vtable->used[entry])
continue;
}
/* Otherwise, kill it. */
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC))
+ && h->ref_dynamic)
h->root.u.def.section->flags |= SEC_KEEP;
return TRUE;
EH frame section. */
if (strcmp (o->name, ".eh_frame") == 0)
o->gc_mark = 1;
- else if (!elf_gc_mark (info, o, gc_mark_hook))
+ else if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
}
}
goto win;
}
- (*_bfd_error_handler) ("%s: %s+%lu: No symbol found for INHERIT",
- bfd_archive_filename (abfd), sec->name,
- (unsigned long) offset);
+ (*_bfd_error_handler) ("%B: %A+%lu: No symbol found for INHERIT",
+ abfd, sec, (unsigned long) offset);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
win:
+ if (!child->vtable)
+ {
+ child->vtable = bfd_zalloc (abfd, sizeof (*child->vtable));
+ if (!child->vtable)
+ return FALSE;
+ }
if (!h)
{
/* This *should* only be the absolute section. It could potentially
would be bad. It isn't worth paging in the local symbols to be
sure though; that case should simply be handled by the assembler. */
- child->vtable_parent = (struct elf_link_hash_entry *) -1;
+ child->vtable->parent = (struct elf_link_hash_entry *) -1;
}
else
- child->vtable_parent = h;
+ child->vtable->parent = h;
return TRUE;
}
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
unsigned int log_file_align = bed->s->log_file_align;
- if (addend >= h->vtable_entries_size)
+ if (!h->vtable)
+ {
+ h->vtable = bfd_zalloc (abfd, sizeof (*h->vtable));
+ if (!h->vtable)
+ return FALSE;
+ }
+
+ if (addend >= h->vtable->size)
{
size_t size, bytes, file_align;
- bfd_boolean *ptr = h->vtable_entries_used;
+ bfd_boolean *ptr = h->vtable->used;
/* While the symbol is undefined, we have to be prepared to handle
a zero size. */
{
size_t oldbytes;
- oldbytes = (((h->vtable_entries_size >> log_file_align) + 1)
+ oldbytes = (((h->vtable->size >> log_file_align) + 1)
* sizeof (bfd_boolean));
memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes);
}
return FALSE;
/* And arrange for that done flag to be at index -1. */
- h->vtable_entries_used = ptr + 1;
- h->vtable_entries_size = size;
+ h->vtable->used = ptr + 1;
+ h->vtable->size = size;
}
- h->vtable_entries_used[addend >> log_file_align] = TRUE;
+ h->vtable->used[addend >> log_file_align] = TRUE;
return TRUE;
}
return ret;
}
+
+void
+_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
+{
+ flagword flags;
+ const char *name, *p;
+ struct bfd_section_already_linked *l;
+ struct bfd_section_already_linked_hash_entry *already_linked_list;
+ asection *group;
+
+ /* A single member comdat group section may be discarded by a
+ linkonce section. See below. */
+ if (sec->output_section == bfd_abs_section_ptr)
+ return;
+
+ flags = sec->flags;
+
+ /* Check if it belongs to a section group. */
+ group = elf_sec_group (sec);
+
+ /* Return if it isn't a linkonce section nor a member of a group. A
+ comdat group section also has SEC_LINK_ONCE set. */
+ if ((flags & SEC_LINK_ONCE) == 0 && group == NULL)
+ return;
+
+ if (group)
+ {
+ /* If this is the member of a single member comdat group, check if
+ the group should be discarded. */
+ if (elf_next_in_group (sec) == sec
+ && (group->flags & SEC_LINK_ONCE) != 0)
+ sec = group;
+ else
+ return;
+ }
+
+ /* FIXME: When doing a relocatable link, we may have trouble
+ copying relocations in other sections that refer to local symbols
+ in the section being discarded. Those relocations will have to
+ be converted somehow; as of this writing I'm not sure that any of
+ the backends handle that correctly.
+
+ It is tempting to instead not discard link once sections when
+ doing a relocatable link (technically, they should be discarded
+ whenever we are building constructors). However, that fails,
+ because the linker winds up combining all the link once sections
+ into a single large link once section, which defeats the purpose
+ of having link once sections in the first place.
+
+ Also, not merging link once sections in a relocatable link
+ causes trouble for MIPS ELF, which relies on link once semantics
+ to handle the .reginfo section correctly. */
+
+ name = bfd_get_section_name (abfd, sec);
+
+ if (strncmp (name, ".gnu.linkonce.", sizeof (".gnu.linkonce.") - 1) == 0
+ && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
+ p++;
+ else
+ p = name;
+
+ already_linked_list = bfd_section_already_linked_table_lookup (p);
+
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ {
+ /* We may have 3 different sections on the list: group section,
+ comdat section and linkonce section. SEC may be a linkonce or
+ group section. We match a group section with a group section,
+ a linkonce section with a linkonce section, and ignore comdat
+ section. */
+ if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
+ && strcmp (name, l->sec->name) == 0
+ && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+ {
+ /* The section has already been linked. See if we should
+ issue a warning. */
+ switch (flags & SEC_LINK_DUPLICATES)
+ {
+ default:
+ abort ();
+
+ case SEC_LINK_DUPLICATES_DISCARD:
+ break;
+
+ case SEC_LINK_DUPLICATES_ONE_ONLY:
+ (*_bfd_error_handler)
+ (_("%B: ignoring duplicate section `%A'\n"),
+ abfd, sec);
+ break;
+
+ case SEC_LINK_DUPLICATES_SAME_SIZE:
+ if (sec->size != l->sec->size)
+ (*_bfd_error_handler)
+ (_("%B: duplicate section `%A' has different size\n"),
+ abfd, sec);
+ break;
+
+ case SEC_LINK_DUPLICATES_SAME_CONTENTS:
+ if (sec->size != l->sec->size)
+ (*_bfd_error_handler)
+ (_("%B: duplicate section `%A' has different size\n"),
+ abfd, sec);
+ else if (sec->size != 0)
+ {
+ bfd_byte *sec_contents, *l_sec_contents;
+
+ if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents))
+ (*_bfd_error_handler)
+ (_("%B: warning: could not read contents of section `%A'\n"),
+ abfd, sec);
+ else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
+ &l_sec_contents))
+ (*_bfd_error_handler)
+ (_("%B: warning: could not read contents of section `%A'\n"),
+ l->sec->owner, l->sec);
+ else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
+ (*_bfd_error_handler)
+ (_("%B: warning: duplicate section `%A' has different contents\n"),
+ abfd, sec);
+
+ if (sec_contents)
+ free (sec_contents);
+ if (l_sec_contents)
+ free (l_sec_contents);
+ }
+ break;
+ }
+
+ /* Set the output_section field so that lang_add_section
+ does not create a lang_input_section structure for this
+ section. Since there might be a symbol in the section
+ being discarded, we must retain a pointer to the section
+ which we are really going to use. */
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = l->sec;
+
+ if (flags & SEC_GROUP)
+ {
+ asection *first = elf_next_in_group (sec);
+ asection *s = first;
+
+ while (s != NULL)
+ {
+ s->output_section = bfd_abs_section_ptr;
+ /* Record which group discards it. */
+ s->kept_section = l->sec;
+ s = elf_next_in_group (s);
+ /* These lists are circular. */
+ if (s == first)
+ break;
+ }
+ }
+
+ return;
+ }
+ }
+
+ if (group)
+ {
+ /* If this is the member of a single member comdat group and the
+ group hasn't be discarded, we check if it matches a linkonce
+ section. We only record the discarded comdat group. Otherwise
+ the undiscarded group will be discarded incorrectly later since
+ itself has been recorded. */
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ if ((l->sec->flags & SEC_GROUP) == 0
+ && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
+ && bfd_elf_match_symbols_in_sections (l->sec,
+ elf_next_in_group (sec)))
+ {
+ elf_next_in_group (sec)->output_section = bfd_abs_section_ptr;
+ elf_next_in_group (sec)->kept_section = l->sec;
+ group->output_section = bfd_abs_section_ptr;
+ break;
+ }
+ if (l == NULL)
+ return;
+ }
+ else
+ /* There is no direct match. But for linkonce section, we should
+ check if there is a match with comdat group member. We always
+ record the linkonce section, discarded or not. */
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ if (l->sec->flags & SEC_GROUP)
+ {
+ asection *first = elf_next_in_group (l->sec);
+
+ if (first != NULL
+ && elf_next_in_group (first) == first
+ && bfd_elf_match_symbols_in_sections (first, sec))
+ {
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = l->sec;
+ break;
+ }
+ }
+
+ /* This is the first section with this name. Record it. */
+ bfd_section_already_linked_table_insert (already_linked_list, sec);
+}