/* ELF linking support for BFD.
- Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
h->def_regular = 1;
h->non_elf = 0;
h->type = STT_OBJECT;
- h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+ if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+ h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
bed = get_elf_backend_data (abfd);
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
if (hidden)
{
bed = get_elf_backend_data (output_bfd);
- h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+ if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+ h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
static void
elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
- Elf_Internal_Sym *isym, bfd_boolean definition,
- bfd_boolean dynamic)
+ const Elf_Internal_Sym *isym,
+ 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. We never merge the visibility
- attribute with the one from a dynamic object. */
+ code might be needed here. */
if (bed->elf_backend_merge_symbol_attribute)
(*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 (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0)
- {
- unsigned char hvis, symvis, other, nvis;
-
- /* Only merge the visibility. Leave the remainder of the
- st_other field to elf_backend_merge_symbol_attribute. */
- other = h->other & ~ELF_ST_VISIBILITY (-1);
-
- /* Combine visibilities, using the most constraining one. */
- hvis = ELF_ST_VISIBILITY (h->other);
- symvis = ELF_ST_VISIBILITY (isym->st_other);
- if (! hvis)
- nvis = symvis;
- else if (! symvis)
- nvis = hvis;
- else
- nvis = hvis < symvis ? hvis : symvis;
-
- h->other = other | nvis;
- }
-}
-
-/* Mark if a symbol has a definition in a dynamic object or is
- weak in all dynamic objects. */
-
-static void
-_bfd_elf_mark_dynamic_def_weak (struct elf_link_hash_entry *h,
- asection *sec, int bind)
-{
- if (!h->dynamic_def)
+ if (!dynamic)
{
- if (!bfd_is_und_section (sec))
- 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->ref_dynamic)
- {
- if (bind == STB_WEAK)
- h->dynamic_weak = 1;
- }
- else if (bind != STB_WEAK)
- h->dynamic_weak = 0;
- }
+ unsigned symvis = ELF_ST_VISIBILITY (isym->st_other);
+ unsigned hvis = ELF_ST_VISIBILITY (h->other);
+
+ /* Keep the most constraining visibility. Leave the remainder
+ of the st_other field to elf_backend_merge_symbol_attribute. */
+ if (symvis - 1 < hvis - 1)
+ h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1));
}
}
-/* This function is called when we want to define a new symbol. It
- handles the various cases which arise when we find a definition in
- a dynamic object, or when there is already a definition in a
- dynamic object. The new symbol is described by NAME, SYM, PSEC,
- and PVALUE. We set SYM_HASH to the hash table entry. We set
- OVERRIDE if the old symbol is overriding a new definition. We set
- TYPE_CHANGE_OK if it is OK for the type to change. We set
- SIZE_CHANGE_OK if it is OK for the size to change. By OK to
- change, we mean that we shouldn't warn if the type or size does
- change. We set POLD_ALIGNMENT if an old common symbol in a dynamic
- object is overridden by a regular object. */
+/* This function is called when we want to merge a new symbol with an
+ existing symbol. It handles the various cases which arise when we
+ find a definition in a dynamic object, or when there is already a
+ definition in a dynamic object. The new symbol is described by
+ NAME, SYM, PSEC, and PVALUE. We set SYM_HASH to the hash table
+ entry. We set POLDBFD to the old symbol's BFD. We set POLD_WEAK
+ if the old symbol was weak. We set POLD_ALIGNMENT to the alignment
+ of an old common symbol. We set OVERRIDE if the old symbol is
+ overriding a new definition. We set TYPE_CHANGE_OK if it is OK for
+ the type to change. We set SIZE_CHANGE_OK if it is OK for the size
+ to change. By OK to change, we mean that we shouldn't warn if the
+ type or size does change. */
-bfd_boolean
+static bfd_boolean
_bfd_elf_merge_symbol (bfd *abfd,
struct bfd_link_info *info,
const char *name,
Elf_Internal_Sym *sym,
asection **psec,
bfd_vma *pvalue,
+ struct elf_link_hash_entry **sym_hash,
+ bfd **poldbfd,
bfd_boolean *pold_weak,
unsigned int *pold_alignment,
- struct elf_link_hash_entry **sym_hash,
bfd_boolean *skip,
bfd_boolean *override,
bfd_boolean *type_change_ok,
sec = *psec;
bind = ELF_ST_BIND (sym->st_info);
- /* Silently discard TLS symbols from --just-syms. There's no way to
- combine a static TLS block with a new TLS block for this executable. */
- if (ELF_ST_TYPE (sym->st_info) == STT_TLS
- && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
- {
- *skip = TRUE;
- return TRUE;
- }
-
if (! bfd_is_und_section (sec))
h = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, FALSE, FALSE);
else
bed = get_elf_backend_data (abfd);
- /* This code is for coping with dynamic objects, and is only useful
- if we are doing an ELF link. */
- if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
- return TRUE;
-
/* For merging, we only care about real symbols. But we need to make
sure that indirect symbol dynamic flags are updated. */
hi = h;
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- /* We have to check it for every instance since the first few may be
- refereences and not all compilers emit symbol type for undefined
- symbols. */
- bfd_elf_link_mark_dynamic_symbol (info, h, sym);
-
- /* If we just created the symbol, mark it as being an ELF symbol.
- Other than that, there is nothing to do--there is no merge issue
- with a newly defined symbol--so we just return. */
-
- if (h->root.type == bfd_link_hash_new)
- {
- h->non_elf = 0;
- return TRUE;
- }
-
/* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the
existing symbol. */
+ oldbfd = NULL;
+ oldsec = NULL;
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_common:
oldbfd = h->root.u.c.p->section->owner;
oldsec = h->root.u.c.p->section;
+ if (pold_alignment)
+ *pold_alignment = h->root.u.c.p->alignment_power;
break;
}
+ if (poldbfd && *poldbfd == NULL)
+ *poldbfd = oldbfd;
/* Differentiate strong and weak symbols. */
newweak = bind == STB_WEAK;
if (pold_weak)
*pold_weak = oldweak;
+ /* This code is for coping with dynamic objects, and is only useful
+ if we are doing an ELF link. */
+ if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
+ return TRUE;
+
+ /* We have to check it for every instance since the first few may be
+ references and not all compilers emit symbol type for undefined
+ symbols. */
+ bfd_elf_link_mark_dynamic_symbol (info, h, sym);
+
+ /* NEWDYN and OLDDYN indicate whether the new or old symbol,
+ respectively, is from a dynamic object. */
+
+ newdyn = (abfd->flags & DYNAMIC) != 0;
+
+ /* ref_dynamic_nonweak and dynamic_def flags track actual undefined
+ syms and defined syms in dynamic libraries respectively.
+ ref_dynamic on the other hand can be set for a symbol defined in
+ a dynamic library, and def_dynamic may not be set; When the
+ definition in a dynamic lib is overridden by a definition in the
+ executable use of the symbol in the dynamic lib becomes a
+ reference to the executable symbol. */
+ if (newdyn)
+ {
+ if (bfd_is_und_section (sec))
+ {
+ if (bind != STB_WEAK)
+ {
+ h->ref_dynamic_nonweak = 1;
+ hi->ref_dynamic_nonweak = 1;
+ }
+ }
+ else
+ {
+ h->dynamic_def = 1;
+ hi->dynamic_def = 1;
+ }
+ }
+
+ /* If we just created the symbol, mark it as being an ELF symbol.
+ Other than that, there is nothing to do--there is no merge issue
+ with a newly defined symbol--so we just return. */
+
+ if (h->root.type == bfd_link_hash_new)
+ {
+ h->non_elf = 0;
+ return TRUE;
+ }
+
/* In cases involving weak versioned symbols, we may wind up trying
to merge a symbol with itself. Catch that here, to avoid the
confusion that results if we try to override a symbol with
|| !h->def_regular))
return TRUE;
- /* NEWDYN and OLDDYN indicate whether the new or old symbol,
- respectively, is from a dynamic object. */
-
- newdyn = (abfd->flags & DYNAMIC) != 0;
-
olddyn = FALSE;
if (oldbfd != NULL)
olddyn = (oldbfd->flags & DYNAMIC) != 0;
/* When we try to create a default indirect symbol from the dynamic
definition with the default version, we skip it if its type and
- the type of existing regular definition mismatch. We only do it
- if the existing regular definition won't be dynamic. */
+ the type of existing regular definition mismatch. */
if (pold_alignment == NULL
- && !info->shared
- && !info->export_dynamic
- && !h->ref_dynamic
&& newdyn
&& newdef
&& !olddyn
- && (olddef || h->root.type == bfd_link_hash_common)
- && ELF_ST_TYPE (sym->st_info) != h->type
- && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
- && h->type != STT_NOTYPE
- && !(newfunc && oldfunc))
+ && (((olddef || h->root.type == bfd_link_hash_common)
+ && ELF_ST_TYPE (sym->st_info) != h->type
+ && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
+ && h->type != STT_NOTYPE
+ && !(newfunc && oldfunc))
+ || (olddef
+ && ((h->type == STT_GNU_IFUNC)
+ != (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))))
{
*skip = TRUE;
return TRUE;
}
- /* Plugin symbol type isn't currently set. Stop bogus errors. */
- if (oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0)
- *type_change_ok = TRUE;
-
- /* Check TLS symbol. We don't check undefined symbol introduced by
- "ld -u". */
- else if (oldbfd != NULL
- && ELF_ST_TYPE (sym->st_info) != h->type
- && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS))
+ /* Check TLS symbols. We don't check undefined symbols introduced
+ by "ld -u" which have no type (and oldbfd NULL), and we don't
+ check symbols from plugins because they also have no type. */
+ if (oldbfd != NULL
+ && (oldbfd->flags & BFD_PLUGIN) == 0
+ && (abfd->flags & BFD_PLUGIN) == 0
+ && ELF_ST_TYPE (sym->st_info) != h->type
+ && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS))
{
bfd *ntbfd, *tbfd;
bfd_boolean ntdef, tdef;
if (tdef && ntdef)
(*_bfd_error_handler)
- (_("%s: TLS definition in %B section %A mismatches non-TLS definition in %B section %A"),
+ (_("%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"),
+ (_("%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"),
+ (_("%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"),
+ (_("%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)
- {
- _bfd_elf_mark_dynamic_def_weak (h, sec, bind);
- if (h != hi)
- _bfd_elf_mark_dynamic_def_weak (hi, sec, bind);
- }
-
/* If the old symbol has non-default visibility, we ignore the new
definition from a dynamic object. */
if (newdyn
/* If the new symbol with non-default visibility comes from a
relocatable file and the old definition comes from a dynamic
object, we remove the old definition. */
- if ((*sym_hash)->root.type == bfd_link_hash_indirect)
+ if (hi->root.type == bfd_link_hash_indirect)
{
/* Handle the case where the old dynamic definition is
default versioned. We need to copy the symbol info from
was referenced before. */
if (h->ref_regular)
{
- struct elf_link_hash_entry *vh = *sym_hash;
-
- vh->root.type = h->root.type;
+ hi->root.type = h->root.type;
h->root.type = bfd_link_hash_indirect;
- (*bed->elf_backend_copy_indirect_symbol) (info, vh, h);
+ (*bed->elf_backend_copy_indirect_symbol) (info, hi, h);
- h->root.u.i.link = (struct bfd_link_hash_entry *) vh;
+ h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
{
/* If the new symbol is hidden or internal, completely undo
h->ref_dynamic = 1;
h->def_dynamic = 0;
- h->dynamic_def = 0;
/* FIXME: Should we check type and size for protected symbol? */
h->size = 0;
h->type = 0;
- h = vh;
+ h = hi;
}
else
- h = *sym_hash;
+ h = hi;
}
/* If the old symbol was undefined before, then it will still be
else
h->ref_dynamic = 1;
h->def_dynamic = 0;
- h->dynamic_def = 0;
/* FIXME: Should we check type and size for protected symbol? */
h->size = 0;
h->type = 0;
return TRUE;
}
- if (bind == STB_GNU_UNIQUE)
- h->unique_global = 1;
-
/* If a new weak symbol definition comes from a regular file and the
old symbol comes from a dynamic library, we treat the new one as
strong. Similarly, an old weak symbol definition from a regular
/* We now know everything about the old and new symbols. We ask the
backend to check if we can merge them. */
- if (bed->merge_symbol
- && !bed->merge_symbol (info, sym_hash, h, sym, psec, pvalue,
- pold_alignment, skip, override,
- type_change_ok, size_change_ok,
- &newdyn, &newdef, &newdyncommon, &newweak,
- abfd, &sec,
- &olddyn, &olddef, &olddyncommon, &oldweak,
- oldbfd, &oldsec))
- return FALSE;
+ if (bed->merge_symbol != NULL)
+ {
+ if (!bed->merge_symbol (h, sym, psec, newdef, olddef, oldbfd, oldsec))
+ return FALSE;
+ sec = *psec;
+ }
/* If both the old and the new symbols look like common symbols in a
dynamic object, set the size of the symbol to the larger of the
if (!(oldbfd != NULL
&& (oldbfd->flags & BFD_PLUGIN) != 0
&& (abfd->flags & BFD_PLUGIN) == 0))
- *skip = TRUE;
+ {
+ newdef = FALSE;
+ *skip = TRUE;
+ }
/* Merge st_other. If the symbol already has a dynamic index,
but visibility says it should not be visible, turn it into a
*type_change_ok = TRUE;
}
- if ((*sym_hash)->root.type == bfd_link_hash_indirect)
- flip = *sym_hash;
+ if (hi->root.type == bfd_link_hash_indirect)
+ flip = hi;
else
/* This union may have been set to be non-NULL when this symbol
was seen in a dynamic object. We must force the union to be
*size_change_ok = TRUE;
*type_change_ok = TRUE;
- if ((*sym_hash)->root.type == bfd_link_hash_indirect)
- flip = *sym_hash;
+ if (hi->root.type == bfd_link_hash_indirect)
+ flip = hi;
else
h->verinfo.vertree = NULL;
}
/* This function is called to create an indirect symbol from the
default for the symbol with the default version if needed. The
- symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE. We
+ symbol is described by H, NAME, SYM, SEC, and VALUE. We
set DYNSYM if the new indirect symbol is dynamic. */
static bfd_boolean
struct elf_link_hash_entry *h,
const char *name,
Elf_Internal_Sym *sym,
- asection **psec,
- bfd_vma *value,
- bfd_boolean *dynsym,
- bfd_boolean override)
+ asection *sec,
+ bfd_vma value,
+ bfd **poldbfd,
+ bfd_boolean *dynsym)
{
bfd_boolean type_change_ok;
bfd_boolean size_change_ok;
const struct elf_backend_data *bed;
bfd_boolean collect;
bfd_boolean dynamic;
+ bfd_boolean override;
char *p;
size_t len, shortlen;
- asection *sec;
+ asection *tmp_sec;
/* If this symbol has a version, and it is the default version, we
create an indirect symbol from the default name to the fully
if (p == NULL || p[1] != ELF_VER_CHR)
return TRUE;
- if (override)
- {
- /* We are overridden by an old definition. We need to check if we
- need to create the indirect symbol from the default name. */
- hi = elf_link_hash_lookup (elf_hash_table (info), name, TRUE,
- FALSE, FALSE);
- BFD_ASSERT (hi != NULL);
- if (hi == h)
- return TRUE;
- while (hi->root.type == bfd_link_hash_indirect
- || hi->root.type == bfd_link_hash_warning)
- {
- hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
- if (hi == h)
- return TRUE;
- }
- }
-
bed = get_elf_backend_data (abfd);
collect = bed->collect;
dynamic = (abfd->flags & DYNAMIC) != 0;
actually going to define an indirect symbol. */
type_change_ok = FALSE;
size_change_ok = FALSE;
- sec = *psec;
- if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
- NULL, NULL, &hi, &skip, &override,
+ tmp_sec = sec;
+ if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
+ &hi, poldbfd, NULL, NULL, &skip, &override,
&type_change_ok, &size_change_ok))
return FALSE;
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
(*bed->elf_backend_copy_indirect_symbol) (info, ht, hi);
+ /* 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. */
+ ht->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
+ hi->dynamic_def |= ht->dynamic_def;
+
/* See if the new flags lead us to realize that the symbol must
be dynamic. */
if (! *dynsym)
/* Once again, merge with any existing symbol. */
type_change_ok = FALSE;
size_change_ok = FALSE;
- sec = *psec;
- if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
- NULL, NULL, &hi, &skip, &override,
+ tmp_sec = sec;
+ if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
+ &hi, poldbfd, NULL, NULL, &skip, &override,
&type_change_ok, &size_change_ok))
return FALSE;
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;
/* See if the new flags lead us to realize that the symbol
must be dynamic. */
&& !h->def_regular
&& h->ref_regular
&& !h->def_dynamic
- && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
+ && (h->root.u.def.section->owner->flags & (DYNAMIC | BFD_PLUGIN)) == 0)
h->def_regular = 1;
/* If -Bsymbolic was used (which means to bind references to global
if (! bfd_check_format (abfd, bfd_object))
return FALSE;
- /* If we have already included the element containing this symbol in the
- link then we do not need to include it again. Just claim that any symbol
- it contains is not a definition, so that our caller will not decide to
- (re)include this element. */
- if (abfd->archive_pass)
- return FALSE;
-
/* Select the appropriate symbol table. */
if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
hdr = &elf_tdata (abfd)->symtab_hdr;
bfd_boolean do_it)
{
struct elf_link_hash_table *hash_table;
- bfd_size_type oldsize;
bfd_size_type strindex;
if (!_bfd_elf_link_create_dynstrtab (abfd, info))
return -1;
hash_table = elf_hash_table (info);
- oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
if (strindex == (bfd_size_type) -1)
return -1;
- if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
+ if (_bfd_elf_strtab_refcount (hash_table->dynstr, strindex) != 1)
{
asection *sdyn;
const struct elf_backend_data *bed;
on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
{
for (; needed != NULL; needed = needed->next)
- if (strcmp (soname, needed->name) == 0)
+ if ((elf_dyn_lib_class (needed->by) & DYN_AS_NEEDED) == 0
+ && strcmp (soname, needed->name) == 0)
return TRUE;
return FALSE;
return ibed->relocs_compatible == obed->relocs_compatible;
}
+/* Make a special call to the linker "notice" function to tell it that
+ we are about to handle an as-needed lib, or have finished
+ processing the lib. */
+
+bfd_boolean
+_bfd_elf_notice_as_needed (bfd *ibfd,
+ struct bfd_link_info *info,
+ enum notice_asneeded_action act)
+{
+ return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static bfd_boolean
unsigned int old_size = 0;
unsigned int old_count = 0;
void *old_tab = NULL;
- void *old_hash;
void *old_ent;
struct bfd_link_hash_entry *old_undefs = NULL;
struct bfd_link_hash_entry *old_undefs_tail = NULL;
long old_dynsymcount = 0;
+ bfd_size_type old_dynstr_size = 0;
size_t tabsize = 0;
- size_t hashsize = 0;
+ asection *s;
+ bfd_boolean just_syms;
htab = elf_hash_table (info);
bed = get_elf_backend_data (abfd);
symbol. This differs from .gnu.warning sections, which generate
warnings when they are included in an output file. */
/* PR 12761: Also generate this warning when building shared libraries. */
- if (info->executable || info->shared)
+ for (s = abfd->sections; s != NULL; s = s->next)
{
- asection *s;
+ const char *name;
- for (s = abfd->sections; s != NULL; s = s->next)
+ name = bfd_get_section_name (abfd, s);
+ if (CONST_STRNEQ (name, ".gnu.warning."))
{
- const char *name;
+ char *msg;
+ bfd_size_type sz;
- name = bfd_get_section_name (abfd, s);
- if (CONST_STRNEQ (name, ".gnu.warning."))
+ name += sizeof ".gnu.warning." - 1;
+
+ /* If this is a shared object, then look up the symbol
+ in the hash table. If it is there, and it is already
+ been defined, then we will not be using the entry
+ from this shared object, so we don't need to warn.
+ FIXME: If we see the definition in a regular object
+ later on, we will warn, but we shouldn't. The only
+ fix is to keep track of what warnings we are supposed
+ to emit, and then handle them all at the end of the
+ link. */
+ if (dynamic)
{
- char *msg;
- bfd_size_type sz;
-
- name += sizeof ".gnu.warning." - 1;
-
- /* If this is a shared object, then look up the symbol
- in the hash table. If it is there, and it is already
- been defined, then we will not be using the entry
- from this shared object, so we don't need to warn.
- FIXME: If we see the definition in a regular object
- later on, we will warn, but we shouldn't. The only
- fix is to keep track of what warnings we are supposed
- to emit, and then handle them all at the end of the
- link. */
- if (dynamic)
- {
- struct elf_link_hash_entry *h;
+ struct elf_link_hash_entry *h;
- h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE);
+ h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE);
- /* FIXME: What about bfd_link_hash_common? */
- if (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak))
- {
- /* We don't want to issue this warning. Clobber
- the section size so that the warning does not
- get copied into the output file. */
- s->size = 0;
- continue;
- }
- }
+ /* FIXME: What about bfd_link_hash_common? */
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
+ continue;
+ }
- sz = s->size;
- msg = (char *) bfd_alloc (abfd, sz + 1);
- if (msg == NULL)
- goto error_return;
+ sz = s->size;
+ msg = (char *) bfd_alloc (abfd, sz + 1);
+ if (msg == NULL)
+ goto error_return;
- if (! bfd_get_section_contents (abfd, s, msg, 0, sz))
- goto error_return;
+ if (! bfd_get_section_contents (abfd, s, msg, 0, sz))
+ goto error_return;
- msg[sz] = '\0';
+ msg[sz] = '\0';
- if (! (_bfd_generic_link_add_one_symbol
- (info, abfd, name, BSF_WARNING, s, 0, msg,
- FALSE, bed->collect, NULL)))
- goto error_return;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, BSF_WARNING, s, 0, msg,
+ FALSE, bed->collect, NULL)))
+ goto error_return;
- if (! info->relocatable)
- {
- /* Clobber the section size so that the warning does
- not get copied into the output file. */
- s->size = 0;
+ if (!info->relocatable && info->executable)
+ {
+ /* Clobber the section size so that the warning does
+ not get copied into the output file. */
+ s->size = 0;
- /* Also set SEC_EXCLUDE, so that symbols defined in
- the warning section don't get copied to the output. */
- s->flags |= SEC_EXCLUDE;
- }
+ /* Also set SEC_EXCLUDE, so that symbols defined in
+ the warning section don't get copied to the output. */
+ s->flags |= SEC_EXCLUDE;
}
}
}
+ just_syms = ((s = abfd->sections) != NULL
+ && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS);
+
add_needed = TRUE;
if (! dynamic)
{
/* If we are creating a shared library, create all the dynamic
sections immediately. We need to attach them to something,
so we attach them to this BFD, provided it is the right
- format. FIXME: If there are no input BFD's of the same
- format as the output, we can't make a shared library. */
- if (info->shared
+ format and is not from ld --just-symbols. FIXME: If there
+ are no input BFD's of the same format as the output, we can't
+ make a shared library. */
+ if (!just_syms
+ && info->shared
&& is_elf_hash_table (htab)
&& info->output_bfd->xvec == abfd->xvec
&& !htab->dynamic_sections_created)
goto error_return;
else
{
- asection *s;
const char *soname = NULL;
char *audit = NULL;
struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
/* ld --just-symbols and dynamic objects don't mix very well.
ld shouldn't allow it. */
- if ((s = abfd->sections) != NULL
- && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ if (just_syms)
abort ();
/* If this dynamic lib was specified on the command line with
return TRUE;
/* Save the DT_AUDIT entry for the linker emulation code. */
- elf_dt_audit (abfd) = audit;
+ elf_dt_audit (abfd) = audit;
}
/* If this is a dynamic object, we always link against the .dynsym
extsymoff = hdr->sh_info;
}
- sym_hash = NULL;
+ sym_hash = elf_sym_hashes (abfd);
if (extsymcount != 0)
{
isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
if (isymbuf == NULL)
goto error_return;
- /* We store a pointer to the hash table entry for each external
- symbol. */
- amt = extsymcount * sizeof (struct elf_link_hash_entry *);
- sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
if (sym_hash == NULL)
- goto error_free_sym;
- elf_sym_hashes (abfd) = sym_hash;
+ {
+ /* We store a pointer to the hash table entry for each
+ external symbol. */
+ amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+ sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt);
+ if (sym_hash == NULL)
+ goto error_free_sym;
+ elf_sym_hashes (abfd) = sym_hash;
+ }
}
if (dynamic)
}
tabsize = htab->root.table.size * sizeof (struct bfd_hash_entry *);
- hashsize = extsymcount * sizeof (struct elf_link_hash_entry *);
- old_tab = bfd_malloc (tabsize + entsize + hashsize);
+ old_tab = bfd_malloc (tabsize + entsize);
if (old_tab == NULL)
goto error_free_vers;
/* Make a special call to the linker "notice" function to
tell it that we are about to handle an as-needed lib. */
- if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
- notice_as_needed, 0, NULL))
+ if (!(*bed->notice_as_needed) (abfd, info, notice_as_needed))
goto error_free_vers;
- /* Clone the symbol table and sym hashes. Remember some
- pointers into the symbol table, and dynamic symbol count. */
- old_hash = (char *) old_tab + tabsize;
- old_ent = (char *) old_hash + hashsize;
+ /* Clone the symbol table. Remember some pointers into the
+ symbol table, and dynamic symbol count. */
+ old_ent = (char *) old_tab + tabsize;
memcpy (old_tab, htab->root.table.table, tabsize);
- memcpy (old_hash, sym_hash, hashsize);
old_undefs = htab->root.undefs;
old_undefs_tail = htab->root.undefs_tail;
old_table = htab->root.table.table;
old_size = htab->root.table.size;
old_count = htab->root.table.count;
old_dynsymcount = htab->dynsymcount;
+ old_dynstr_size = _bfd_elf_strtab_size (htab->dynstr);
for (i = 0; i < htab->root.table.size; i++)
{
bfd_boolean common;
unsigned int old_alignment;
bfd *old_bfd;
- bfd * undef_bfd = NULL;
override = FALSE;
flags = BSF_NO_FLAGS;
sec = NULL;
value = isym->st_value;
- *sym_hash = NULL;
common = bed->common_definition (isym);
bind = ELF_ST_BIND (isym->st_info);
goto error_free_vers;
}
+ /* Silently discard TLS symbols from --just-syms. There's
+ no way to combine a static TLS block with a new TLS block
+ for this executable. */
+ if (ELF_ST_TYPE (isym->st_info) == STT_TLS
+ && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ continue;
+
if (bfd_is_und_section (sec)
|| bfd_is_com_section (sec))
definition = FALSE;
unsigned int vernum = 0;
bfd_boolean skip;
- /* If this is a definition of a symbol which was previously
- referenced in a non-weak manner then make a note of the bfd
- that contained the reference. This is used if we need to
- refer to the source of the reference later on. */
- if (! bfd_is_und_section (sec))
- {
- h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
-
- if (h != NULL
- && h->root.type == bfd_link_hash_undefined
- && h->root.u.undef.abfd)
- undef_bfd = h->root.u.undef.abfd;
- }
-
if (ever == NULL)
{
if (info->default_imported_symver)
name = newname;
}
- /* If necessary, make a second attempt to locate the bfd
- containing an unresolved, non-weak reference to the
- current symbol. */
- if (! bfd_is_und_section (sec) && undef_bfd == NULL)
- {
- h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
-
- if (h != NULL
- && h->root.type == bfd_link_hash_undefined
- && h->root.u.undef.abfd)
- undef_bfd = h->root.u.undef.abfd;
- }
-
- if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
- &value, &old_weak, &old_alignment,
- sym_hash, &skip, &override,
+ /* 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 (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
+ sym_hash, &old_bfd, &old_weak,
+ &old_alignment, &skip, &override,
&type_change_ok, &size_change_ok))
goto error_free_vers;
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- /* Remember the old alignment if this is a common symbol, so
- that we don't reduce the alignment later on. We can't
- check later, because _bfd_generic_link_add_one_symbol
- will set a default for the alignment which we want to
- override. We also remember the old bfd where the existing
- definition comes from. */
- switch (h->root.type)
- {
- default:
- break;
-
- case bfd_link_hash_defined:
- case bfd_link_hash_defweak:
- old_bfd = h->root.u.def.section->owner;
- break;
-
- case bfd_link_hash_common:
- old_bfd = h->root.u.c.p->section->owner;
- old_alignment = h->root.u.c.p->alignment_power;
- break;
- }
-
if (elf_tdata (abfd)->verdef != NULL
- && ! override
&& vernum > 1
&& definition)
h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
h = (struct elf_link_hash_entry *) h->root.u.i.link;
*sym_hash = h;
- if (is_elf_hash_table (htab))
- h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
new_weak = (flags & BSF_WEAK) != 0;
new_weakdef = FALSE;
if (is_elf_hash_table (htab))
{
- bfd_boolean dynsym;
+ /* Set a flag in the hash table entry indicating the type of
+ reference or definition we just found. A dynamic symbol
+ is one which is referenced or defined by both a regular
+ 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. */
+ if ((abfd->flags & BFD_PLUGIN) != 0)
+ ;
+ else if (! dynamic)
+ {
+ if (! definition)
+ {
+ h->ref_regular = 1;
+ if (bind != STB_WEAK)
+ h->ref_regular_nonweak = 1;
+ }
+ else
+ {
+ h->def_regular = 1;
+ if (h->def_dynamic)
+ {
+ h->def_dynamic = 0;
+ 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)
+ && (! info->executable
+ || h->def_dynamic
+ || h->ref_dynamic))
+ dynsym = TRUE;
+ }
+ else
+ {
+ if (! definition)
+ {
+ h->ref_dynamic = 1;
+ hi->ref_dynamic = 1;
+ }
+ 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->u.weakdef != NULL
+ && ! new_weakdef
+ && h->u.weakdef->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 (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
+ sec, value, &old_bfd, &dynsym))
+ goto error_free_vers;
/* Check the alignment when a common symbol is involved. This
can change when a common symbol is overridden by a normal
bfd *normal_bfd;
bfd *common_bfd;
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak);
+
symbol_align = ffs (h->root.u.def.value) - 1;
if (h->root.u.def.section->owner != NULL
&& (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
/* PR binutils/2735 */
if (normal_bfd == NULL)
(*_bfd_error_handler)
- (_("Warning: alignment %u of common symbol `%s' in %B"
- " is greater than the alignment (%u) of its section %A"),
+ (_("Warning: alignment %u of common symbol `%s' in %B is"
+ " greater than the alignment (%u) of its section %A"),
common_bfd, h->root.u.def.section,
1 << common_align, name, 1 << normal_align);
else
}
/* Remember the symbol size if it isn't undefined. */
- if ((isym->st_size != 0 && isym->st_shndx != SHN_UNDEF)
+ if (isym->st_size != 0
+ && isym->st_shndx != SHN_UNDEF
&& (definition || h->size == 0))
{
if (h->size != 0
to be the size of the common symbol. The code just above
won't fix the size if a common symbol becomes larger. We
don't warn about a size change here, because that is
- covered by --warn-common. Allow changed between different
+ covered by --warn-common. Allow changes between different
function types. */
if (h->root.type == bfd_link_hash_common)
h->size = h->root.u.c.size;
/* Merge st_other field. */
elf_merge_st_other (abfd, h, isym, definition, dynamic);
- /* Set a flag in the hash table entry indicating the type of
- reference or definition we just found. Keep a count of
- 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. */
- dynsym = FALSE;
- if (! dynamic)
- {
- if (! definition)
- {
- h->ref_regular = 1;
- if (bind != STB_WEAK)
- h->ref_regular_nonweak = 1;
- }
- else
- {
- h->def_regular = 1;
- if (h->def_dynamic)
- {
- h->def_dynamic = 0;
- h->ref_dynamic = 1;
- /* PR 12549: Note if the dynamic reference is weak. */
- h->ref_dynamic_nonweak = (bind != STB_WEAK);
- }
- }
-
- /* If the indirect symbol has been forced local, don't
- make the real symbol dynamic. */
- if ((h == hi || !hi->forced_local)
- && (! info->executable
- || h->def_dynamic
- || h->ref_dynamic))
- dynsym = TRUE;
- }
- else
- {
- if (! definition)
- {
- h->ref_dynamic = 1;
- hi->ref_dynamic = 1;
- /* PR 12549: Note if the dynamic reference is weak. */
- hi->ref_dynamic_nonweak =
- h->ref_dynamic_nonweak = (bind != STB_WEAK);
- }
- else
- {
- h->def_dynamic = 1;
- h->dynamic_def = 1;
- hi->def_dynamic = 1;
- hi->dynamic_def = 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->u.weakdef != NULL
- && ! new_weakdef
- && h->u.weakdef->dynindx != -1)))
- dynsym = TRUE;
- }
-
/* We don't want to make debug symbol dynamic. */
if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
dynsym = FALSE;
dynsym = FALSE;
if (definition)
- h->target_internal = isym->st_target_internal;
-
- /* 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_add_default_symbol (abfd, info, h, name, isym,
- &sec, &value, &dynsym,
- override))
- goto error_free_vers;
+ {
+ h->target_internal = isym->st_target_internal;
+ h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
+ }
if (definition && !dynamic)
{
break;
}
+ /* Don't add DT_NEEDED for references from the dummy bfd. */
if (!add_needed
&& definition
&& ((dynsym
- && h->ref_regular_nonweak)
+ && h->ref_regular_nonweak
+ && (old_bfd == NULL
+ || (old_bfd->flags & BFD_PLUGIN) == 0))
|| (h->ref_dynamic_nonweak
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
&& !on_needed_list (elf_dt_name (abfd), htab->needed))))
int ret;
const char *soname = elf_dt_name (abfd);
+ info->callbacks->minfo ("%!", soname, old_bfd,
+ h->root.root.string);
+
/* 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. Issue an error if
--no-add-needed is used and the reference was not
a weak one. */
- if (undef_bfd != NULL
+ if (old_bfd != NULL
&& (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0)
{
(*_bfd_error_handler)
(_("%B: undefined reference to symbol '%s'"),
- undef_bfd, name);
- (*_bfd_error_handler)
- (_("note: '%s' is defined in DSO %B so try adding it to the linker command line"),
- abfd, name);
- bfd_set_error (bfd_error_invalid_operation);
+ old_bfd, name);
+ bfd_set_error (bfd_error_missing_dso);
goto error_free_vers;
}
unsigned int i;
/* Restore the symbol table. */
- if (bed->as_needed_cleanup)
- (*bed->as_needed_cleanup) (abfd, info);
- old_hash = (char *) old_tab + tabsize;
- old_ent = (char *) old_hash + hashsize;
- sym_hash = elf_sym_hashes (abfd);
+ old_ent = (char *) old_tab + tabsize;
+ memset (elf_sym_hashes (abfd), 0,
+ extsymcount * sizeof (struct elf_link_hash_entry *));
htab->root.table.table = old_table;
htab->root.table.size = old_size;
htab->root.table.count = old_count;
memcpy (htab->root.table.table, old_tab, tabsize);
- memcpy (sym_hash, old_hash, hashsize);
htab->root.undefs = old_undefs;
htab->root.undefs_tail = old_undefs_tail;
+ _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size);
for (i = 0; i < htab->root.table.size; i++)
{
struct bfd_hash_entry *p;
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;
- if (h->dynindx >= old_dynsymcount)
+ if (h->dynindx >= old_dynsymcount
+ && h->dynstr_index < old_dynstr_size)
_bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
/* 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 the run-time by another
+ since it can still be loaded at run time by another
dynamic lib. */
if (h->root.type == bfd_link_hash_common)
{
{
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;
}
- else if (h->root.type == bfd_link_hash_common)
+ if (h->root.type == bfd_link_hash_common)
{
if (size > h->root.u.c.size)
h->root.u.c.size = size;
/* Make a special call to the linker "notice" function to
tell it that symbols added for crefs may need to be removed. */
- if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
- notice_not_needed, 0, NULL))
+ if (!(*bed->notice_as_needed) (abfd, info, notice_not_needed))
goto error_free_vers;
free (old_tab);
if (old_tab != NULL)
{
- if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
- notice_needed, 0, NULL))
+ if (!(*bed->notice_as_needed) (abfd, info, notice_needed))
goto error_free_vers;
free (old_tab);
old_tab = NULL;
struct elf_link_hash_entry *hlook;
asection *slook;
bfd_vma vlook;
- size_t i, j, idx;
+ size_t i, j, idx = 0;
hlook = weaks;
weaks = hlook->u.weakdef;
}
/* 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
- archive which includes an entry libc.so.1 which defines a bunch of
- symbols. The libc.so archive also includes a number of other
- object files, which also define symbols, some of which are the same
- as those defined in libc.so.1. Correct linking requires that we
- consider each object file in turn, and include it if it defines any
- symbols we need. _bfd_generic_link_add_archive_symbols does not do
- this; it looks through the list of undefined symbols, and includes
- any object file which defines them. When this algorithm is used on
- UnixWare, it winds up pulling in libc.so.1 early and defining a
- bunch of symbols. This means that some of the other objects in the
- archive are not included in the link, which is incorrect since they
- precede libc.so.1 in the archive.
+ don't use _bfd_generic_link_add_archive_symbols because we need to
+ handle versioned symbols.
Fortunately, ELF archive handling is simpler than that done by
_bfd_generic_link_add_archive_symbols, which has to allow for a.out
elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
{
symindex c;
- bfd_boolean *defined = NULL;
- bfd_boolean *included = NULL;
+ unsigned char *included = NULL;
carsym *symdefs;
bfd_boolean loop;
bfd_size_type amt;
if (c == 0)
return TRUE;
amt = c;
- amt *= sizeof (bfd_boolean);
- defined = (bfd_boolean *) bfd_zmalloc (amt);
- included = (bfd_boolean *) bfd_zmalloc (amt);
- if (defined == NULL || included == NULL)
- goto error_return;
+ amt *= sizeof (*included);
+ included = (unsigned char *) bfd_zmalloc (amt);
+ if (included == NULL)
+ return FALSE;
symdefs = bfd_ardata (abfd)->symdefs;
bed = get_elf_backend_data (abfd);
struct bfd_link_hash_entry *undefs_tail;
symindex mark;
- if (defined[i] || included[i])
+ if (included[i])
continue;
if (symdef->file_offset == last)
{
else if (h->root.type != bfd_link_hash_undefined)
{
if (h->root.type != bfd_link_hash_undefweak)
- defined[i] = TRUE;
+ /* Symbol must be defined. Don't check it again. */
+ included[i] = TRUE;
continue;
}
if (! bfd_check_format (element, bfd_object))
goto error_return;
- /* Doublecheck that we have not included this object
- already--it should be impossible, but there may be
- something wrong with the archive. */
- if (element->archive_pass != 0)
- {
- bfd_set_error (bfd_error_bad_value);
- goto error_return;
- }
- element->archive_pass = 1;
-
undefs_tail = info->hash->undefs_tail;
if (!(*info->callbacks
}
while (loop);
- free (defined);
free (included);
return TRUE;
error_return:
- if (defined != NULL)
- free (defined);
if (included != NULL)
free (included);
return FALSE;
{
bfd *ibfd;
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
&& !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr))
return FALSE;
/* Determine any GNU_STACK segment requirements, after the backend
has had a chance to set a default segment size. */
if (info->execstack)
- elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
+ elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
else if (info->noexecstack)
- elf_tdata (output_bfd)->stack_flags = PF_R | PF_W;
+ elf_stack_flags (output_bfd) = PF_R | PF_W;
else
{
bfd *inputobj;
for (inputobj = info->input_bfds;
inputobj;
- inputobj = inputobj->link_next)
+ inputobj = inputobj->link.next)
{
asection *s;
exec = PF_X;
}
if (notesec || info->stacksize > 0)
- elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec;
+ elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
if (notesec && exec && info->relocatable
&& notesec->output_section != bfd_abs_section_ptr)
notesec->output_section->flags |= SEC_CODE;
if (rpath != NULL)
{
bfd_size_type indx;
+ bfd_vma tag;
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
TRUE);
- if (indx == (bfd_size_type) -1
- || !_bfd_elf_add_dynamic_entry (info, DT_RPATH, indx))
+ if (indx == (bfd_size_type) -1)
return FALSE;
- if (info->new_dtags)
- {
- _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx);
- if (!_bfd_elf_add_dynamic_entry (info, DT_RUNPATH, indx))
- return FALSE;
- }
+ tag = info->new_dtags ? DT_RUNPATH : DT_RPATH;
+ if (!_bfd_elf_add_dynamic_entry (info, tag, indx))
+ return FALSE;
}
if (filter_shlib != NULL)
asection *o;
for (sub = info->input_bfds; sub != NULL;
- sub = sub->link_next)
+ sub = sub->link.next)
if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
for (o = sub->sections; o != NULL; o = o->next)
if (elf_section_data (o)->this_hdr.sh_type
if (!is_elf_hash_table (info->hash))
return FALSE;
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
if ((ibfd->flags & DYNAMIC) == 0)
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
if ((sec->flags & SEC_MERGE) != 0
}
}
-/* Initialize an ELF linker hash table. */
+/* Initialize an ELF linker hash table. *TABLE has been zeroed by our
+ caller. */
bfd_boolean
_bfd_elf_link_hash_table_init
bfd_boolean ret;
int can_refcount = get_elf_backend_data (abfd)->can_refcount;
- memset (table, 0, sizeof * table);
table->init_got_refcount.refcount = can_refcount - 1;
table->init_plt_refcount.refcount = can_refcount - 1;
table->init_got_offset.offset = -(bfd_vma) 1;
struct elf_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf_link_hash_table);
- ret = (struct elf_link_hash_table *) bfd_malloc (amt);
+ ret = (struct elf_link_hash_table *) bfd_zmalloc (amt);
if (ret == NULL)
return NULL;
free (ret);
return NULL;
}
+ ret->root.hash_table_free = _bfd_elf_link_hash_table_free;
return &ret->root;
}
+/* Destroy an ELF linker hash table. */
+
+void
+_bfd_elf_link_hash_table_free (bfd *obfd)
+{
+ struct elf_link_hash_table *htab;
+
+ htab = (struct elf_link_hash_table *) obfd->link.hash;
+ if (htab->dynstr != NULL)
+ _bfd_elf_strtab_free (htab->dynstr);
+ _bfd_merge_sections_free (htab->merge_info);
+ _bfd_generic_link_hash_table_free (obfd);
+}
+
/* This is a hook for the ELF emulation code in the generic linker to
tell the backend linker what file name to use for the DT_NEEDED
entry for a dynamic object. */
bfd_boolean localsyms;
bfd_boolean need_second_pass;
bfd_boolean second_pass;
+ bfd_boolean file_sym_done;
struct elf_final_link_info *flinfo;
};
bfd *input_bfd,
bfd_byte *location)
{
+ int shift;
bfd_vma x = 0;
+ /* Sanity checks. */
+ BFD_ASSERT (chunksz <= sizeof (x)
+ && size >= chunksz
+ && chunksz != 0
+ && (size % chunksz) == 0
+ && input_bfd != NULL
+ && location != NULL);
+
+ if (chunksz == sizeof (x))
+ {
+ BFD_ASSERT (size == chunksz);
+
+ /* Make sure that we do not perform an undefined shift operation.
+ We know that size == chunksz so there will only be one iteration
+ of the loop below. */
+ shift = 0;
+ }
+ else
+ shift = 8 * chunksz;
+
for (; size; size -= chunksz, location += chunksz)
{
switch (chunksz)
{
- default:
- case 0:
- abort ();
case 1:
- x = (x << (8 * chunksz)) | bfd_get_8 (input_bfd, location);
+ x = (x << shift) | bfd_get_8 (input_bfd, location);
break;
case 2:
- x = (x << (8 * chunksz)) | bfd_get_16 (input_bfd, location);
+ x = (x << shift) | bfd_get_16 (input_bfd, location);
break;
case 4:
- x = (x << (8 * chunksz)) | bfd_get_32 (input_bfd, location);
+ x = (x << shift) | bfd_get_32 (input_bfd, location);
break;
- case 8:
#ifdef BFD64
- x = (x << (8 * chunksz)) | bfd_get_64 (input_bfd, location);
-#else
- abort ();
-#endif
+ case 8:
+ x = (x << shift) | bfd_get_64 (input_bfd, location);
break;
+#endif
+ default:
+ abort ();
}
}
return x;
{
const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A;
const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B;
- int copya, copyb;
- if (a->u.offset < b->u.offset)
+ if (a->type < b->type)
return -1;
- if (a->u.offset > b->u.offset)
+ if (a->type > b->type)
return 1;
- copya = (a->type == reloc_class_copy) * 2 + (a->type == reloc_class_plt);
- copyb = (b->type == reloc_class_copy) * 2 + (b->type == reloc_class_plt);
- if (copya < copyb)
+ if (a->u.offset < b->u.offset)
return -1;
- if (copya > copyb)
+ if (a->u.offset > b->u.offset)
return 1;
if (a->rela->r_offset < b->rela->r_offset)
return -1;
struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
(*swap_in) (abfd, erel, s->rela);
- s->type = (*bed->elf_backend_reloc_type_class) (s->rela);
+ s->type = (*bed->elf_backend_reloc_type_class) (info, o, s->rela);
s->u.sym_mask = r_sym_mask;
p += sort_elt;
erel += ext_size;
|| h->root.type == bfd_link_hash_defweak)
&& h->root.u.def.section->output_section != NULL))
return TRUE;
+
+ if (!eoinfo->file_sym_done
+ && (eoinfo->second_pass ? eoinfo->flinfo->filesym_count == 1
+ : eoinfo->flinfo->filesym_count > 1))
+ {
+ /* Output a FILE symbol so that following locals are not associated
+ with the wrong input file. */
+ memset (&sym, 0, sizeof (sym));
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+ sym.st_shndx = SHN_ABS;
+ if (!elf_link_output_sym (eoinfo->flinfo, NULL, &sym,
+ bfd_und_section_ptr, NULL))
+ return FALSE;
+
+ eoinfo->file_sym_done = TRUE;
+ }
}
else
{
&& h->ref_dynamic
&& h->def_regular
&& !h->dynamic_def
- && !h->dynamic_weak
+ && h->ref_dynamic_nonweak
&& !elf_link_check_versioned_symbol (flinfo->info, bed, h))
{
bfd *def_bfd;
/* Turn off visibility on local symbol. */
sym.st_other &= ~ELF_ST_VISIBILITY (-1);
}
- else if (h->unique_global)
+ /* Set STB_GNU_UNIQUE only if symbol is defined in regular object. */
+ else if (h->unique_global && h->def_regular)
sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type);
else if (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_defweak)
file, so the contents field will not have been set by any of
the routines which work on output files. */
if (elf_section_data (o)->this_hdr.contents != NULL)
- contents = elf_section_data (o)->this_hdr.contents;
+ {
+ contents = elf_section_data (o)->this_hdr.contents;
+ if (bed->caches_rawsize
+ && o->rawsize != 0
+ && o->rawsize < o->size)
+ {
+ memcpy (flinfo->contents, contents, o->rawsize);
+ contents = flinfo->contents;
+ }
+ }
else
{
contents = flinfo->contents;
return TRUE;
}
+static void
+elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo)
+{
+ asection *o;
+
+ if (flinfo->symstrtab != NULL)
+ _bfd_stringtab_free (flinfo->symstrtab);
+ if (flinfo->contents != NULL)
+ free (flinfo->contents);
+ if (flinfo->external_relocs != NULL)
+ free (flinfo->external_relocs);
+ if (flinfo->internal_relocs != NULL)
+ free (flinfo->internal_relocs);
+ if (flinfo->external_syms != NULL)
+ free (flinfo->external_syms);
+ if (flinfo->locsym_shndx != NULL)
+ free (flinfo->locsym_shndx);
+ if (flinfo->internal_syms != NULL)
+ free (flinfo->internal_syms);
+ if (flinfo->indices != NULL)
+ free (flinfo->indices);
+ if (flinfo->sections != NULL)
+ free (flinfo->sections);
+ if (flinfo->symbuf != NULL)
+ free (flinfo->symbuf);
+ if (flinfo->symshndxbuf != NULL)
+ free (flinfo->symshndxbuf);
+ for (o = obfd->sections; o != NULL; o = o->next)
+ {
+ struct bfd_elf_section_data *esdo = elf_section_data (o);
+ if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL)
+ free (esdo->rel.hashes);
+ if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL)
+ free (esdo->rela.hashes);
+ }
+}
/* Do the final step of an ELF link. */
esdo->rela.count = 0;
}
- _bfd_elf_assign_file_positions_for_relocs (abfd);
-
/* We have now assigned file positions for all the sections except
- .symtab and .strtab. We start the .symtab section at the current
- file position, and write directly to it. We build the .strtab
- section in memory. */
+ .symtab, .strtab, and non-loaded reloc sections. We start the
+ .symtab section at the current file position, and write directly
+ to it. We build the .strtab section in memory. */
bfd_get_symcount (abfd) = 0;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
/* sh_name is set in prep_headers. */
/* sh_offset is set just below. */
symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
- off = elf_tdata (abfd)->next_file_pos;
+ off = elf_next_file_pos (abfd);
off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
- /* Note that at this point elf_tdata (abfd)->next_file_pos is
+ /* Note that at this point elf_next_file_pos (abfd) is
incorrect. We do not yet know the size of the .symtab section.
We correct next_file_pos below, after we do know the size. */
we could write the relocs out and then read them again; I don't
know how bad the memory loss will be. */
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
sub->output_has_begun = FALSE;
for (o = abfd->sections; o != NULL; o = o->next)
{
/* Free symbol buffer if needed. */
if (!info->reduce_memory_overheads)
{
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
if (bfd_get_flavour (sub) == bfd_target_elf_flavour
&& elf_tdata (sub)->symbuf)
{
}
}
- /* Output a FILE symbol so that following locals are not associated
- with the wrong input file. */
- memset (&elfsym, 0, sizeof (elfsym));
- elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
- elfsym.st_shndx = SHN_ABS;
-
- if (flinfo.filesym_count > 1
- && !elf_link_output_sym (&flinfo, NULL, &elfsym,
- bfd_und_section_ptr, NULL))
- return FALSE;
-
/* 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.localsyms = TRUE;
eoinfo.need_second_pass = FALSE;
eoinfo.second_pass = FALSE;
+ eoinfo.file_sym_done = FALSE;
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
return FALSE;
- if (flinfo.filesym_count == 1
- && !elf_link_output_sym (&flinfo, NULL, &elfsym,
- bfd_und_section_ptr, NULL))
- return FALSE;
-
if (eoinfo.need_second_pass)
{
eoinfo.second_pass = TRUE;
symstrtab_hdr->sh_addralign = 1;
off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, TRUE);
- elf_tdata (abfd)->next_file_pos = off;
+ elf_next_file_pos (abfd) = off;
if (bfd_get_symcount (abfd) > 0)
{
goto error_return;
}
- if (info->eh_frame_hdr)
- {
- if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
- goto error_return;
- }
+ if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
+ goto error_return;
- if (flinfo.symstrtab != NULL)
- _bfd_stringtab_free (flinfo.symstrtab);
- if (flinfo.contents != NULL)
- free (flinfo.contents);
- if (flinfo.external_relocs != NULL)
- free (flinfo.external_relocs);
- if (flinfo.internal_relocs != NULL)
- free (flinfo.internal_relocs);
- if (flinfo.external_syms != NULL)
- free (flinfo.external_syms);
- if (flinfo.locsym_shndx != NULL)
- free (flinfo.locsym_shndx);
- if (flinfo.internal_syms != NULL)
- free (flinfo.internal_syms);
- if (flinfo.indices != NULL)
- free (flinfo.indices);
- if (flinfo.sections != NULL)
- free (flinfo.sections);
- if (flinfo.symbuf != NULL)
- free (flinfo.symbuf);
- if (flinfo.symshndxbuf != NULL)
- free (flinfo.symshndxbuf);
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- struct bfd_elf_section_data *esdo = elf_section_data (o);
- if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL)
- free (esdo->rel.hashes);
- if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL)
- free (esdo->rela.hashes);
- }
+ elf_final_link_free (abfd, &flinfo);
- elf_tdata (abfd)->linker = TRUE;
+ elf_linker (abfd) = TRUE;
if (attr_section)
{
return TRUE;
error_return:
- if (flinfo.symstrtab != NULL)
- _bfd_stringtab_free (flinfo.symstrtab);
- if (flinfo.contents != NULL)
- free (flinfo.contents);
- if (flinfo.external_relocs != NULL)
- free (flinfo.external_relocs);
- if (flinfo.internal_relocs != NULL)
- free (flinfo.internal_relocs);
- if (flinfo.external_syms != NULL)
- free (flinfo.external_syms);
- if (flinfo.locsym_shndx != NULL)
- free (flinfo.locsym_shndx);
- if (flinfo.internal_syms != NULL)
- free (flinfo.internal_syms);
- if (flinfo.indices != NULL)
- free (flinfo.indices);
- if (flinfo.sections != NULL)
- free (flinfo.sections);
- if (flinfo.symbuf != NULL)
- free (flinfo.symbuf);
- if (flinfo.symshndxbuf != NULL)
- free (flinfo.symshndxbuf);
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- struct bfd_elf_section_data *esdo = elf_section_data (o);
- if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL)
- free (esdo->rel.hashes);
- if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL)
- free (esdo->rela.hashes);
- }
-
+ elf_final_link_free (abfd, &flinfo);
return FALSE;
}
\f
if (sec_name && *sec_name != '\0')
{
bfd *i;
-
- for (i = info->input_bfds; i; i = i->link_next)
+
+ for (i = info->input_bfds; i; i = i->link.next)
{
sec = bfd_get_section_by_name (i, sec_name);
if (sec)
{
bfd *ibfd;
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
asection *isec;
bfd_boolean some_kept;
+ bfd_boolean debug_frag_seen;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
continue;
- /* Ensure all linker created sections are kept, and see whether
- any other section is already marked. */
- some_kept = FALSE;
+ /* Ensure all linker created sections are kept,
+ see if any other section is already marked,
+ and note if we have any fragmented debug sections. */
+ debug_frag_seen = some_kept = FALSE;
for (isec = ibfd->sections; isec != NULL; isec = isec->next)
{
if ((isec->flags & SEC_LINKER_CREATED) != 0)
isec->gc_mark = 1;
else if (isec->gc_mark)
some_kept = TRUE;
+
+ if (debug_frag_seen == FALSE
+ && (isec->flags & SEC_DEBUGGING)
+ && CONST_STRNEQ (isec->name, ".debug_line."))
+ debug_frag_seen = TRUE;
}
/* If no section in this file will be kept, then we can
- toss out debug sections. */
+ toss out the debug and special sections. */
if (!some_kept)
continue;
&& ((isec->flags & SEC_DEBUGGING) != 0
|| (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0))
isec->gc_mark = 1;
+
+ if (! debug_frag_seen)
+ continue;
+
+ /* Look for CODE sections which are going to be discarded,
+ and find and discard any fragmented debug sections which
+ are associated with that code section. */
+ for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+ if ((isec->flags & SEC_CODE) != 0
+ && isec->gc_mark == 0)
+ {
+ unsigned int ilen;
+ asection *dsec;
+
+ ilen = strlen (isec->name);
+
+ /* Association is determined by the name of the debug section
+ containing the name of the code section as a suffix. For
+ example .debug_line.text.foo is a debug section associated
+ with .text.foo. */
+ for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next)
+ {
+ unsigned int dlen;
+
+ if (dsec->gc_mark == 0
+ || (dsec->flags & SEC_DEBUGGING) == 0)
+ continue;
+
+ dlen = strlen (dsec->name);
+
+ if (dlen > ilen
+ && strncmp (dsec->name + (dlen - ilen),
+ isec->name, ilen) == 0)
+ {
+ dsec->gc_mark = 0;
+ break;
+ }
+ }
+ }
}
return TRUE;
}
unsigned long section_sym_count;
struct elf_gc_sweep_symbol_info sweep_info;
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *o;
info we collected before. */
if (gc_sweep_hook
&& (o->flags & SEC_RELOC) != 0
- && o->reloc_count > 0
+ && o->reloc_count != 0
+ && !((info->strip == strip_all || info->strip == strip_debugger)
+ && (o->flags & SEC_DEBUGGING) != 0)
&& !bfd_is_abs_section (o->output_section))
{
Elf_Internal_Rela *internal_relocs;
bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ struct bfd_elf_dynamic_list *d = info->dynamic_list;
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->ref_dynamic
- || ((!info->executable || info->export_dynamic)
- && h->def_regular
+ || (h->def_regular
&& ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
+ && (!info->executable
+ || info->export_dynamic
+ || (h->dynamic
+ && d != NULL
+ && (*d->match) (&d->head, NULL, h->root.root.string)))
&& (strchr (h->root.root.string, ELF_VER_CHR) != NULL
|| !bfd_hide_sym_by_version (info->version_info,
h->root.root.string)))))
bfd *sub;
elf_gc_mark_hook_fn gc_mark_hook;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct elf_link_hash_table *htab;
if (!bed->can_gc_sections
|| !is_elf_hash_table (info->hash))
}
bed->gc_keep (info);
+ htab = elf_hash_table (info);
/* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section
at the .eh_frame section if we can mark the FDEs individually. */
- _bfd_elf_begin_eh_frame_parsing (info);
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *sec;
struct elf_reloc_cookie cookie;
sec = bfd_get_next_section_by_name (sec);
}
}
- _bfd_elf_end_eh_frame_parsing (info);
/* Apply transitive closure to the vtable entry usage info. */
- elf_link_hash_traverse (elf_hash_table (info),
- elf_gc_propagate_vtable_entries_used,
- &ok);
+ elf_link_hash_traverse (htab, elf_gc_propagate_vtable_entries_used, &ok);
if (!ok)
return FALSE;
/* Kill the vtable relocations that were not used. */
- elf_link_hash_traverse (elf_hash_table (info),
- elf_gc_smash_unused_vtentry_relocs,
- &ok);
+ elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok);
if (!ok)
return FALSE;
/* Mark dynamically referenced symbols. */
- if (elf_hash_table (info)->dynamic_sections_created)
- elf_link_hash_traverse (elf_hash_table (info),
- bed->gc_mark_dynamic_ref,
- info);
+ if (htab->dynamic_sections_created)
+ elf_link_hash_traverse (htab, bed->gc_mark_dynamic_ref, info);
/* Grovel through relocs to find out who stays ... */
gc_mark_hook = bed->gc_mark_hook;
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *o;
}
if (!tf->valid)
{
- info->callbacks->einfo
+ info->callbacks->einfo
(_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name);
return FALSE;
}
gotoff = bed->got_header_size;
/* Do the local .got entries first. */
- for (i = info->input_bfds; i; i = i->link_next)
+ for (i = info->input_bfds; i; i = i->link.next)
{
bfd_signed_vma *local_got;
bfd_size_type j, locsymcount;
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && discarded_section (h->root.u.def.section))
+ && (h->root.u.def.section->owner != rcookie->abfd
+ || h->root.u.def.section->kept_section != NULL
+ || discarded_section (h->root.u.def.section)))
return TRUE;
- else
- return FALSE;
}
else
{
/* Need to: get the symbol; get the section. */
isym = &rcookie->locsyms[r_symndx];
isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
- if (isec != NULL && discarded_section (isec))
+ if (isec != NULL
+ && (isec->kept_section != NULL
+ || discarded_section (isec)))
return TRUE;
}
return FALSE;
}
/* Discard unneeded references to discarded sections.
- Returns TRUE if any section's size was changed. */
-/* This function assumes that the relocations are in sorted order,
- which is true for all known assemblers. */
+ Returns -1 on error, 1 if any section's size was changed, 0 if
+ nothing changed. This function assumes that the relocations are in
+ sorted order, which is true for all known assemblers. */
-bfd_boolean
+int
bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
{
struct elf_reloc_cookie cookie;
- asection *stab, *eh;
- const struct elf_backend_data *bed;
+ asection *o;
bfd *abfd;
- bfd_boolean ret = FALSE;
+ int changed = 0;
if (info->traditional_format
|| !is_elf_hash_table (info->hash))
- return FALSE;
+ return 0;
- _bfd_elf_begin_eh_frame_parsing (info);
- for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ o = bfd_get_section_by_name (output_bfd, ".stab");
+ if (o != NULL)
{
- if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
- continue;
-
- bed = get_elf_backend_data (abfd);
+ asection *i;
- eh = NULL;
- if (!info->relocatable)
+ for (i = o->map_head.s; i != NULL; i = i->map_head.s)
{
- eh = bfd_get_section_by_name (abfd, ".eh_frame");
- while (eh != NULL
- && (eh->size == 0
- || bfd_is_abs_section (eh->output_section)))
- eh = bfd_get_next_section_by_name (eh);
- }
-
- stab = bfd_get_section_by_name (abfd, ".stab");
- if (stab != NULL
- && (stab->size == 0
- || bfd_is_abs_section (stab->output_section)
- || stab->sec_info_type != SEC_INFO_TYPE_STABS))
- stab = NULL;
+ if (i->size == 0
+ || i->reloc_count == 0
+ || i->sec_info_type != SEC_INFO_TYPE_STABS)
+ continue;
- if (stab == NULL
- && eh == NULL
- && bed->elf_backend_discard_info == NULL)
- continue;
+ abfd = i->owner;
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
- if (!init_reloc_cookie (&cookie, info, abfd))
- return FALSE;
+ if (!init_reloc_cookie_for_section (&cookie, info, i))
+ return -1;
- if (stab != NULL
- && stab->reloc_count > 0
- && init_reloc_cookie_rels (&cookie, info, abfd, stab))
- {
- if (_bfd_discard_section_stabs (abfd, stab,
- elf_section_data (stab)->sec_info,
+ if (_bfd_discard_section_stabs (abfd, i,
+ elf_section_data (i)->sec_info,
bfd_elf_reloc_symbol_deleted_p,
&cookie))
- ret = TRUE;
- fini_reloc_cookie_rels (&cookie, stab);
+ changed = 1;
+
+ fini_reloc_cookie_for_section (&cookie, i);
}
+ }
+
+ o = bfd_get_section_by_name (output_bfd, ".eh_frame");
+ if (o != NULL)
+ {
+ asection *i;
- while (eh != NULL
- && init_reloc_cookie_rels (&cookie, info, abfd, eh))
+ for (i = o->map_head.s; i != NULL; i = i->map_head.s)
{
- _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
- if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
+ if (i->size == 0)
+ continue;
+
+ abfd = i->owner;
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
+
+ if (!init_reloc_cookie_for_section (&cookie, info, i))
+ return -1;
+
+ _bfd_elf_parse_eh_frame (abfd, info, i, &cookie);
+ if (_bfd_elf_discard_section_eh_frame (abfd, info, i,
bfd_elf_reloc_symbol_deleted_p,
&cookie))
- ret = TRUE;
- fini_reloc_cookie_rels (&cookie, eh);
- eh = bfd_get_next_section_by_name (eh);
+ changed = 1;
+
+ fini_reloc_cookie_for_section (&cookie, i);
}
+ }
- if (bed->elf_backend_discard_info != NULL
- && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
- ret = TRUE;
+ for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
+ {
+ const struct elf_backend_data *bed;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
+
+ bed = get_elf_backend_data (abfd);
- fini_reloc_cookie (&cookie, abfd);
+ if (bed->elf_backend_discard_info != NULL)
+ {
+ if (!init_reloc_cookie (&cookie, info, abfd))
+ return -1;
+
+ if ((*bed->elf_backend_discard_info) (abfd, &cookie, info))
+ changed = 1;
+
+ fini_reloc_cookie (&cookie, abfd);
+ }
}
- _bfd_elf_end_eh_frame_parsing (info);
if (info->eh_frame_hdr
&& !info->relocatable
&& _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info))
- ret = TRUE;
+ changed = 1;
- return ret;
+ return changed;
}
bfd_boolean
return NULL;
name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1);
- sprintf (name, "%s%s", prefix, old_name);
+ sprintf (name, "%s%s", prefix, old_name);
return name;
}
reloc_sec = bfd_make_section_anyway_with_flags (dynobj, name, flags);
if (reloc_sec != NULL)
{
+ /* _bfd_elf_get_sec_type_attr chooses a section type by
+ name. Override as it may be wrong, eg. for a user
+ section named "auto" we'll get ".relauto" which is
+ seen to be a .rela section. */
+ elf_section_type (reloc_sec) = is_rela ? SHT_RELA : SHT_REL;
if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))
reloc_sec = NULL;
}
return reloc_sec;
}
-/* Copy the ELF symbol type associated with a linker hash entry. */
+/* Copy the ELF symbol type and other attributes for a linker script
+ assignment from HSRC to HDEST. Generally this should be treated as
+ if we found a strong non-dynamic definition for HDEST (except that
+ ld ignores multiple definition errors). */
void
-_bfd_elf_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_hash_entry * hdest,
- struct bfd_link_hash_entry * hsrc)
+_bfd_elf_copy_link_hash_symbol_type (bfd *abfd,
+ struct bfd_link_hash_entry *hdest,
+ struct bfd_link_hash_entry *hsrc)
{
- struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *)hdest;
- struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc;
+ struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *) hdest;
+ struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *) hsrc;
+ Elf_Internal_Sym isym;
ehdest->type = ehsrc->type;
ehdest->target_internal = ehsrc->target_internal;
+
+ isym.st_other = ehsrc->other;
+ elf_merge_st_other (abfd, ehdest, &isym, TRUE, FALSE);
}
/* Append a RELA relocation REL to section S in BFD. */
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rel);
BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size);
- bed->s->swap_reloca_out (abfd, rel, loc);
+ bed->s->swap_reloc_out (abfd, rel, loc);
}