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;
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;
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)
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;
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;
+ /* 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 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
{
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;
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;
+ /* PR 12549: Note if the dynamic reference is weak. */
+ h->ref_dynamic_nonweak = (bind != STB_WEAK);
}
}
- 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;
+ /* PR 12549: Note if the dynamic reference is weak. */
+ hi->ref_dynamic_nonweak =
+ h->ref_dynamic_nonweak = (bind != STB_WEAK);
+ }
else
{
h->def_dynamic = 1;
h->dynamic_def = 1;
+ hi->def_dynamic = 1;
+ hi->dynamic_def = 1;
}
- if (h->def_regular
- || h->ref_regular
- || (h->u.weakdef != NULL
- && ! new_weakdef
- && h->u.weakdef->dynindx != -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;
}
if (!add_needed
&& definition
&& ((dynsym
- && h->ref_regular)
- || (h->ref_dynamic
+ && h->ref_regular_nonweak)
+ || (h->ref_dynamic_nonweak
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
&& !on_needed_list (elf_dt_name (abfd), htab->needed))))
{
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[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 [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)
{
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
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)
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)
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
/* 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);
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;
+ bfd_boolean need_second_pass;
+ bfd_boolean second_pass;
struct elf_final_link_info *flinfo;
};
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:
{
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
{
{
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");
else
msg = _("%B: local symbol `%s' in %B is referenced by DSO");
def_bfd = flinfo->output_bfd;
- if (h->root.u.def.section != bfd_abs_section_ptr)
- def_bfd = h->root.u.def.section->owner;
+ 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);
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 (flinfo->output_bfd,
input_sec->output_section);
{
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 = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
if (!check_dynsym (flinfo->output_bfd, &sym))
bfd_size_type address_size;
bfd_vma r_type_mask;
int r_sym_shift;
+ bfd_boolean have_file_sym = FALSE;
output_bfd = flinfo->output_bfd;
bed = get_elf_backend_data (output_bfd);
&& 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. */
}
else
{
- flinfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
- flinfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
+ 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_section_by_name (dynobj, ".gnu.version");
+ flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version");
/* Note that it is OK if symver_sec is 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
}
}
+ /* Output a FILE symbol so that following locals are not associated
+ with the wrong input file. */
+ memset (&elfsym, 0, sizeof (elfsym));
+ elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+ elfsym.st_shndx = SHN_ABS;
+
+ if (flinfo.filesym_count > 1
+ && !elf_link_output_sym (&flinfo, NULL, &elfsym,
+ bfd_und_section_ptr, NULL))
+ return FALSE;
+
/* Output any global symbols that got converted to local in a
version script or due to symbol visibility. We do this in a
separate step since ELF requires all local symbols to appear
eoinfo.failed = FALSE;
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)
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;
/* Check for DT_TEXTREL (late, in case the backend removes it). */
if (((info->warn_shared_textrel && info->shared)
|| info->error_textrel)
- && (o = bfd_get_section_by_name (dynobj, ".dynamic")) != NULL)
+ && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
{
bfd_byte *dyncon, *dynconend;
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,
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);
bed = get_elf_backend_data (abfd);
- if ((abfd->flags & DYNAMIC) != 0)
- continue;
-
eh = NULL;
if (!info->relocatable)
{
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))