/* ELF linking support for BFD.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
struct elf_info_failed
{
struct bfd_link_info *info;
- struct bfd_elf_version_tree *verdefs;
bfd_boolean failed;
};
struct elf_link_hash_table *htab = elf_hash_table (info);
/* This function may be called more than once. */
- s = bfd_get_section_by_name (abfd, ".got");
- if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0)
+ s = bfd_get_linker_section (abfd, ".got");
+ if (s != NULL)
return TRUE;
flags = bed->dynamic_sec_flags;
- s = bfd_make_section_with_flags (abfd,
- (bed->rela_plts_and_copies_p
- ? ".rela.got" : ".rel.got"),
- (bed->dynamic_sec_flags
- | SEC_READONLY));
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.got" : ".rel.got"),
+ (bed->dynamic_sec_flags
+ | SEC_READONLY));
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
htab->srelgot = s;
- s = bfd_make_section_with_flags (abfd, ".got", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (s == NULL
|| !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
if (bed->want_got_plt)
{
- s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
if (s == NULL
|| !bfd_set_section_alignment (abfd, s,
bed->s->log_file_align))
flagword flags;
asection *s;
const struct elf_backend_data *bed;
+ struct elf_link_hash_entry *h;
if (! is_elf_hash_table (info->hash))
return FALSE;
shared library does not. */
if (info->executable)
{
- s = bfd_make_section_with_flags (abfd, ".interp",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".interp",
+ flags | SEC_READONLY);
if (s == NULL)
return FALSE;
}
/* Create sections to hold version informations. These are removed
if they are not needed. */
- s = bfd_make_section_with_flags (abfd, ".gnu.version_d",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".gnu.version",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, 1))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".gnu.version_r",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_r",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".dynsym",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynsym",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".dynstr",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynstr",
+ flags | SEC_READONLY);
if (s == NULL)
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".dynamic", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", flags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
section. We don't want to define it if there is no .dynamic
section, since on some ELF platforms the start up code examines it
to decide how to initialize the process. */
- if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC"))
+ h = _bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC");
+ elf_hash_table (info)->hdynamic = h;
+ if (h == NULL)
return FALSE;
if (info->emit_hash)
{
- s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".hash",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
if (info->emit_gnu_hash)
{
- s = bfd_make_section_with_flags (abfd, ".gnu.hash",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
- s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
return FALSE;
return FALSE;
}
- s = bfd_make_section_with_flags (abfd,
- (bed->rela_plts_and_copies_p
- ? ".rela.plt" : ".rel.plt"),
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.plt" : ".rel.plt"),
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
image and use a R_*_COPY reloc to tell the dynamic linker to
initialize them at run time. The linker script puts the .dynbss
section into the .bss section of the final image. */
- s = bfd_make_section_with_flags (abfd, ".dynbss",
- (SEC_ALLOC
- | SEC_LINKER_CREATED));
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynbss",
+ (SEC_ALLOC | SEC_LINKER_CREATED));
if (s == NULL)
return FALSE;
copy relocs. */
if (! info->shared)
{
- s = bfd_make_section_with_flags (abfd,
- (bed->rela_plts_and_copies_p
- ? ".rela.bss" : ".rel.bss"),
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.bss" : ".rel.bss"),
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
h->def_regular = 1;
- if (provide && hidden)
+ if (hidden)
{
bed = get_elf_backend_data (output_bfd);
h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
asection *ip;
if (htab->dynobj != NULL
- && (ip = bfd_get_section_by_name (htab->dynobj, p->name)) != NULL
- && (ip->flags & SEC_LINKER_CREATED)
+ && (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL
&& ip->output_section == p)
return TRUE;
}
}
}
+/* 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 (!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;
+ }
+ }
+}
+
/* 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
Elf_Internal_Sym *sym,
asection **psec,
bfd_vma *pvalue,
+ bfd_boolean *pold_weak,
unsigned int *pold_alignment,
struct elf_link_hash_entry **sym_hash,
bfd_boolean *skip,
{
asection *sec, *oldsec;
struct elf_link_hash_entry *h;
+ struct elf_link_hash_entry *hi;
struct elf_link_hash_entry *flip;
int bind;
bfd *oldbfd;
/* 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 == ELF_INFO_TYPE_JUST_SYMS)
+ && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
{
*skip = TRUE;
return TRUE;
if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
return TRUE;
- /* For merging, we only care about real symbols. */
-
+ /* For merging, we only care about real symbols. But we need to make
+ sure that indirect symbol dynamic flags are updated. */
+ hi = h;
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;
newweak = bind == STB_WEAK;
oldweak = (h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_undefweak);
+ if (pold_weak)
+ *pold_weak = oldweak;
/* In cases involving weak versioned symbols, we may wind up trying
to merge a symbol with itself. Catch that here, to avoid the
/* 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->dynamic_def)
+ if (newdyn)
{
- 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;
- }
+ _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
*skip = TRUE;
/* Make sure this symbol is dynamic. */
h->ref_dynamic = 1;
+ hi->ref_dynamic = 1;
/* A protected symbol has external availability. Make sure it is
recorded as dynamic.
vh->root.type = h->root.type;
h->root.type = bfd_link_hash_indirect;
(*bed->elf_backend_copy_indirect_symbol) (info, vh, h);
- /* Protected symbols will override the dynamic definition
- with default version. */
- if (ELF_ST_VISIBILITY (sym->st_other) == STV_PROTECTED)
+
+ h->root.u.i.link = (struct bfd_link_hash_entry *) vh;
+ if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
{
- h->root.u.i.link = (struct bfd_link_hash_entry *) vh;
- vh->dynamic_def = 1;
- vh->ref_dynamic = 1;
+ /* If the new symbol is hidden or internal, completely undo
+ any dynamic link state. */
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ h->forced_local = 0;
+ h->ref_dynamic = 0;
}
else
- {
- h->root.type = vh->root.type;
- vh->ref_dynamic = 0;
- /* We have to hide it here since it was made dynamic
- global with extra bits when the symbol info was
- copied from the old dynamic definition. */
- (*bed->elf_backend_hide_symbol) (info, vh, TRUE);
- }
+ 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;
}
else
h = *sym_hash;
}
- if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root)
- && bfd_is_und_section (sec))
+ /* If the old symbol was undefined before, then it will still be
+ on the undefs list. If the new symbol is undefined or
+ common, we can't make it bfd_link_hash_new here, because new
+ undefined or common symbols will be added to the undefs list
+ by _bfd_generic_link_add_one_symbol. Symbols may not be
+ added twice to the undefs list. Also, if the new symbol is
+ undefweak then we don't want to lose the strong undef. */
+ if (h->root.u.undef.next || info->hash->undefs_tail == &h->root)
{
- /* 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
- definition came from a dynamic object, it is still on the
- undefs list. */
h->root.type = bfd_link_hash_undefined;
h->root.u.undef.abfd = abfd;
}
h->root.u.undef.abfd = NULL;
}
- if (h->def_dynamic)
+ if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
{
- h->def_dynamic = 0;
- h->ref_dynamic = 1;
- h->dynamic_def = 1;
+ /* If the new symbol is hidden or internal, completely undo
+ any dynamic link state. */
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ h->forced_local = 0;
+ h->ref_dynamic = 0;
}
+ 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;
size_change_ok = FALSE;
sec = *psec;
if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
- NULL, &hi, &skip, &override,
+ NULL, NULL, &hi, &skip, &override,
&type_change_ok, &size_change_ok))
return FALSE;
if (! dynamic)
{
if (! info->executable
+ || hi->def_dynamic
|| hi->ref_dynamic)
*dynsym = TRUE;
}
size_change_ok = FALSE;
sec = *psec;
if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
- NULL, &hi, &skip, &override,
+ NULL, NULL, &hi, &skip, &override,
&type_change_ok, &size_change_ok))
return FALSE;
return TRUE;
if (h->dynindx == -1
- && (h->def_regular
- || h->ref_regular))
+ && (h->def_regular || h->ref_regular)
+ && ! bfd_hide_sym_by_version (eif->info->version_info,
+ h->root.root.string))
{
- bfd_boolean hide;
-
- if (eif->verdefs == NULL
- || (bfd_find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
- && !hide))
+ if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
{
- if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
- {
- eif->failed = TRUE;
- return FALSE;
- }
+ eif->failed = TRUE;
+ return FALSE;
}
}
}
/* Look for the version. If we find it, it is no longer weak. */
- for (t = sinfo->verdefs; t != NULL; t = t->next)
+ for (t = sinfo->info->version_info; t != NULL; t = t->next)
{
if (strcmp (t->name, p) == 0)
{
version_index = 1;
/* Don't count anonymous version tag. */
- if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0)
+ if (sinfo->info->version_info != NULL
+ && sinfo->info->version_info->vernum == 0)
version_index = 0;
- for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
+ for (pp = &sinfo->info->version_info;
+ *pp != NULL;
+ pp = &(*pp)->next)
++version_index;
t->vernum = version_index;
/* If we don't have a version for this symbol, see if we can find
something. */
- if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
+ if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL)
{
bfd_boolean hide;
- h->verinfo.vertree = bfd_find_version_for_sym (sinfo->verdefs,
- h->root.root.string, &hide);
+ h->verinfo.vertree
+ = bfd_find_version_for_sym (sinfo->info->version_info,
+ h->root.root.string, &hide);
if (h->verinfo.vertree != NULL && hide)
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
over to the real definition. */
if (h->u.weakdef != NULL)
{
- struct elf_link_hash_entry *weakdef;
-
- weakdef = h->u.weakdef;
- if (h->root.type == bfd_link_hash_indirect)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- BFD_ASSERT (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak);
- 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->def_regular)
+ if (h->u.weakdef->def_regular)
h->u.weakdef = NULL;
else
{
+ struct elf_link_hash_entry *weakdef = h->u.weakdef;
+
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak);
+ BFD_ASSERT (weakdef->def_dynamic);
BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
|| weakdef->root.type == bfd_link_hash_defweak);
(*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h);
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->U.WEAKDEF before it finds H? */
+ /* If we get to this point, there is an implicit reference to
+ H->U.WEAKDEF by a regular object file via the weak symbol H. */
h->u.weakdef->ref_regular = 1;
+ /* Ensure that the backend adjust_dynamic_symbol function sees
+ H->U.WEAKDEF before H by recursively calling ourselves. */
if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif))
return FALSE;
}
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& ((sec = h->root.u.def.section)->flags & SEC_MERGE)
- && sec->sec_info_type == ELF_INFO_TYPE_MERGE)
+ && sec->sec_info_type == SEC_INFO_TYPE_MERGE)
{
bfd *output_bfd = (bfd *) data;
return FALSE;
bed = get_elf_backend_data (hash_table->dynobj);
- s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
+ s = bfd_get_linker_section (hash_table->dynobj, ".dynamic");
BFD_ASSERT (s != NULL);
newsize = s->size + bed->s->sizeof_dyn;
bfd_byte *extdyn;
bed = get_elf_backend_data (hash_table->dynobj);
- sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
+ sdyn = bfd_get_linker_section (hash_table->dynobj, ".dynamic");
if (sdyn != NULL)
for (extdyn = sdyn->contents;
extdyn < sdyn->contents + sdyn->size;
return FALSE;
}
-/* Sort symbol by value and section. */
+/* Sort symbol by value, section, and size. */
static int
elf_sort_symbol (const void *arg1, const void *arg2)
{
if (sdiff != 0)
return sdiff > 0 ? 1 : -1;
}
- return 0;
+ vdiff = h1->size - h2->size;
+ return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1;
}
/* This function is used to adjust offsets into .dynstr for
size = _bfd_elf_strtab_size (dynstr);
bed = get_elf_backend_data (dynobj);
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic");
BFD_ASSERT (sdyn != NULL);
/* Update all .dynamic entries referencing .dynstr strings. */
Elf_Internal_Verdef def;
Elf_Internal_Verdaux defaux;
- s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+ s = bfd_get_linker_section (dynobj, ".gnu.version_d");
p = s->contents;
do
{
Elf_Internal_Verneed need;
Elf_Internal_Vernaux needaux;
- s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+ s = bfd_get_linker_section (dynobj, ".gnu.version_r");
p = s->contents;
do
{
/* 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 == ELF_INFO_TYPE_JUST_SYMS)
+ && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
abort ();
/* If this dynamic lib was specified on the command line with
flagword flags;
const char *name;
struct elf_link_hash_entry *h;
+ struct elf_link_hash_entry *hi;
bfd_boolean definition;
bfd_boolean size_change_ok;
bfd_boolean type_change_ok;
bfd_boolean new_weakdef;
+ bfd_boolean new_weak;
+ bfd_boolean old_weak;
bfd_boolean override;
bfd_boolean common;
unsigned int old_alignment;
sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (sec == NULL)
sec = bfd_abs_section_ptr;
- else if (sec->kept_section)
+ else if (discarded_section (sec))
{
/* Symbols from discarded section are undefined. We keep
its visibility. */
size_change_ok = FALSE;
type_change_ok = bed->type_change_ok;
+ old_weak = FALSE;
old_alignment = 0;
old_bfd = NULL;
new_sec = sec;
}
if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
- &value, &old_alignment,
+ &value, &old_weak, &old_alignment,
sym_hash, &skip, &override,
&type_change_ok, &size_change_ok))
goto error_free_vers;
goto error_free_vers;
h = *sym_hash;
+ /* We need to make sure that indirect symbol dynamic flags are
+ updated. */
+ hi = h;
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;
if (is_elf_hash_table (htab))
h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
+ new_weak = (flags & BSF_WEAK) != 0;
new_weakdef = FALSE;
if (dynamic
&& definition
- && (flags & BSF_WEAK) != 0
+ && new_weak
&& !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
&& is_elf_hash_table (htab)
&& h->u.weakdef == NULL)
h->size = h->root.u.c.size;
if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
- && (definition || h->type == STT_NOTYPE))
+ && ((definition && !new_weak)
+ || (old_weak && h->root.type == bfd_link_hash_common)
+ || h->type == STT_NOTYPE))
{
unsigned int type = ELF_ST_TYPE (isym->st_info);
{
h->def_dynamic = 0;
h->ref_dynamic = 1;
- h->dynamic_def = 1;
}
}
- if (! info->executable
- || h->def_dynamic
- || h->ref_dynamic)
+
+ /* 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;
+ {
+ h->ref_dynamic = 1;
+ hi->ref_dynamic = 1;
+ }
else
- h->def_dynamic = 1;
- if (h->def_regular
- || h->ref_regular
- || (h->u.weakdef != NULL
- && ! new_weakdef
- && h->u.weakdef->dynindx != -1))
+ {
+ 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)
- {
- /* We don't want to make debug symbol dynamic. */
- dynsym = FALSE;
- }
+ dynsym = FALSE;
+
+ /* Nor should we make plugin symbols dynamic. */
+ if ((abfd->flags & BFD_PLUGIN) != 0)
+ dynsym = FALSE;
if (definition)
h->target_internal = isym->st_target_internal;
{
struct bfd_hash_entry *p;
struct elf_link_hash_entry *h;
+ bfd_size_type size;
+ unsigned int alignment_power;
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
if (h->dynindx >= old_dynsymcount)
_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
+ dynamic lib. */
+ if (h->root.type == bfd_link_hash_common)
+ {
+ size = h->root.u.c.size;
+ alignment_power = h->root.u.c.p->alignment_power;
+ }
+ else
+ {
+ size = 0;
+ alignment_power = 0;
+ }
memcpy (p, old_ent, htab->root.table.entsize);
old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) p;
memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
old_ent = (char *) old_ent + htab->root.table.entsize;
}
+ else if (h->root.type == bfd_link_hash_common)
+ {
+ if (size > h->root.u.c.size)
+ h->root.u.c.size = size;
+ if (alignment_power > h->root.u.c.p->alignment_power)
+ h->root.u.c.p->alignment_power = alignment_power;
+ }
}
}
struct elf_link_hash_entry *hlook;
asection *slook;
bfd_vma vlook;
- long ilook;
size_t i, j, idx;
hlook = weaks;
slook = hlook->root.u.def.section;
vlook = hlook->root.u.def.value;
- ilook = -1;
i = 0;
j = sym_count;
- while (i < j)
+ while (i != j)
{
bfd_signed_vma vdiff;
idx = (i + j) / 2;
- h = sorted_sym_hash [idx];
+ h = sorted_sym_hash[idx];
vdiff = vlook - h->root.u.def.value;
if (vdiff < 0)
j = idx;
else if (sdiff > 0)
i = idx + 1;
else
- {
- ilook = idx;
- break;
- }
+ break;
}
}
/* We didn't find a value/section match. */
- if (ilook == -1)
+ if (i == j)
continue;
- for (i = ilook; i < sym_count; i++)
+ /* With multiple aliases, or when the weak symbol is already
+ strongly defined, we have multiple matching symbols and
+ the binary search above may land on any of them. Step
+ one past the matching symbol(s). */
+ while (++idx != j)
{
- h = sorted_sym_hash [i];
+ h = sorted_sym_hash[idx];
+ if (h->root.u.def.section != slook
+ || h->root.u.def.value != vlook)
+ break;
+ }
+
+ /* Now look back over the aliases. Since we sorted by size
+ as well as value and section, we'll choose the one with
+ the largest size. */
+ while (idx-- != i)
+ {
+ h = sorted_sym_hash[idx];
/* Stop if value or section doesn't match. */
- if (h->root.u.def.value != vlook
- || h->root.u.def.section != slook)
+ if (h->root.u.def.section != slook
+ || h->root.u.def.value != vlook)
break;
else if (h != hlook)
{
&string_offset))
goto error_return;
if (secdata->sec_info)
- stab->sec_info_type = ELF_INFO_TYPE_STABS;
+ stab->sec_info_type = SEC_INFO_TYPE_STABS;
}
}
}
return TRUE;
}
+/* Set a default stack segment size. The value in INFO wins. If it
+ is unset, LEGACY_SYMBOL's value is used, and if that symbol is
+ undefined it is initialized. */
+
+bfd_boolean
+bfd_elf_stack_segment_size (bfd *output_bfd,
+ struct bfd_link_info *info,
+ const char *legacy_symbol,
+ bfd_vma default_size)
+{
+ struct elf_link_hash_entry *h = NULL;
+
+ /* Look for legacy symbol. */
+ if (legacy_symbol)
+ h = elf_link_hash_lookup (elf_hash_table (info), legacy_symbol,
+ FALSE, FALSE, FALSE);
+ if (h && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->def_regular
+ && (h->type == STT_NOTYPE || h->type == STT_OBJECT))
+ {
+ /* The symbol has no type if specified on the command line. */
+ h->type = STT_OBJECT;
+ if (info->stacksize)
+ (*_bfd_error_handler) (_("%B: stack size specified and %s set"),
+ output_bfd, legacy_symbol);
+ else if (h->root.u.def.section != bfd_abs_section_ptr)
+ (*_bfd_error_handler) (_("%B: %s not absolute"),
+ output_bfd, legacy_symbol);
+ else
+ info->stacksize = h->root.u.def.value;
+ }
+
+ if (!info->stacksize)
+ /* If the user didn't set a size, or explicitly inhibit the
+ size, set it now. */
+ info->stacksize = default_size;
+
+ /* Provide the legacy symbol, if it is referenced. */
+ if (h && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
+ {
+ struct bfd_link_hash_entry *bh = NULL;
+
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, output_bfd, legacy_symbol,
+ BSF_GLOBAL, bfd_abs_section_ptr,
+ info->stacksize >= 0 ? info->stacksize : 0,
+ NULL, FALSE, get_elf_backend_data (output_bfd)->collect, &bh)))
+ return FALSE;
+
+ h = (struct elf_link_hash_entry *) bh;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+ }
+
+ return TRUE;
+}
+
/* Set up the sizes and contents of the ELF dynamic sections. This is
called by the ELF linker emulation before_allocation routine. We
must set the sizes of the sections before the linker sets the
const char *depaudit,
const char * const *auxiliary_filters,
struct bfd_link_info *info,
- asection **sinterpptr,
- struct bfd_elf_version_tree *verdefs)
+ asection **sinterpptr)
{
bfd_size_type soname_indx;
bfd *dynobj;
return TRUE;
bed = get_elf_backend_data (output_bfd);
+
+ /* Any syms created from now on start with -1 in
+ got.refcount/offset and plt.refcount/offset. */
+ elf_hash_table (info)->init_got_refcount
+ = elf_hash_table (info)->init_got_offset;
+ elf_hash_table (info)->init_plt_refcount
+ = elf_hash_table (info)->init_plt_offset;
+
+ if (info->relocatable
+ && !_bfd_elf_size_group_sections (info))
+ return FALSE;
+
+ /* The backend may have to create some sections regardless of whether
+ we're dynamic or not. */
+ if (bed->elf_backend_always_size_sections
+ && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
+ 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;
else if (info->noexecstack)
{
asection *s;
- if (inputobj->flags & (DYNAMIC | EXEC_P | BFD_LINKER_CREATED))
+ if (inputobj->flags
+ & (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED))
continue;
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
if (s)
else if (bed->default_execstack)
exec = PF_X;
}
- if (notesec)
- {
- elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec;
- if (exec && info->relocatable
- && notesec->output_section != bfd_abs_section_ptr)
- notesec->output_section->flags |= SEC_CODE;
- }
+ if (notesec || info->stacksize > 0)
+ elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec;
+ if (notesec && exec && info->relocatable
+ && notesec->output_section != bfd_abs_section_ptr)
+ notesec->output_section->flags |= SEC_CODE;
}
- /* Any syms created from now on start with -1 in
- got.refcount/offset and plt.refcount/offset. */
- elf_hash_table (info)->init_got_refcount
- = elf_hash_table (info)->init_got_offset;
- elf_hash_table (info)->init_plt_refcount
- = elf_hash_table (info)->init_plt_offset;
-
- if (info->relocatable
- && !_bfd_elf_size_group_sections (info))
- return FALSE;
-
- /* The backend may have to create some sections regardless of whether
- we're dynamic or not. */
- if (bed->elf_backend_always_size_sections
- && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
- return FALSE;
-
- if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
- return FALSE;
-
dynobj = elf_hash_table (info)->dynobj;
- /* If there were no dynamic objects in the link, there is nothing to
- do here. */
- if (dynobj == NULL)
- return TRUE;
-
- if (elf_hash_table (info)->dynamic_sections_created)
+ if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
{
struct elf_info_failed eif;
struct elf_link_hash_entry *h;
asection *s;
bfd_boolean all_defined;
- *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
+ *sinterpptr = bfd_get_linker_section (dynobj, ".interp");
BFD_ASSERT (*sinterpptr != NULL || !info->executable);
if (soname != NULL)
}
eif.info = info;
- eif.verdefs = verdefs;
eif.failed = FALSE;
/* If we are supposed to export all symbols into the dynamic symbol
}
/* Make all global versions with definition. */
- for (t = verdefs; t != NULL; t = t->next)
+ for (t = info->version_info; t != NULL; t = t->next)
for (d = t->globals.list; d != NULL; d = d->next)
if (!d->symver && d->literal)
{
/* Attach all the symbols to their version information. */
asvinfo.info = info;
- asvinfo.verdefs = verdefs;
asvinfo.failed = FALSE;
elf_link_hash_traverse (elf_hash_table (info),
{
/* Check if all global versions have a definition. */
all_defined = TRUE;
- for (t = verdefs; t != NULL; t = t->next)
+ for (t = info->version_info; t != NULL; t = t->next)
for (d = t->globals.list; d != NULL; d = d->next)
if (d->literal && !d->symver && !d->script)
{
return FALSE;
}
- dynstr = bfd_get_section_by_name (dynobj, ".dynstr");
+ dynstr = bfd_get_linker_section (dynobj, ".dynstr");
/* If .dynstr is excluded from the link, we don't want any of
these tags. Strictly, we should be checking each section
individually; This quick check covers for the case where
/* The backend must work out the sizes of all the other dynamic
sections. */
- if (bed->elf_backend_size_dynamic_sections
+ if (dynobj != NULL
+ && bed->elf_backend_size_dynamic_sections != NULL
&& ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
return FALSE;
- if (elf_hash_table (info)->dynamic_sections_created)
+ if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
+ return FALSE;
+
+ if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
{
unsigned long section_sym_count;
+ struct bfd_elf_version_tree *verdefs;
asection *s;
/* Set up the version definition section. */
- s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+ s = bfd_get_linker_section (dynobj, ".gnu.version_d");
BFD_ASSERT (s != NULL);
/* We may have created additional version definitions if we are
just linking a regular application. */
- verdefs = asvinfo.verdefs;
+ verdefs = info->version_info;
/* Skip anonymous version tag. */
if (verdefs != NULL && verdefs->vernum == 0)
/* Work out the size of the version reference section. */
- s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+ s = bfd_get_linker_section (dynobj, ".gnu.version_r");
BFD_ASSERT (s != NULL);
{
struct elf_find_verdep_info sinfo;
|| _bfd_elf_link_renumber_dynsyms (output_bfd, info,
§ion_sym_count) == 0)
{
- s = bfd_get_section_by_name (dynobj, ".gnu.version");
+ s = bfd_get_linker_section (dynobj, ".gnu.version");
s->flags |= SEC_EXCLUDE;
}
}
§ion_sym_count);
/* Work out the size of the symbol version section. */
- s = bfd_get_section_by_name (dynobj, ".gnu.version");
+ s = bfd_get_linker_section (dynobj, ".gnu.version");
BFD_ASSERT (s != NULL);
if (dynsymcount != 0
&& (s->flags & SEC_EXCLUDE) == 0)
the final symbol table, because until then we do not know the
correct value to give the symbols. We built the .dynstr
section as we went along in elf_link_add_object_symbols. */
- s = bfd_get_section_by_name (dynobj, ".dynsym");
+ s = bfd_get_linker_section (dynobj, ".dynsym");
BFD_ASSERT (s != NULL);
s->size = dynsymcount * bed->s->sizeof_sym;
elf_hash_table (info)->bucketcount = bucketcount;
- s = bfd_get_section_by_name (dynobj, ".hash");
+ s = bfd_get_linker_section (dynobj, ".hash");
BFD_ASSERT (s != NULL);
hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
return FALSE;
}
- s = bfd_get_section_by_name (dynobj, ".gnu.hash");
+ s = bfd_get_linker_section (dynobj, ".gnu.hash");
BFD_ASSERT (s != NULL);
if (cinfo.nsyms == 0)
}
}
- s = bfd_get_section_by_name (dynobj, ".dynstr");
+ s = bfd_get_linker_section (dynobj, ".dynstr");
BFD_ASSERT (s != NULL);
elf_finalize_dynstr (output_bfd, info);
return TRUE;
}
\f
-/* Indicate that we are only retrieving symbol values from this
- section. */
-
-void
-_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
-{
- if (is_elf_hash_table (info->hash))
- sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
- _bfd_generic_link_just_syms (sec, info);
-}
-
/* Make sure sec_info_type is cleared if sec_info is cleared too. */
static void
merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec)
{
- BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
- sec->sec_info_type = ELF_INFO_TYPE_NONE;
+ BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_MERGE);
+ sec->sec_info_type = SEC_INFO_TYPE_NONE;
}
/* Finish SHF_MERGE section merging. */
sec, &secdata->sec_info))
return FALSE;
else if (secdata->sec_info)
- sec->sec_info_type = ELF_INFO_TYPE_MERGE;
+ sec->sec_info_type = SEC_INFO_TYPE_MERGE;
}
if (elf_hash_table (info)->merge_info != NULL)
size_t symbuf_size;
/* And same for symshndxbuf. */
size_t shndxbuf_size;
+ /* Number of STT_FILE syms seen. */
+ size_t filesym_count;
};
/* This struct is used to pass information to elf_link_output_extsym. */
{
bfd_boolean failed;
bfd_boolean localsyms;
- struct elf_final_link_info *finfo;
+ bfd_boolean need_second_pass;
+ bfd_boolean second_pass;
+ struct elf_final_link_info *flinfo;
};
static bfd_boolean
resolve_symbol (const char *name,
bfd *input_bfd,
- struct elf_final_link_info *finfo,
+ struct elf_final_link_info *flinfo,
bfd_vma *result,
Elf_Internal_Sym *isymbuf,
size_t locsymcount)
#endif
if (candidate && strcmp (candidate, name) == 0)
{
- asection *sec = finfo->sections [i];
+ asection *sec = flinfo->sections [i];
*result = _bfd_elf_rel_local_sym (input_bfd, sym, &sec, 0);
*result += sec->output_offset + sec->output_section->vma;
}
/* Hmm, haven't found it yet. perhaps it is a global. */
- global_entry = bfd_link_hash_lookup (finfo->info->hash, name,
+ global_entry = bfd_link_hash_lookup (flinfo->info->hash, name,
FALSE, FALSE, TRUE);
if (!global_entry)
return FALSE;
eval_symbol (bfd_vma *result,
const char **symp,
bfd *input_bfd,
- struct elf_final_link_info *finfo,
+ struct elf_final_link_info *flinfo,
bfd_vma dot,
Elf_Internal_Sym *isymbuf,
size_t locsymcount,
if (symbol_is_section)
{
- if (!resolve_section (symbuf, finfo->output_bfd->sections, result)
- && !resolve_symbol (symbuf, input_bfd, finfo, result,
+ if (!resolve_section (symbuf, flinfo->output_bfd->sections, result)
+ && !resolve_symbol (symbuf, input_bfd, flinfo, result,
isymbuf, locsymcount))
{
undefined_reference ("section", symbuf);
}
else
{
- if (!resolve_symbol (symbuf, input_bfd, finfo, result,
+ if (!resolve_symbol (symbuf, input_bfd, flinfo, result,
isymbuf, locsymcount)
- && !resolve_section (symbuf, finfo->output_bfd->sections,
+ && !resolve_section (symbuf, flinfo->output_bfd->sections,
result))
{
undefined_reference ("symbol", symbuf);
if (*sym == ':') \
++sym; \
*symp = sym; \
- if (!eval_symbol (&a, symp, input_bfd, finfo, dot, \
+ if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \
isymbuf, locsymcount, signed_p)) \
return FALSE; \
if (signed_p) \
if (*sym == ':') \
++sym; \
*symp = sym; \
- if (!eval_symbol (&a, symp, input_bfd, finfo, dot, \
+ if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \
isymbuf, locsymcount, signed_p)) \
return FALSE; \
++*symp; \
- if (!eval_symbol (&b, symp, input_bfd, finfo, dot, \
+ if (!eval_symbol (&b, symp, input_bfd, flinfo, dot, \
isymbuf, locsymcount, signed_p)) \
return FALSE; \
if (signed_p) \
/* Flush the output symbols to the file. */
static bfd_boolean
-elf_link_flush_output_syms (struct elf_final_link_info *finfo,
+elf_link_flush_output_syms (struct elf_final_link_info *flinfo,
const struct elf_backend_data *bed)
{
- if (finfo->symbuf_count > 0)
+ if (flinfo->symbuf_count > 0)
{
Elf_Internal_Shdr *hdr;
file_ptr pos;
bfd_size_type amt;
- hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr;
+ hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
pos = hdr->sh_offset + hdr->sh_size;
- amt = finfo->symbuf_count * bed->s->sizeof_sym;
- if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
- || bfd_bwrite (finfo->symbuf, amt, finfo->output_bfd) != amt)
+ amt = flinfo->symbuf_count * bed->s->sizeof_sym;
+ if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) != 0
+ || bfd_bwrite (flinfo->symbuf, amt, flinfo->output_bfd) != amt)
return FALSE;
hdr->sh_size += amt;
- finfo->symbuf_count = 0;
+ flinfo->symbuf_count = 0;
}
return TRUE;
/* Add a symbol to the output symbol table. */
static int
-elf_link_output_sym (struct elf_final_link_info *finfo,
+elf_link_output_sym (struct elf_final_link_info *flinfo,
const char *name,
Elf_Internal_Sym *elfsym,
asection *input_sec,
struct elf_link_hash_entry *);
const struct elf_backend_data *bed;
- bed = get_elf_backend_data (finfo->output_bfd);
+ bed = get_elf_backend_data (flinfo->output_bfd);
output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
if (output_symbol_hook != NULL)
{
- int ret = (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h);
+ int ret = (*output_symbol_hook) (flinfo->info, name, elfsym, input_sec, h);
if (ret != 1)
return ret;
}
elfsym->st_name = 0;
else
{
- elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
+ elfsym->st_name = (unsigned long) _bfd_stringtab_add (flinfo->symstrtab,
name, TRUE, FALSE);
if (elfsym->st_name == (unsigned long) -1)
return 0;
}
- if (finfo->symbuf_count >= finfo->symbuf_size)
+ if (flinfo->symbuf_count >= flinfo->symbuf_size)
{
- if (! elf_link_flush_output_syms (finfo, bed))
+ if (! elf_link_flush_output_syms (flinfo, bed))
return 0;
}
- dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym;
- destshndx = finfo->symshndxbuf;
+ dest = flinfo->symbuf + flinfo->symbuf_count * bed->s->sizeof_sym;
+ destshndx = flinfo->symshndxbuf;
if (destshndx != NULL)
{
- if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size)
+ if (bfd_get_symcount (flinfo->output_bfd) >= flinfo->shndxbuf_size)
{
bfd_size_type amt;
- amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
+ amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx,
amt * 2);
if (destshndx == NULL)
return 0;
- finfo->symshndxbuf = destshndx;
+ flinfo->symshndxbuf = destshndx;
memset ((char *) destshndx + amt, 0, amt);
- finfo->shndxbuf_size *= 2;
+ flinfo->shndxbuf_size *= 2;
}
- destshndx += bfd_get_symcount (finfo->output_bfd);
+ destshndx += bfd_get_symcount (flinfo->output_bfd);
}
- bed->s->swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx);
- finfo->symbuf_count += 1;
- bfd_get_symcount (finfo->output_bfd) += 1;
+ bed->s->swap_symbol_out (flinfo->output_bfd, elfsym, dest, destshndx);
+ flinfo->symbuf_count += 1;
+ bfd_get_symcount (flinfo->output_bfd) += 1;
return 1;
}
if (!is_elf_hash_table (info->hash))
return FALSE;
+ /* Check indirect symbol. */
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
switch (h->root.type)
{
default:
{
struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh;
struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
- struct elf_final_link_info *finfo = eoinfo->finfo;
+ struct elf_final_link_info *flinfo = eoinfo->flinfo;
bfd_boolean strip;
Elf_Internal_Sym sym;
asection *input_sec;
{
if (!h->forced_local)
return TRUE;
+ if (eoinfo->second_pass
+ && !((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->output_section != NULL))
+ return TRUE;
}
else
{
return TRUE;
}
- bed = get_elf_backend_data (finfo->output_bfd);
+ bed = get_elf_backend_data (flinfo->output_bfd);
if (h->root.type == bfd_link_hash_undefined)
{
/* If we are reporting errors for this situation then do so now. */
if (!ignore_undef
&& h->ref_dynamic
- && (!h->ref_regular || finfo->info->gc_sections)
- && ! elf_link_check_versioned_symbol (finfo->info, bed, h)
- && finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
- {
- if (! (finfo->info->callbacks->undefined_symbol
- (finfo->info, h->root.root.string,
- h->ref_regular ? NULL : h->root.u.undef.abfd,
- NULL, 0, finfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR)))
+ && (!h->ref_regular || flinfo->info->gc_sections)
+ && !elf_link_check_versioned_symbol (flinfo->info, bed, h)
+ && flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
+ {
+ if (!(flinfo->info->callbacks->undefined_symbol
+ (flinfo->info, h->root.root.string,
+ h->ref_regular ? NULL : h->root.u.undef.abfd,
+ NULL, 0,
+ (flinfo->info->unresolved_syms_in_shared_libs
+ == RM_GENERATE_ERROR))))
{
bfd_set_error (bfd_error_bad_value);
eoinfo->failed = TRUE;
/* We should also warn if a forced local symbol is referenced from
shared libraries. */
- if (! finfo->info->relocatable
- && (! finfo->info->shared)
+ if (!flinfo->info->relocatable
+ && flinfo->info->executable
&& h->forced_local
&& h->ref_dynamic
+ && h->def_regular
&& !h->dynamic_def
&& !h->dynamic_weak
- && ! elf_link_check_versioned_symbol (finfo->info, bed, h))
+ && !elf_link_check_versioned_symbol (flinfo->info, bed, h))
{
bfd *def_bfd;
const char *msg;
+ struct elf_link_hash_entry *hi = h;
+
+ /* Check indirect symbol. */
+ while (hi->root.type == bfd_link_hash_indirect)
+ hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
msg = _("%B: internal symbol `%s' in %B is referenced by DSO");
msg = _("%B: hidden symbol `%s' in %B is referenced by DSO");
else
msg = _("%B: local symbol `%s' in %B is referenced by DSO");
- def_bfd = finfo->output_bfd;
- if (h->root.u.def.section != bfd_abs_section_ptr)
- def_bfd = h->root.u.def.section->owner;
- (*_bfd_error_handler) (msg, finfo->output_bfd, def_bfd,
+ def_bfd = flinfo->output_bfd;
+ if (hi->root.u.def.section != bfd_abs_section_ptr)
+ def_bfd = hi->root.u.def.section->owner;
+ (*_bfd_error_handler) (msg, flinfo->output_bfd, def_bfd,
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
eoinfo->failed = TRUE;
&& !h->def_regular
&& !h->ref_regular)
strip = TRUE;
- else if (finfo->info->strip == strip_all)
+ else if (flinfo->info->strip == strip_all)
strip = TRUE;
- else if (finfo->info->strip == strip_some
- && bfd_hash_lookup (finfo->info->keep_hash,
+ else if (flinfo->info->strip == strip_some
+ && bfd_hash_lookup (flinfo->info->keep_hash,
h->root.root.string, FALSE, FALSE) == NULL)
strip = TRUE;
- else if (finfo->info->strip_discarded
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && elf_discarded_section (h->root.u.def.section))
+ else if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && ((flinfo->info->strip_discarded
+ && discarded_section (h->root.u.def.section))
+ || (h->root.u.def.section->owner != NULL
+ && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)))
strip = TRUE;
else if ((h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
input_sec = h->root.u.def.section;
if (input_sec->output_section != NULL)
{
+ if (eoinfo->localsyms && flinfo->filesym_count == 1)
+ {
+ bfd_boolean second_pass_sym
+ = (input_sec->owner == flinfo->output_bfd
+ || input_sec->owner == NULL
+ || (input_sec->flags & SEC_LINKER_CREATED) != 0
+ || (input_sec->owner->flags & BFD_LINKER_CREATED) != 0);
+
+ eoinfo->need_second_pass |= second_pass_sym;
+ if (eoinfo->second_pass != second_pass_sym)
+ return TRUE;
+ }
+
sym.st_shndx =
- _bfd_elf_section_from_bfd_section (finfo->output_bfd,
+ _bfd_elf_section_from_bfd_section (flinfo->output_bfd,
input_sec->output_section);
if (sym.st_shndx == SHN_BAD)
{
(*_bfd_error_handler)
(_("%B: could not find output section %A for input section %A"),
- finfo->output_bfd, input_sec->output_section, input_sec);
+ flinfo->output_bfd, input_sec->output_section, input_sec);
bfd_set_error (bfd_error_nonrepresentable_section);
eoinfo->failed = TRUE;
return FALSE;
but in nonrelocatable files they are virtual
addresses. */
sym.st_value = h->root.u.def.value + input_sec->output_offset;
- if (! finfo->info->relocatable)
+ if (!flinfo->info->relocatable)
{
sym.st_value += input_sec->output_section->vma;
if (h->type == STT_TLS)
{
- asection *tls_sec = elf_hash_table (finfo->info)->tls_sec;
+ asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec;
if (tls_sec != NULL)
sym.st_value -= tls_sec->vma;
else
{
/* The TLS section may have been garbage collected. */
- BFD_ASSERT (finfo->info->gc_sections
+ BFD_ASSERT (flinfo->info->gc_sections
&& !input_sec->gc_mark);
}
}
STT_GNU_IFUNC symbol must go through PLT. */
if ((h->type == STT_GNU_IFUNC
&& h->def_regular
- && !finfo->info->relocatable)
+ && !flinfo->info->relocatable)
|| ((h->dynindx != -1
|| h->forced_local)
- && ((finfo->info->shared
+ && ((flinfo->info->shared
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
|| !h->forced_local)
- && elf_hash_table (finfo->info)->dynamic_sections_created))
+ && elf_hash_table (flinfo->info)->dynamic_sections_created))
{
if (! ((*bed->elf_backend_finish_dynamic_symbol)
- (finfo->output_bfd, finfo->info, h, &sym)))
+ (flinfo->output_bfd, flinfo->info, h, &sym)))
{
eoinfo->failed = TRUE;
return FALSE;
/* If a non-weak symbol with non-default visibility is not defined
locally, it is a fatal error. */
- if (! finfo->info->relocatable
+ if (!flinfo->info->relocatable
&& ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
&& ELF_ST_BIND (sym.st_info) != STB_WEAK
&& h->root.type == bfd_link_hash_undefined
msg = _("%B: internal symbol `%s' isn't defined");
else
msg = _("%B: hidden symbol `%s' isn't defined");
- (*_bfd_error_handler) (msg, finfo->output_bfd, h->root.root.string);
+ (*_bfd_error_handler) (msg, flinfo->output_bfd, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
eoinfo->failed = TRUE;
return FALSE;
/* If this symbol should be put in the .dynsym section, then put it
there now. We already know the symbol index. We also fill in
the entry in the .hash section. */
- if (h->dynindx != -1
- && elf_hash_table (finfo->info)->dynamic_sections_created)
+ if (flinfo->dynsym_sec != NULL
+ && h->dynindx != -1
+ && elf_hash_table (flinfo->info)->dynamic_sections_created)
{
bfd_byte *esym;
+ /* Since there is no version information in the dynamic string,
+ if there is no version info in symbol version section, we will
+ have a run-time problem. */
+ if (h->verinfo.verdef == NULL)
+ {
+ char *p = strrchr (h->root.root.string, ELF_VER_CHR);
+
+ if (p && p [1] != '\0')
+ {
+ (*_bfd_error_handler)
+ (_("%B: No symbol version section for versioned symbol `%s'"),
+ flinfo->output_bfd, h->root.root.string);
+ eoinfo->failed = TRUE;
+ return FALSE;
+ }
+ }
+
sym.st_name = h->dynstr_index;
- esym = finfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
- if (! check_dynsym (finfo->output_bfd, &sym))
+ esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
+ if (!check_dynsym (flinfo->output_bfd, &sym))
{
eoinfo->failed = TRUE;
return FALSE;
}
- bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0);
+ bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0);
- if (finfo->hash_sec != NULL)
+ if (flinfo->hash_sec != NULL)
{
size_t hash_entry_size;
bfd_byte *bucketpos;
size_t bucketcount;
size_t bucket;
- bucketcount = elf_hash_table (finfo->info)->bucketcount;
+ bucketcount = elf_hash_table (flinfo->info)->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_section_data (flinfo->hash_sec)->this_hdr.sh_entsize;
+ bucketpos = ((bfd_byte *) flinfo->hash_sec->contents
+ (bucket + 2) * hash_entry_size);
- chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
- bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos);
- bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
- ((bfd_byte *) finfo->hash_sec->contents
+ chain = bfd_get (8 * hash_entry_size, flinfo->output_bfd, bucketpos);
+ bfd_put (8 * hash_entry_size, flinfo->output_bfd, h->dynindx,
+ bucketpos);
+ bfd_put (8 * hash_entry_size, flinfo->output_bfd, chain,
+ ((bfd_byte *) flinfo->hash_sec->contents
+ (bucketcount + 2 + h->dynindx) * hash_entry_size));
}
- if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
+ if (flinfo->symver_sec != NULL && flinfo->symver_sec->contents != NULL)
{
Elf_Internal_Versym iversym;
Elf_External_Versym *eversym;
iversym.vs_vers = 1;
else
iversym.vs_vers = h->verinfo.vertree->vernum + 1;
- if (finfo->info->create_default_symver)
+ if (flinfo->info->create_default_symver)
iversym.vs_vers++;
}
if (h->hidden)
iversym.vs_vers |= VERSYM_HIDDEN;
- eversym = (Elf_External_Versym *) finfo->symver_sec->contents;
+ eversym = (Elf_External_Versym *) flinfo->symver_sec->contents;
eversym += h->dynindx;
- _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym);
+ _bfd_elf_swap_versym_out (flinfo->output_bfd, &iversym, eversym);
}
}
if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
return TRUE;
- indx = bfd_get_symcount (finfo->output_bfd);
- ret = elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h);
+ indx = bfd_get_symcount (flinfo->output_bfd);
+ ret = elf_link_output_sym (flinfo, h->root.root.string, &sym, input_sec, h);
if (ret == 0)
{
eoinfo->failed = TRUE;
switch (sec->sec_info_type)
{
- case ELF_INFO_TYPE_STABS:
- case ELF_INFO_TYPE_EH_FRAME:
+ case SEC_INFO_TYPE_STABS:
+ case SEC_INFO_TYPE_EH_FRAME:
return TRUE;
default:
break;
don't have to keep them in memory. */
static bfd_boolean
-elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
+elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
{
int (*relocate_section)
(bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
bfd_size_type address_size;
bfd_vma r_type_mask;
int r_sym_shift;
+ bfd_boolean have_file_sym = FALSE;
- output_bfd = finfo->output_bfd;
+ output_bfd = flinfo->output_bfd;
bed = get_elf_backend_data (output_bfd);
relocate_section = bed->elf_backend_relocate_section;
if (isymbuf == NULL && locsymcount != 0)
{
isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
- finfo->internal_syms,
- finfo->external_syms,
- finfo->locsym_shndx);
+ flinfo->internal_syms,
+ flinfo->external_syms,
+ flinfo->locsym_shndx);
if (isymbuf == NULL)
return FALSE;
}
SEC_MERGE sections. Write out those local symbols we know are
going into the output file. */
isymend = isymbuf + locsymcount;
- for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections;
+ for (isym = isymbuf, pindex = flinfo->indices, ppsection = flinfo->sections;
isym < isymend;
isym++, pindex++, ppsection++)
{
*ppsection = NULL;
continue;
}
- else if (isec->sec_info_type == ELF_INFO_TYPE_MERGE
+ else if (isec->sec_info_type == SEC_INFO_TYPE_MERGE
&& ELF_ST_TYPE (isym->st_info) != STT_SECTION)
isym->st_value =
_bfd_merged_section_offset (output_bfd, &isec,
*ppsection = isec;
/* Don't output the first, undefined, symbol. */
- if (ppsection == finfo->sections)
+ if (ppsection == flinfo->sections)
continue;
if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
/* If we are stripping all symbols, we don't want to output this
one. */
- if (finfo->info->strip == strip_all)
+ if (flinfo->info->strip == strip_all)
continue;
/* If we are discarding all local symbols, we don't want to
file, then some of the local symbols may be required by
relocs; we output them below as we discover that they are
needed. */
- if (finfo->info->discard == discard_all)
+ if (flinfo->info->discard == discard_all)
continue;
/* If this symbol is defined in a section which we are
return FALSE;
/* See if we are discarding symbols with this name. */
- if ((finfo->info->strip == strip_some
- && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE, FALSE)
+ if ((flinfo->info->strip == strip_some
+ && (bfd_hash_lookup (flinfo->info->keep_hash, name, FALSE, FALSE)
== NULL))
- || (((finfo->info->discard == discard_sec_merge
- && (isec->flags & SEC_MERGE) && ! finfo->info->relocatable)
- || finfo->info->discard == discard_l)
+ || (((flinfo->info->discard == discard_sec_merge
+ && (isec->flags & SEC_MERGE) && !flinfo->info->relocatable)
+ || flinfo->info->discard == discard_l)
&& bfd_is_local_label_name (input_bfd, name)))
continue;
+ if (ELF_ST_TYPE (isym->st_info) == STT_FILE)
+ {
+ have_file_sym = TRUE;
+ flinfo->filesym_count += 1;
+ }
+ if (!have_file_sym)
+ {
+ /* In the absence of debug info, bfd_find_nearest_line uses
+ FILE symbols to determine the source file for local
+ function symbols. Provide a FILE symbol here if input
+ files lack such, so that their symbols won't be
+ associated with a previous input file. It's not the
+ source file, but the best we can do. */
+ have_file_sym = TRUE;
+ flinfo->filesym_count += 1;
+ memset (&osym, 0, sizeof (osym));
+ osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+ osym.st_shndx = SHN_ABS;
+ if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym,
+ bfd_abs_section_ptr, NULL))
+ return FALSE;
+ }
+
osym = *isym;
/* Adjust the section index for the output file. */
output_section. Any special sections must be set up to meet
these requirements. */
osym.st_value += isec->output_offset;
- if (! finfo->info->relocatable)
+ if (!flinfo->info->relocatable)
{
osym.st_value += isec->output_section->vma;
if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
{
/* STT_TLS symbols are relative to PT_TLS segment base. */
- BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
- osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
+ BFD_ASSERT (elf_hash_table (flinfo->info)->tls_sec != NULL);
+ osym.st_value -= elf_hash_table (flinfo->info)->tls_sec->vma;
}
}
indx = bfd_get_symcount (output_bfd);
- ret = elf_link_output_sym (finfo, name, &osym, isec, NULL);
+ ret = elf_link_output_sym (flinfo, name, &osym, isec, NULL);
if (ret == 0)
return FALSE;
else if (ret == 1)
continue;
}
- if (finfo->info->relocatable
+ if (flinfo->info->relocatable
&& (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP)
{
/* Deal with the group signature symbol. */
if (symndx >= locsymcount
|| (elf_bad_symtab (input_bfd)
- && finfo->sections[symndx] == NULL))
+ && flinfo->sections[symndx] == NULL))
{
struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff];
while (h->root.type == bfd_link_hash_indirect
else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION)
{
/* We'll use the output section target_index. */
- asection *sec = finfo->sections[symndx]->output_section;
+ asection *sec = flinfo->sections[symndx]->output_section;
elf_section_data (osec)->this_hdr.sh_info = sec->target_index;
}
else
{
- if (finfo->indices[symndx] == -1)
+ if (flinfo->indices[symndx] == -1)
{
/* Otherwise output the local symbol now. */
Elf_Internal_Sym sym = isymbuf[symndx];
- asection *sec = finfo->sections[symndx]->output_section;
+ asection *sec = flinfo->sections[symndx]->output_section;
const char *name;
long indx;
int ret;
sym.st_value += o->output_offset;
indx = bfd_get_symcount (output_bfd);
- ret = elf_link_output_sym (finfo, name, &sym, o, NULL);
+ ret = elf_link_output_sym (flinfo, name, &sym, o, NULL);
if (ret == 0)
return FALSE;
else if (ret == 1)
- finfo->indices[symndx] = indx;
+ flinfo->indices[symndx] = indx;
else
abort ();
}
elf_section_data (osec)->this_hdr.sh_info
- = finfo->indices[symndx];
+ = flinfo->indices[symndx];
}
}
contents = elf_section_data (o)->this_hdr.contents;
else
{
- contents = finfo->contents;
+ contents = flinfo->contents;
if (! bfd_get_full_section_contents (input_bfd, o, &contents))
return FALSE;
}
/* Get the swapped relocs. */
internal_relocs
- = _bfd_elf_link_read_relocs (input_bfd, o, finfo->external_relocs,
- finfo->internal_relocs, FALSE);
+ = _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs,
+ flinfo->internal_relocs, FALSE);
if (internal_relocs == NULL
&& o->reloc_count > 0)
return FALSE;
if (r_symndx >= locsymcount
|| (elf_bad_symtab (input_bfd)
- && finfo->sections[r_symndx] == NULL))
+ && flinfo->sections[r_symndx] == NULL))
{
h = sym_hashes[r_symndx - extsymoff];
Elf_Internal_Sym *sym = isymbuf + r_symndx;
s_type = ELF_ST_TYPE (sym->st_info);
- ps = &finfo->sections[r_symndx];
+ ps = &flinfo->sections[r_symndx];
sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr,
sym, *ps);
}
if ((s_type == STT_RELC || s_type == STT_SRELC)
- && !finfo->info->relocatable)
+ && !flinfo->info->relocatable)
{
bfd_vma val;
bfd_vma dot = (rel->r_offset
(unsigned long) rel->r_info,
(unsigned long) rel->r_offset);
#endif
- if (!eval_symbol (&val, &sym_name, input_bfd, finfo, dot,
+ if (!eval_symbol (&val, &sym_name, input_bfd, flinfo, dot,
isymbuf, locsymcount, s_type == STT_SRELC))
return FALSE;
{
/* Complain if the definition comes from a
discarded section. */
- if ((sec = *ps) != NULL && elf_discarded_section (sec))
+ if ((sec = *ps) != NULL && discarded_section (sec))
{
BFD_ASSERT (r_symndx != STN_UNDEF);
if (action_discarded & COMPLAIN)
- (*finfo->info->callbacks->einfo)
+ (*flinfo->info->callbacks->einfo)
(_("%X`%s' referenced in section `%A' of %B: "
"defined in discarded section `%A' of %B\n"),
sym_name, o, input_bfd, sec, sec->owner);
asection *kept;
kept = _bfd_elf_check_kept_section (sec,
- finfo->info);
+ flinfo->info);
if (kept != NULL)
{
*ps = kept;
corresponding to the output section, which will require
the addend to be adjusted. */
- ret = (*relocate_section) (output_bfd, finfo->info,
+ ret = (*relocate_section) (output_bfd, flinfo->info,
input_bfd, o, contents,
internal_relocs,
isymbuf,
- finfo->sections);
+ flinfo->sections);
if (!ret)
return FALSE;
if (ret == 2
- || finfo->info->relocatable
- || finfo->info->emitrelocations)
+ || flinfo->info->relocatable
+ || flinfo->info->emitrelocations)
{
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend, *irelamid;
rel_hash_list = rel_hash;
rela_hash_list = NULL;
last_offset = o->output_offset;
- if (!finfo->info->relocatable)
+ if (!flinfo->info->relocatable)
last_offset += o->output_section->vma;
for (next_erel = 0; irela < irelaend; irela++, next_erel++)
{
}
irela->r_offset = _bfd_elf_section_offset (output_bfd,
- finfo->info, o,
+ flinfo->info, o,
irela->r_offset);
if (irela->r_offset >= (bfd_vma) -2)
{
irela->r_offset += o->output_offset;
/* Relocs in an executable have to be virtual addresses. */
- if (!finfo->info->relocatable)
+ if (!flinfo->info->relocatable)
irela->r_offset += o->output_section->vma;
last_offset = irela->r_offset;
if (r_symndx >= locsymcount
|| (elf_bad_symtab (input_bfd)
- && finfo->sections[r_symndx] == NULL))
+ && flinfo->sections[r_symndx] == NULL))
{
struct elf_link_hash_entry *rh;
unsigned long indx;
*rel_hash = NULL;
sym = isymbuf[r_symndx];
- sec = finfo->sections[r_symndx];
+ sec = flinfo->sections[r_symndx];
if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
{
/* I suppose the backend ought to fill in the
r_symndx = osec->target_index;
if (r_symndx == STN_UNDEF)
{
- struct elf_link_hash_table *htab;
- asection *oi;
-
- htab = elf_hash_table (finfo->info);
- oi = htab->text_index_section;
- if ((osec->flags & SEC_READONLY) == 0
- && htab->data_index_section != NULL)
- oi = htab->data_index_section;
-
- if (oi != NULL)
- {
- irela->r_addend += osec->vma - oi->vma;
- r_symndx = oi->target_index;
- }
+ irela->r_addend += osec->vma;
+ osec = _bfd_nearby_section (output_bfd, osec,
+ osec->vma);
+ irela->r_addend -= osec->vma;
+ r_symndx = osec->target_index;
}
-
- BFD_ASSERT (r_symndx != STN_UNDEF);
}
}
}
else
{
- if (finfo->indices[r_symndx] == -1)
+ if (flinfo->indices[r_symndx] == -1)
{
unsigned long shlink;
const char *name;
asection *osec;
long indx;
- if (finfo->info->strip == strip_all)
+ if (flinfo->info->strip == strip_all)
{
/* You can't do ld -r -s. */
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
sym.st_value += sec->output_offset;
- if (! finfo->info->relocatable)
+ if (!flinfo->info->relocatable)
{
sym.st_value += osec->vma;
if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
{
/* STT_TLS symbols are relative to PT_TLS
segment base. */
- BFD_ASSERT (elf_hash_table (finfo->info)
+ BFD_ASSERT (elf_hash_table (flinfo->info)
->tls_sec != NULL);
- sym.st_value -= (elf_hash_table (finfo->info)
+ sym.st_value -= (elf_hash_table (flinfo->info)
->tls_sec->vma);
}
}
indx = bfd_get_symcount (output_bfd);
- ret = elf_link_output_sym (finfo, name, &sym, sec,
+ ret = elf_link_output_sym (flinfo, name, &sym, sec,
NULL);
if (ret == 0)
return FALSE;
else if (ret == 1)
- finfo->indices[r_symndx] = indx;
+ flinfo->indices[r_symndx] = indx;
else
abort ();
}
- r_symndx = finfo->indices[r_symndx];
+ r_symndx = flinfo->indices[r_symndx];
}
irela->r_info = ((bfd_vma) r_symndx << r_sym_shift
/* Write out the modified section contents. */
if (bed->elf_backend_write_section
- && (*bed->elf_backend_write_section) (output_bfd, finfo->info, o,
+ && (*bed->elf_backend_write_section) (output_bfd, flinfo->info, o,
contents))
{
/* Section written out. */
}
else switch (o->sec_info_type)
{
- case ELF_INFO_TYPE_STABS:
+ case SEC_INFO_TYPE_STABS:
if (! (_bfd_write_section_stabs
(output_bfd,
- &elf_hash_table (finfo->info)->stab_info,
+ &elf_hash_table (flinfo->info)->stab_info,
o, &elf_section_data (o)->sec_info, contents)))
return FALSE;
break;
- case ELF_INFO_TYPE_MERGE:
+ case SEC_INFO_TYPE_MERGE:
if (! _bfd_write_merged_section (output_bfd, o,
elf_section_data (o)->sec_info))
return FALSE;
break;
- case ELF_INFO_TYPE_EH_FRAME:
+ case SEC_INFO_TYPE_EH_FRAME:
{
- if (! _bfd_elf_write_section_eh_frame (output_bfd, finfo->info,
+ if (! _bfd_elf_write_section_eh_frame (output_bfd, flinfo->info,
o, contents))
return FALSE;
}
bfd_boolean dynamic;
bfd_boolean emit_relocs;
bfd *dynobj;
- struct elf_final_link_info finfo;
+ struct elf_final_link_info flinfo;
asection *o;
struct bfd_link_order *p;
bfd *sub;
emit_relocs = (info->relocatable
|| info->emitrelocations);
- finfo.info = info;
- finfo.output_bfd = abfd;
- finfo.symstrtab = _bfd_elf_stringtab_init ();
- if (finfo.symstrtab == NULL)
+ flinfo.info = info;
+ flinfo.output_bfd = abfd;
+ flinfo.symstrtab = _bfd_elf_stringtab_init ();
+ if (flinfo.symstrtab == NULL)
return FALSE;
if (! dynamic)
{
- finfo.dynsym_sec = NULL;
- finfo.hash_sec = NULL;
- finfo.symver_sec = NULL;
+ flinfo.dynsym_sec = NULL;
+ flinfo.hash_sec = NULL;
+ flinfo.symver_sec = NULL;
}
else
{
- finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
- finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
- BFD_ASSERT (finfo.dynsym_sec != NULL);
- finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version");
+ flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym");
+ flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash");
+ /* Note that dynsym_sec can be NULL (on VMS). */
+ flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version");
/* Note that it is OK if symver_sec is NULL. */
}
- finfo.contents = NULL;
- finfo.external_relocs = NULL;
- finfo.internal_relocs = NULL;
- finfo.external_syms = NULL;
- finfo.locsym_shndx = NULL;
- finfo.internal_syms = NULL;
- finfo.indices = NULL;
- finfo.sections = NULL;
- finfo.symbuf = NULL;
- finfo.symshndxbuf = NULL;
- finfo.symbuf_count = 0;
- finfo.shndxbuf_size = 0;
+ flinfo.contents = NULL;
+ flinfo.external_relocs = NULL;
+ flinfo.internal_relocs = NULL;
+ flinfo.external_syms = NULL;
+ flinfo.locsym_shndx = NULL;
+ flinfo.internal_syms = NULL;
+ flinfo.indices = NULL;
+ flinfo.sections = NULL;
+ flinfo.symbuf = NULL;
+ flinfo.symshndxbuf = NULL;
+ flinfo.symbuf_count = 0;
+ flinfo.shndxbuf_size = 0;
+ flinfo.filesym_count = 0;
/* The object attributes have been merged. Remove the input
sections from the link, and set the contents of the output
if (sec->flags & SEC_MERGE)
merged = TRUE;
- if (info->relocatable || info->emitrelocations)
+ if (esdo->this_hdr.sh_type == SHT_REL
+ || esdo->this_hdr.sh_type == SHT_RELA)
+ /* Some backends use reloc_count in relocation sections
+ to count particular types of relocs. Of course,
+ reloc sections themselves can't have relocations. */
+ reloc_count = 0;
+ else if (info->relocatable || info->emitrelocations)
reloc_count = sec->reloc_count;
else if (bed->elf_backend_count_relocs)
reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
/* Allocate a buffer to hold swapped out symbols. This is to avoid
continuously seeking to the right position in the file. */
if (! info->keep_memory || max_sym_count < 20)
- finfo.symbuf_size = 20;
+ flinfo.symbuf_size = 20;
else
- finfo.symbuf_size = max_sym_count;
- amt = finfo.symbuf_size;
+ flinfo.symbuf_size = max_sym_count;
+ amt = flinfo.symbuf_size;
amt *= bed->s->sizeof_sym;
- finfo.symbuf = (bfd_byte *) bfd_malloc (amt);
- if (finfo.symbuf == NULL)
+ flinfo.symbuf = (bfd_byte *) bfd_malloc (amt);
+ if (flinfo.symbuf == NULL)
goto error_return;
if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
{
/* Wild guess at number of output symbols. realloc'd as needed. */
amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
- finfo.shndxbuf_size = amt;
+ flinfo.shndxbuf_size = amt;
amt *= sizeof (Elf_External_Sym_Shndx);
- finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
- if (finfo.symshndxbuf == NULL)
+ flinfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
+ if (flinfo.symshndxbuf == NULL)
goto error_return;
}
elfsym.st_other = 0;
elfsym.st_shndx = SHN_UNDEF;
elfsym.st_target_internal = 0;
- if (elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+ if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr,
NULL) != 1)
goto error_return;
}
elfsym.st_shndx = i;
if (!info->relocatable)
elfsym.st_value = o->vma;
- if (elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL) != 1)
+ if (elf_link_output_sym (&flinfo, NULL, &elfsym, o, NULL) != 1)
goto error_return;
}
}
files. */
if (max_contents_size != 0)
{
- finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
- if (finfo.contents == NULL)
+ flinfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+ if (flinfo.contents == NULL)
goto error_return;
}
if (max_external_reloc_size != 0)
{
- finfo.external_relocs = bfd_malloc (max_external_reloc_size);
- if (finfo.external_relocs == NULL)
+ flinfo.external_relocs = bfd_malloc (max_external_reloc_size);
+ if (flinfo.external_relocs == NULL)
goto error_return;
}
{
amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
amt *= sizeof (Elf_Internal_Rela);
- finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
- if (finfo.internal_relocs == NULL)
+ flinfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+ if (flinfo.internal_relocs == NULL)
goto error_return;
}
if (max_sym_count != 0)
{
amt = max_sym_count * bed->s->sizeof_sym;
- finfo.external_syms = (bfd_byte *) bfd_malloc (amt);
- if (finfo.external_syms == NULL)
+ flinfo.external_syms = (bfd_byte *) bfd_malloc (amt);
+ if (flinfo.external_syms == NULL)
goto error_return;
amt = max_sym_count * sizeof (Elf_Internal_Sym);
- finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
- if (finfo.internal_syms == NULL)
+ flinfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
+ if (flinfo.internal_syms == NULL)
goto error_return;
amt = max_sym_count * sizeof (long);
- finfo.indices = (long int *) bfd_malloc (amt);
- if (finfo.indices == NULL)
+ flinfo.indices = (long int *) bfd_malloc (amt);
+ if (flinfo.indices == NULL)
goto error_return;
amt = max_sym_count * sizeof (asection *);
- finfo.sections = (asection **) bfd_malloc (amt);
- if (finfo.sections == NULL)
+ flinfo.sections = (asection **) bfd_malloc (amt);
+ if (flinfo.sections == NULL)
goto error_return;
}
if (max_sym_shndx_count != 0)
{
amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
- finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
- if (finfo.locsym_shndx == NULL)
+ flinfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+ if (flinfo.locsym_shndx == NULL)
goto error_return;
}
{
if (! sub->output_has_begun)
{
- if (! elf_link_input_bfd (&finfo, sub))
+ if (! elf_link_input_bfd (&flinfo, sub))
goto error_return;
sub->output_has_begun = TRUE;
}
}
}
+ /* 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
some global symbols were, in fact, converted to become local.
FIXME: Will this work correctly with the Irix 5 linker? */
eoinfo.failed = FALSE;
- eoinfo.finfo = &finfo;
+ eoinfo.flinfo = &flinfo;
eoinfo.localsyms = TRUE;
+ eoinfo.need_second_pass = FALSE;
+ eoinfo.second_pass = 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;
+ bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
+ if (eoinfo.failed)
+ return FALSE;
+ }
+
/* If backend needs to output some local symbols not present in the hash
table, do it now. */
if (bed->elf_backend_output_arch_local_syms)
struct elf_link_hash_entry *);
if (! ((*bed->elf_backend_output_arch_local_syms)
- (abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
+ (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym)))
return FALSE;
}
symtab_hdr->sh_info = bfd_get_symcount (abfd);
if (dynamic
- && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
+ && flinfo.dynsym_sec != NULL
+ && flinfo.dynsym_sec->output_section != bfd_abs_section_ptr)
{
Elf_Internal_Sym sym;
- bfd_byte *dynsym = finfo.dynsym_sec->contents;
+ bfd_byte *dynsym = flinfo.dynsym_sec->contents;
long last_local = 0;
/* Write out the section symbols for the output sections. */
}
}
- elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+ elf_section_data (flinfo.dynsym_sec->output_section)->this_hdr.sh_info =
last_local + 1;
}
/* We get the global symbols from the hash table. */
eoinfo.failed = FALSE;
eoinfo.localsyms = FALSE;
- eoinfo.finfo = &finfo;
+ eoinfo.flinfo = &flinfo;
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
return FALSE;
struct elf_link_hash_entry *);
if (! ((*bed->elf_backend_output_arch_syms)
- (abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
+ (abfd, info, &flinfo, (out_sym_func) elf_link_output_sym)))
return FALSE;
}
/* Flush all symbols to the file. */
- if (! elf_link_flush_output_syms (&finfo, bed))
+ if (! elf_link_flush_output_syms (&flinfo, bed))
return FALSE;
/* Now we know the size of the symtab section. */
off, TRUE);
if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
- || (bfd_bwrite (finfo.symshndxbuf, amt, abfd) != amt))
+ || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
return FALSE;
}
symstrtab_hdr->sh_type = SHT_STRTAB;
symstrtab_hdr->sh_flags = 0;
symstrtab_hdr->sh_addr = 0;
- symstrtab_hdr->sh_size = _bfd_stringtab_size (finfo.symstrtab);
+ symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab);
symstrtab_hdr->sh_entsize = 0;
symstrtab_hdr->sh_link = 0;
symstrtab_hdr->sh_info = 0;
if (bfd_get_symcount (abfd) > 0)
{
if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
- || ! _bfd_stringtab_emit (abfd, finfo.symstrtab))
+ || ! _bfd_stringtab_emit (abfd, flinfo.symstrtab))
return FALSE;
}
bfd_byte *dyncon, *dynconend;
/* Fix up .dynamic entries. */
- o = bfd_get_section_by_name (dynobj, ".dynamic");
+ o = bfd_get_linker_section (dynobj, ".dynamic");
BFD_ASSERT (o != NULL);
dyncon = o->contents;
goto error_return;
/* Check for DT_TEXTREL (late, in case the backend removes it). */
- if (info->warn_shared_textrel && info->shared)
+ if (((info->warn_shared_textrel && info->shared)
+ || info->error_textrel)
+ && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
{
bfd_byte *dyncon, *dynconend;
- /* Fix up .dynamic entries. */
- o = bfd_get_section_by_name (dynobj, ".dynamic");
- BFD_ASSERT (o != NULL);
-
dyncon = o->contents;
dynconend = o->contents + o->size;
for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
if (dyn.d_tag == DT_TEXTREL)
{
- info->callbacks->einfo
- (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
+ if (info->error_textrel)
+ info->callbacks->einfo
+ (_("%P%X: read-only segment has dynamic relocations.\n"));
+ else
+ info->callbacks->einfo
+ (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
break;
}
}
continue;
if (elf_hash_table (info)->eh_info.hdr_sec == o)
continue;
- if ((elf_section_data (o->output_section)->this_hdr.sh_type
- != SHT_STRTAB)
- && (strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0))
+ if (strcmp (o->name, ".dynstr") != 0)
{
/* FIXME: octets_per_byte. */
if (! bfd_set_section_contents (abfd, o->output_section,
goto error_return;
}
- if (finfo.symstrtab != NULL)
- _bfd_stringtab_free (finfo.symstrtab);
- if (finfo.contents != NULL)
- free (finfo.contents);
- if (finfo.external_relocs != NULL)
- free (finfo.external_relocs);
- if (finfo.internal_relocs != NULL)
- free (finfo.internal_relocs);
- if (finfo.external_syms != NULL)
- free (finfo.external_syms);
- if (finfo.locsym_shndx != NULL)
- free (finfo.locsym_shndx);
- if (finfo.internal_syms != NULL)
- free (finfo.internal_syms);
- if (finfo.indices != NULL)
- free (finfo.indices);
- if (finfo.sections != NULL)
- free (finfo.sections);
- if (finfo.symbuf != NULL)
- free (finfo.symbuf);
- if (finfo.symshndxbuf != NULL)
- free (finfo.symshndxbuf);
+ 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);
return TRUE;
error_return:
- if (finfo.symstrtab != NULL)
- _bfd_stringtab_free (finfo.symstrtab);
- if (finfo.contents != NULL)
- free (finfo.contents);
- if (finfo.external_relocs != NULL)
- free (finfo.external_relocs);
- if (finfo.internal_relocs != NULL)
- free (finfo.internal_relocs);
- if (finfo.external_syms != NULL)
- free (finfo.external_syms);
- if (finfo.locsym_shndx != NULL)
- free (finfo.locsym_shndx);
- if (finfo.internal_syms != NULL)
- free (finfo.internal_syms);
- if (finfo.indices != NULL)
- free (finfo.indices);
- if (finfo.sections != NULL)
- free (finfo.sections);
- if (finfo.symbuf != NULL)
- free (finfo.symbuf);
- if (finfo.symshndxbuf != NULL)
- free (finfo.symshndxbuf);
+ 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);
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;
+ h->mark = 1;
+ /* If this symbol is weak and there is a non-weak definition, we
+ keep the non-weak definition because many backends put
+ dynamic reloc info on the non-weak definition for code
+ handling copy relocs. */
+ if (h->u.weakdef != NULL)
+ h->u.weakdef->mark = 1;
return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
}
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
if (rsec && !rsec->gc_mark)
{
- if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+ if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
+ || (rsec->owner->flags & DYNAMIC) != 0)
rsec->gc_mark = 1;
else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
return FALSE;
continue;
/* Keep debug and special sections like .comment when they are
- not part of a group. */
+ not part of a group, or when we have single-member groups. */
for (isec = ibfd->sections; isec != NULL; isec = isec->next)
- if (elf_next_in_group (isec) == NULL
+ if ((elf_next_in_group (isec) == NULL
+ || elf_next_in_group (isec) == isec)
&& ((isec->flags & SEC_DEBUGGING) != 0
|| (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0))
isec->gc_mark = 1;
static bfd_boolean
elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
{
- if ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && !h->root.u.def.section->gc_mark
- && !(h->root.u.def.section->owner->flags & DYNAMIC))
+ if (!h->mark
+ && (((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && !(h->def_regular
+ && h->root.u.def.section->gc_mark))
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
{
- struct elf_gc_sweep_symbol_info *inf =
- (struct elf_gc_sweep_symbol_info *) data;
+ struct elf_gc_sweep_symbol_info *inf;
+
+ inf = (struct elf_gc_sweep_symbol_info *) data;
(*inf->hide_symbol) (inf->info, h, TRUE);
+ h->def_regular = 0;
+ h->ref_regular = 0;
+ h->ref_regular_nonweak = 0;
}
return TRUE;
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->ref_dynamic
- || (!info->executable
+ || ((!info->executable || info->export_dynamic)
&& h->def_regular
&& ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
- && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN)))
+ && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
+ && (strchr (h->root.root.string, ELF_VER_CHR) != NULL
+ || !bfd_hide_sym_by_version (info->version_info,
+ h->root.root.string)))))
h->root.u.def.section->flags |= SEC_KEEP;
return TRUE;
struct elf_reloc_cookie cookie;
sec = bfd_get_section_by_name (sub, ".eh_frame");
- if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
+ while (sec && init_reloc_cookie_for_section (&cookie, info, sec))
{
_bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
- if (elf_section_data (sec)->sec_info)
+ if (elf_section_data (sec)->sec_info
+ && (sec->flags & SEC_LINKER_CREATED) == 0)
elf_eh_frame_section (sub) = sec;
fini_reloc_cookie_for_section (&cookie, sec);
+ sec = bfd_get_next_section_by_name (sec);
}
}
_bfd_elf_end_eh_frame_parsing (info);
return TRUE;
}
+/* Map an ELF section header flag to its corresponding string. */
+typedef struct
+{
+ char *flag_name;
+ flagword flag_value;
+} elf_flags_to_name_table;
+
+static elf_flags_to_name_table elf_flags_to_names [] =
+{
+ { "SHF_WRITE", SHF_WRITE },
+ { "SHF_ALLOC", SHF_ALLOC },
+ { "SHF_EXECINSTR", SHF_EXECINSTR },
+ { "SHF_MERGE", SHF_MERGE },
+ { "SHF_STRINGS", SHF_STRINGS },
+ { "SHF_INFO_LINK", SHF_INFO_LINK},
+ { "SHF_LINK_ORDER", SHF_LINK_ORDER},
+ { "SHF_OS_NONCONFORMING", SHF_OS_NONCONFORMING},
+ { "SHF_GROUP", SHF_GROUP },
+ { "SHF_TLS", SHF_TLS },
+ { "SHF_MASKOS", SHF_MASKOS },
+ { "SHF_EXCLUDE", SHF_EXCLUDE },
+};
+
+/* Returns TRUE if the section is to be included, otherwise FALSE. */
+bfd_boolean
+bfd_elf_lookup_section_flags (struct bfd_link_info *info,
+ struct flag_info *flaginfo,
+ asection *section)
+{
+ const bfd_vma sh_flags = elf_section_flags (section);
+
+ if (!flaginfo->flags_initialized)
+ {
+ bfd *obfd = info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+ struct flag_info_list *tf = flaginfo->flag_list;
+ int with_hex = 0;
+ int without_hex = 0;
+
+ for (tf = flaginfo->flag_list; tf != NULL; tf = tf->next)
+ {
+ unsigned i;
+ flagword (*lookup) (char *);
+
+ lookup = bed->elf_backend_lookup_section_flags_hook;
+ if (lookup != NULL)
+ {
+ flagword hexval = (*lookup) ((char *) tf->name);
+
+ if (hexval != 0)
+ {
+ if (tf->with == with_flags)
+ with_hex |= hexval;
+ else if (tf->with == without_flags)
+ without_hex |= hexval;
+ tf->valid = TRUE;
+ continue;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE (elf_flags_to_names); ++i)
+ {
+ if (strcmp (tf->name, elf_flags_to_names[i].flag_name) == 0)
+ {
+ if (tf->with == with_flags)
+ with_hex |= elf_flags_to_names[i].flag_value;
+ else if (tf->with == without_flags)
+ without_hex |= elf_flags_to_names[i].flag_value;
+ tf->valid = TRUE;
+ break;
+ }
+ }
+ if (!tf->valid)
+ {
+ info->callbacks->einfo
+ (_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name);
+ return FALSE;
+ }
+ }
+ flaginfo->flags_initialized = TRUE;
+ flaginfo->only_with_flags |= with_hex;
+ flaginfo->not_with_flags |= without_hex;
+ }
+
+ if ((flaginfo->only_with_flags & sh_flags) != flaginfo->only_with_flags)
+ return FALSE;
+
+ if ((flaginfo->not_with_flags & sh_flags) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
struct alloc_got_off_arg {
bfd_vma gotoff;
struct bfd_link_info *info;
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && elf_discarded_section (h->root.u.def.section))
+ && discarded_section (h->root.u.def.section))
return TRUE;
else
return FALSE;
/* 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 && elf_discarded_section (isec))
+ if (isec != NULL && discarded_section (isec))
return TRUE;
}
return FALSE;
bed = get_elf_backend_data (abfd);
- if ((abfd->flags & DYNAMIC) != 0)
- continue;
-
eh = NULL;
if (!info->relocatable)
{
eh = bfd_get_section_by_name (abfd, ".eh_frame");
- if (eh != NULL
- && (eh->size == 0
- || bfd_is_abs_section (eh->output_section)))
- eh = NULL;
+ 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 != ELF_INFO_TYPE_STABS))
+ || stab->sec_info_type != SEC_INFO_TYPE_STABS))
stab = NULL;
if (stab == NULL
fini_reloc_cookie_rels (&cookie, stab);
}
- if (eh != NULL
- && init_reloc_cookie_rels (&cookie, info, abfd, eh))
+ while (eh != NULL
+ && init_reloc_cookie_rels (&cookie, info, abfd, eh))
{
_bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
&cookie))
ret = TRUE;
fini_reloc_cookie_rels (&cookie, eh);
+ eh = bfd_get_next_section_by_name (eh);
}
if (bed->elf_backend_discard_info != NULL
return ret;
}
-/* For a SHT_GROUP section, return the group signature. For other
- sections, return the normal section name. */
-
-static const char *
-section_signature (asection *sec)
-{
- if ((sec->flags & SEC_GROUP) != 0
- && elf_next_in_group (sec) != NULL
- && elf_group_name (elf_next_in_group (sec)) != NULL)
- return elf_group_name (elf_next_in_group (sec));
- return sec->name;
-}
-
-void
-_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
+bfd_boolean
+_bfd_elf_section_already_linked (bfd *abfd,
+ asection *sec,
struct bfd_link_info *info)
{
flagword flags;
- const char *name, *p;
+ const char *name, *key;
struct bfd_section_already_linked *l;
struct bfd_section_already_linked_hash_entry *already_linked_list;
if (sec->output_section == bfd_abs_section_ptr)
- return;
+ return FALSE;
flags = sec->flags;
/* Return if it isn't a linkonce section. A comdat group section
also has SEC_LINK_ONCE set. */
if ((flags & SEC_LINK_ONCE) == 0)
- return;
+ return FALSE;
/* Don't put group member sections on our list of already linked
sections. They are handled as a group via their group section. */
if (elf_sec_group (sec) != NULL)
- 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 = section_signature (sec);
+ return FALSE;
- if (CONST_STRNEQ (name, ".gnu.linkonce.")
- && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
- p++;
+ /* For a SHT_GROUP section, use the group signature as the key. */
+ name = sec->name;
+ if ((flags & SEC_GROUP) != 0
+ && elf_next_in_group (sec) != NULL
+ && elf_group_name (elf_next_in_group (sec)) != NULL)
+ key = elf_group_name (elf_next_in_group (sec));
else
- p = name;
+ {
+ /* Otherwise we should have a .gnu.linkonce.<type>.<key> section. */
+ if (CONST_STRNEQ (name, ".gnu.linkonce.")
+ && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
+ key++;
+ else
+ /* Must be a user linkonce section that doesn't follow gcc's
+ naming convention. In this case we won't be matching
+ single member groups. */
+ key = name;
+ }
- already_linked_list = bfd_section_already_linked_table_lookup (p);
+ already_linked_list = bfd_section_already_linked_table_lookup (key);
for (l = already_linked_list->entry; l != NULL; l = l->next)
{
/* We may have 2 different types of sections on the list: group
- sections and linkonce sections. Match like sections. */
- if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
- && strcmp (name, section_signature (l->sec)) == 0
- && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+ sections with a signature of <key> (<key> is some string),
+ and linkonce sections named .gnu.linkonce.<type>.<key>.
+ Match like sections. LTO plugin sections are an exception.
+ They are always named .gnu.linkonce.t.<key> and match either
+ type of section. */
+ if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
+ && ((flags & SEC_GROUP) != 0
+ || strcmp (name, l->sec->name) == 0))
+ || (l->sec->owner->flags & BFD_PLUGIN) != 0)
{
/* 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'"),
- 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"),
- 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"),
- 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'"),
- 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'"),
- 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"),
- 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 (!_bfd_handle_already_linked (sec, l, info))
+ return FALSE;
if (flags & SEC_GROUP)
{
}
}
- return;
+ return TRUE;
}
}
/* A single member comdat group section may be discarded by a
linkonce section and vice versa. */
-
if ((flags & SEC_GROUP) != 0)
{
asection *first = elf_next_in_group (sec);
/* Check this single member group against linkonce sections. */
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, first, info))
{
first->output_section = bfd_abs_section_ptr;
}
/* This is the first section with this name. Record it. */
- if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
+ if (!bfd_section_already_linked_table_insert (already_linked_list, sec))
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
+ return sec->output_section == bfd_abs_section_ptr;
}
bfd_boolean
if (name != NULL)
{
- reloc_sec = bfd_get_section_by_name (abfd, name);
+ reloc_sec = bfd_get_linker_section (abfd, name);
if (reloc_sec != NULL)
elf_section_data (sec)->sreloc = reloc_sec;
if (name == NULL)
return NULL;
- reloc_sec = bfd_get_section_by_name (dynobj, name);
+ reloc_sec = bfd_get_linker_section (dynobj, name);
if (reloc_sec == NULL)
{
- flagword flags;
-
- flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ flagword flags = (SEC_HAS_CONTENTS | SEC_READONLY
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
if ((sec->flags & SEC_ALLOC) != 0)
flags |= SEC_ALLOC | SEC_LOAD;
- reloc_sec = bfd_make_section_with_flags (dynobj, name, flags);
+ reloc_sec = bfd_make_section_anyway_with_flags (dynobj, name, flags);
if (reloc_sec != NULL)
{
if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))