h = *sym_hash;
}
- if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root)
- && bfd_is_und_section (sec))
- {
- /* If the new symbol is undefined and the old symbol was
- also undefined before, we need to make sure
- _bfd_generic_link_add_one_symbol doesn't mess
- up the linker hash table undefs list. Since the old
- definition came from a dynamic object, it is still on the
- undefs list. */
+ /* 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)
+ {
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;
&& ! (*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;
/* 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;
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 (!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
{
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_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. */
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)
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)
{
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");
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