return FALSE;
}
- if (! info->traditional_format)
- {
- s = bfd_make_section_with_flags (abfd, ".eh_frame_hdr",
- flags | SEC_READONLY);
- if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, 2))
- return FALSE;
- elf_hash_table (info)->eh_info.hdr_sec = s;
- }
-
/* Create sections to hold version informations. These are removed
if they are not needed. */
s = bfd_make_section_with_flags (abfd, ".gnu.version_d",
return TRUE;
}
\f
+/* Mark a symbol dynamic. */
+
+void
+bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ struct bfd_elf_dynamic_list *d = info->dynamic;
+
+ if (d == NULL || info->relocatable)
+ return;
+
+ if ((*d->match) (&d->head, NULL, h->root.root.string))
+ h->dynamic = 1;
+}
+
/* Record an assignment to a symbol made by a linker script. We need
this in case some dynamic object refers to this symbol. */
}
if (h->root.type == bfd_link_hash_new)
- h->non_elf = 0;
+ {
+ bfd_elf_link_mark_dynamic_symbol (info, h);
+ h->non_elf = 0;
+ }
/* If this symbol is being provided by the linker script, and it is
currently defined by a dynamic object, but not by a regular
struct bfd_link_info *info,
asection *p)
{
+ struct elf_link_hash_table *htab;
+
switch (elf_section_data (p)->this_hdr.sh_type)
{
case SHT_PROGBITS:
/* If sh_type is yet undecided, assume it could be
SHT_PROGBITS/SHT_NOBITS. */
case SHT_NULL:
+ htab = elf_hash_table (info);
+ if (p == htab->tls_sec)
+ return FALSE;
+
+ if (htab->text_index_section != NULL)
+ return p != htab->text_index_section && p != htab->data_index_section;
+
if (strcmp (p->name, ".got") == 0
|| strcmp (p->name, ".got.plt") == 0
|| strcmp (p->name, ".plt") == 0)
{
asection *ip;
- bfd *dynobj = elf_hash_table (info)->dynobj;
- if (dynobj != NULL
- && (ip = bfd_get_section_by_name (dynobj, p->name)) != NULL
+ if (htab->dynobj != NULL
+ && (ip = bfd_get_section_by_name (htab->dynobj, p->name)) != NULL
&& (ip->flags & SEC_LINKER_CREATED)
&& ip->output_section == p)
return TRUE;
&& (p->flags & SEC_ALLOC) != 0
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
elf_section_data (p)->dynindx = ++dynsymcount;
+ else
+ elf_section_data (p)->dynindx = 0;
}
*section_sym_count = dynsymcount;
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 == ELF_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
if (h->root.type == bfd_link_hash_new)
{
+ bfd_elf_link_mark_dynamic_symbol (info, h);
h->non_elf = 0;
return TRUE;
}
{
struct elf_info_failed *eif = data;
+ /* Ignore this if we won't export it. */
+ if (!eif->info->export_dynamic && !h->dynamic)
+ return TRUE;
+
/* Ignore indirect symbols. These are added by the versioning code. */
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
if (h->needs_plt
&& eif->info->shared
&& is_elf_hash_table (eif->info->hash)
- && (eif->info->symbolic
+ && (SYMBOLIC_BIND (eif->info, h)
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
&& h->def_regular)
{
/* Identify the cases where name binding rules say that a
visible symbol resolves locally. */
- binding_stays_local_p = info->executable || info->symbolic;
+ binding_stays_local_p = info->executable || SYMBOLIC_BIND (info, h);
switch (ELF_ST_VISIBILITY (h->other))
{
/* At this point, we know the symbol is defined and dynamic. In an
executable it must resolve locally, likewise when building symbolic
shared libraries. */
- if (info->executable || info->symbolic)
+ if (info->executable || SYMBOLIC_BIND (info, h))
return TRUE;
/* Now deal with defined dynamic symbols in shared libraries. Ones
const char *name;
name = bfd_get_section_name (abfd, s);
- if (strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0)
+ if (CONST_STRNEQ (name, ".gnu.warning."))
{
char *msg;
bfd_size_type sz;
sec = bfd_abs_section_ptr;
else if (sec->kept_section)
{
- /* Symbols from discarded section are undefined, and have
- default visibility. */
+ /* Symbols from discarded section are undefined. We keep
+ its visibility. */
sec = bfd_und_section_ptr;
isym->st_shndx = SHN_UNDEF;
- isym->st_other = (STV_DEFAULT
- | (isym->st_other & ~ ELF_ST_VISIBILITY (-1)));
}
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
value -= sec->vma;
isym->st_other = (STV_HIDDEN
| (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
- if (isym->st_other != 0 && !dynamic)
+ if (ELF_ST_VISIBILITY (isym->st_other) != 0 && !dynamic)
{
unsigned char hvis, symvis, other, nvis;
- /* Take the balance of OTHER from the definition. */
- other = (definition ? isym->st_other : h->other);
- other &= ~ ELF_ST_VISIBILITY (-1);
+ /* 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);
dynsym = TRUE;
}
+ if (definition && (sec->flags & SEC_DEBUGGING))
+ {
+ /* We don't want to make debug symbol dynamic. */
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ dynsym = FALSE;
+ }
+
/* Check to see if we need to add an indirect symbol for
the default name. */
if (definition || h->root.type == bfd_link_hash_common)
asection *stab;
for (stab = abfd->sections; stab; stab = stab->next)
- if (strncmp (".stab", stab->name, 5) == 0
+ if (CONST_STRNEQ (stab->name, ".stab")
&& (!stab->name[5] ||
(stab->name[5] == '.' && ISDIGIT (stab->name[6])))
&& (stab->flags & SEC_MERGE) == 0
&& ! (*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
if (dynobj == NULL)
return TRUE;
- if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
- return FALSE;
-
if (elf_hash_table (info)->dynamic_sections_created)
{
struct elf_info_failed eif;
/* If we are supposed to export all symbols into the dynamic symbol
table (this is not the normal case), then do so. */
- if (info->export_dynamic)
+ if (info->export_dynamic
+ || (info->executable && info->dynamic))
{
elf_link_hash_traverse (elf_hash_table (info),
_bfd_elf_export_symbol,
return TRUE;
}
+/* Find the first non-excluded output section. We'll use its
+ section symbol for some emitted relocs. */
+void
+_bfd_elf_init_1_index_section (bfd *output_bfd, struct bfd_link_info *info)
+{
+ asection *s;
+
+ for (s = output_bfd->sections; s != NULL; s = s->next)
+ if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC
+ && !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
+ {
+ elf_hash_table (info)->text_index_section = s;
+ break;
+ }
+}
+
+/* Find two non-excluded output sections, one for code, one for data.
+ We'll use their section symbols for some emitted relocs. */
+void
+_bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info)
+{
+ asection *s;
+
+ for (s = output_bfd->sections; s != NULL; s = s->next)
+ if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
+ == (SEC_ALLOC | SEC_READONLY))
+ && !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
+ {
+ elf_hash_table (info)->text_index_section = s;
+ break;
+ }
+
+ for (s = output_bfd->sections; s != NULL; s = s->next)
+ if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
+ && !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s))
+ {
+ elf_hash_table (info)->data_index_section = s;
+ break;
+ }
+
+ if (elf_hash_table (info)->text_index_section == NULL)
+ elf_hash_table (info)->text_index_section
+ = elf_hash_table (info)->data_index_section;
+}
+
bfd_boolean
bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
{
+ const struct elf_backend_data *bed;
+
if (!is_elf_hash_table (info->hash))
return TRUE;
+ bed = get_elf_backend_data (output_bfd);
+ (*bed->elf_backend_init_index_section) (output_bfd, info);
+
if (elf_hash_table (info)->dynamic_sections_created)
{
bfd *dynobj;
- const struct elf_backend_data *bed;
asection *s;
bfd_size_type dynsymcount;
unsigned long section_sym_count;
section as we went along in elf_link_add_object_symbols. */
s = bfd_get_section_by_name (dynobj, ".dynsym");
BFD_ASSERT (s != NULL);
- bed = get_elf_backend_data (output_bfd);
s->size = dynsymcount * bed->s->sizeof_sym;
if (dynsymcount != 0)
if (h->dynindx != -1
&& elf_hash_table (finfo->info)->dynamic_sections_created)
{
- size_t bucketcount;
- size_t bucket;
bfd_byte *esym;
sym.st_name = h->dynstr_index;
}
bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0);
- bucketcount = elf_hash_table (finfo->info)->bucketcount;
- bucket = h->u.elf_hash_value % bucketcount;
-
if (finfo->hash_sec != NULL)
{
size_t hash_entry_size;
bfd_byte *bucketpos;
bfd_vma chain;
+ size_t bucketcount;
+ size_t bucket;
+
+ bucketcount = elf_hash_table (finfo->info)->bucketcount;
+ bucket = h->u.elf_hash_value % bucketcount;
hash_entry_size
= elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
/* Find a match between a section and a member of a section group. */
static asection *
-match_group_member (asection *sec, asection *group)
+match_group_member (asection *sec, asection *group,
+ struct bfd_link_info *info)
{
asection *first = elf_next_in_group (group);
asection *s = first;
while (s != NULL)
{
- if (bfd_elf_match_symbols_in_sections (s, sec))
+ if (bfd_elf_match_symbols_in_sections (s, sec, info))
return s;
s = elf_next_in_group (s);
}
/* Check if the kept section of a discarded section SEC can be used
- to replace it. Return the replacement if it is OK. Otherwise return
- NULL. */
+ to replace it. Return the replacement if it is OK. Otherwise return
+ NULL. */
asection *
-_bfd_elf_check_kept_section (asection *sec)
+_bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info)
{
asection *kept;
kept = sec->kept_section;
if (kept != NULL)
{
- if (elf_sec_group (sec) != NULL)
- kept = match_group_member (sec, kept);
+ if ((kept->flags & SEC_GROUP) != 0)
+ kept = match_group_member (sec, kept, info);
if (kept != NULL && sec->size != kept->size)
kept = NULL;
+ sec->kept_section = kept;
}
return kept;
}
{
asection *kept;
- kept = _bfd_elf_check_kept_section (sec);
+ kept = _bfd_elf_check_kept_section (sec,
+ finfo->info);
if (kept != NULL)
{
*ps = kept;
if (!bfd_is_abs_section (osec))
{
r_symndx = osec->target_index;
+ if (r_symndx == 0)
+ {
+ 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;
+ }
+ }
+
BFD_ASSERT (r_symndx != 0);
}
}
}
}
+ /* Free symbol buffer if needed. */
+ if (!info->reduce_memory_overheads)
+ {
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ if (elf_tdata (sub)->symbuf)
+ {
+ free (elf_tdata (sub)->symbuf);
+ elf_tdata (sub)->symbuf = NULL;
+ }
+ }
+
/* 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
\f
/* Garbage collect unused sections. */
-/* The mark phase of garbage collection. For a given section, mark
- it and any sections in this section's group, and all the sections
- which define symbols to which it refers. */
-
typedef asection * (*gc_mark_hook_fn)
(asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *);
+/* Default gc_mark_hook. */
+
+asection *
+_bfd_elf_gc_mark_hook (asection *sec,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ Elf_Internal_Rela *rel ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ if (h != NULL)
+ {
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+
+ default:
+ break;
+ }
+ }
+ else
+ return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+ return NULL;
+}
+
+/* The mark phase of garbage collection. For a given section, mark
+ it and any sections in this section's group, and all the sections
+ which define symbols to which it refers. */
+
bfd_boolean
_bfd_elf_gc_mark (struct bfd_link_info *info,
asection *sec,
/* Sweep symbols in swept sections. Called via elf_link_hash_traverse. */
-struct elf_gc_sweep_symbol_info {
+struct elf_gc_sweep_symbol_info
+{
struct bfd_link_info *info;
void (*hide_symbol) (struct bfd_link_info *, struct elf_link_hash_entry *,
bfd_boolean);
to remove a section from the output. */
o->flags |= SEC_EXCLUDE;
+ if (info->print_gc_sections == TRUE)
+ _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
+
/* But we also have to update some of the relocation
info we collected before. */
if (gc_sweep_hook
continue;
for (o = sub->sections; o != NULL; o = o->next)
- if ((o->flags & SEC_KEEP) != 0 && !o->gc_mark)
+ if ((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP && !o->gc_mark)
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
}
easily due to needing special relocs to handle the
difference of two symbols in separate sections.
Don't keep code sections referenced by .eh_frame. */
+#define TEXT_PREFIX ".text."
+#define GCC_EXCEPT_TABLE_PREFIX ".gcc_except_table."
for (o = sub->sections; o != NULL; o = o->next)
if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
{
- if (strncmp (o->name, ".gcc_except_table.", 18) == 0)
+ if (CONST_STRNEQ (o->name, GCC_EXCEPT_TABLE_PREFIX))
{
- unsigned long len;
char *fn_name;
+ const char *sec_name;
asection *fn_text;
+ unsigned o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX);
+ unsigned fn_name_prefix_len = strlen (TEXT_PREFIX);
- len = strlen (o->name + 18) + 1;
- fn_name = bfd_malloc (len + 6);
+ sec_name = o->name + o_name_prefix_len;
+ fn_name = bfd_malloc (strlen (sec_name) + fn_name_prefix_len + 1);
if (fn_name == NULL)
return FALSE;
- memcpy (fn_name, ".text.", 6);
- memcpy (fn_name + 6, o->name + 18, len);
+ sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name);
fn_text = bfd_get_section_by_name (sub, fn_name);
free (fn_name);
if (fn_text == NULL || !fn_text->gc_mark)
}
void
-_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
+_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section *sec,
+ struct bfd_link_info *info)
{
flagword flags;
const char *name, *p;
struct bfd_section_already_linked *l;
struct bfd_section_already_linked_hash_entry *already_linked_list;
- asection *group;
- /* A single member comdat group section may be discarded by a
- linkonce section. See below. */
if (sec->output_section == bfd_abs_section_ptr)
return;
flags = sec->flags;
- /* Check if it belongs to a section group. */
- group = elf_sec_group (sec);
-
- /* Return if it isn't a linkonce section nor a member of a group. A
- comdat group section also has SEC_LINK_ONCE set. */
- if ((flags & SEC_LINK_ONCE) == 0 && group == NULL)
+ /* Return if it isn't a linkonce section. A comdat group section
+ also has SEC_LINK_ONCE set. */
+ if ((flags & SEC_LINK_ONCE) == 0)
return;
- if (group)
- {
- /* If this is the member of a single member comdat group, check if
- the group should be discarded. */
- if (elf_next_in_group (sec) == sec
- && (group->flags & SEC_LINK_ONCE) != 0)
- sec = group;
- else
- return;
- }
+ /* 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
name = bfd_get_section_name (abfd, sec);
- if (strncmp (name, ".gnu.linkonce.", sizeof (".gnu.linkonce.") - 1) == 0
+ if (CONST_STRNEQ (name, ".gnu.linkonce.")
&& (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
p++;
else
for (l = already_linked_list->entry; l != NULL; l = l->next)
{
- /* We may have 3 different sections on the list: group section,
- comdat section and linkonce section. SEC may be a linkonce or
- group section. We match a group section with a group section,
- a linkonce section with a linkonce section, and ignore comdat
- section. */
+ /* 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, l->sec->name) == 0
&& bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
}
}
- if (group)
+ /* A single member comdat group section may be discarded by a
+ linkonce section and vice versa. */
+
+ if ((flags & SEC_GROUP) != 0)
{
- /* If this is the member of a single member comdat group and the
- group hasn't be discarded, we check if it matches a linkonce
- section. We only record the discarded comdat group. Otherwise
- the undiscarded group will be discarded incorrectly later since
- itself has been recorded. */
- for (l = already_linked_list->entry; l != NULL; l = l->next)
- if ((l->sec->flags & SEC_GROUP) == 0
- && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
- && bfd_elf_match_symbols_in_sections (l->sec,
- elf_next_in_group (sec)))
- {
- elf_next_in_group (sec)->output_section = bfd_abs_section_ptr;
- elf_next_in_group (sec)->kept_section = l->sec;
- group->output_section = bfd_abs_section_ptr;
- break;
- }
- if (l == NULL)
- return;
+ asection *first = elf_next_in_group (sec);
+
+ if (first != NULL && elf_next_in_group (first) == first)
+ /* 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;
+ first->kept_section = l->sec;
+ sec->output_section = bfd_abs_section_ptr;
+ break;
+ }
}
else
- /* There is no direct match. But for linkonce section, we should
- check if there is a match with comdat group member. We always
- record the linkonce section, discarded or not. */
+ /* Check this linkonce section against single member groups. */
for (l = already_linked_list->entry; l != NULL; l = l->next)
if (l->sec->flags & SEC_GROUP)
{
if (first != NULL
&& elf_next_in_group (first) == first
- && bfd_elf_match_symbols_in_sections (first, sec))
+ && bfd_elf_match_symbols_in_sections (first, sec, info))
{
sec->output_section = bfd_abs_section_ptr;
- sec->kept_section = l->sec;
+ sec->kept_section = first;
break;
}
}