static void
elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
- Elf_Internal_Sym *isym, bfd_boolean definition,
- bfd_boolean dynamic)
+ const Elf_Internal_Sym *isym,
+ bfd_boolean definition, bfd_boolean dynamic)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
/* If st_other has a processor-specific meaning, specific
- code might be needed here. We never merge the visibility
- attribute with the one from a dynamic object. */
+ code might be needed here. */
if (bed->elf_backend_merge_symbol_attribute)
(*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
dynamic);
- /* If this symbol has default visibility and the user has requested
- we not re-export it, then mark it as hidden. */
- if (definition
- && !dynamic
- && (abfd->no_export
- || (abfd->my_archive && abfd->my_archive->no_export))
- && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
- isym->st_other = (STV_HIDDEN
- | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
-
- if (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0)
- {
- unsigned char hvis, symvis, other, nvis;
-
- /* Only merge the visibility. Leave the remainder of the
- st_other field to elf_backend_merge_symbol_attribute. */
- other = h->other & ~ELF_ST_VISIBILITY (-1);
-
- /* Combine visibilities, using the most constraining one. */
- hvis = ELF_ST_VISIBILITY (h->other);
- symvis = ELF_ST_VISIBILITY (isym->st_other);
- if (! hvis)
- nvis = symvis;
- else if (! symvis)
- nvis = hvis;
- else
- nvis = hvis < symvis ? hvis : symvis;
+ if (!dynamic)
+ {
+ unsigned symvis = ELF_ST_VISIBILITY (isym->st_other);
+ unsigned hvis = ELF_ST_VISIBILITY (h->other);
- h->other = other | nvis;
+ /* Keep the most constraining visibility. Leave the remainder
+ of the st_other field to elf_backend_merge_symbol_attribute. */
+ if (symvis - 1 < hvis - 1)
+ h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1));
}
}
return TRUE;
}
- /* Plugin symbol type isn't currently set. Stop bogus errors. */
- if (oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0)
- *type_change_ok = TRUE;
-
- /* Check TLS symbol. We don't check undefined symbol introduced by
- "ld -u". */
- else if (oldbfd != NULL
- && ELF_ST_TYPE (sym->st_info) != h->type
- && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS))
+ /* Check TLS symbols. We don't check undefined symbols introduced
+ by "ld -u" which have no type (and oldbfd NULL), and we don't
+ check symbols from plugins because they also have no type. */
+ if (oldbfd != NULL
+ && (oldbfd->flags & BFD_PLUGIN) == 0
+ && (abfd->flags & BFD_PLUGIN) == 0
+ && ELF_ST_TYPE (sym->st_info) != h->type
+ && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS))
{
bfd *ntbfd, *tbfd;
bfd_boolean ntdef, tdef;
if (! bfd_check_format (abfd, bfd_object))
return FALSE;
- /* If we have already included the element containing this symbol in the
- link then we do not need to include it again. Just claim that any symbol
- it contains is not a definition, so that our caller will not decide to
- (re)include this element. */
- if (abfd->archive_pass)
- return FALSE;
-
/* Select the appropriate symbol table. */
if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
hdr = &elf_tdata (abfd)->symtab_hdr;
on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
{
for (; needed != NULL; needed = needed->next)
- if (strcmp (soname, needed->name) == 0)
+ if ((elf_dyn_lib_class (needed->by) & DYN_AS_NEEDED) == 0
+ && strcmp (soname, needed->name) == 0)
return TRUE;
return FALSE;
struct bfd_link_info *info,
enum notice_asneeded_action act)
{
- return (*info->callbacks->notice) (info, NULL, ibfd, NULL, act, 0, NULL);
+ return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
}
/* Add symbols from an ELF object file to the linker hash table. */
bfd_size_type old_dynstr_size = 0;
size_t tabsize = 0;
asection *s;
+ bfd_boolean just_syms;
htab = elf_hash_table (info);
bed = get_elf_backend_data (abfd);
}
}
+ just_syms = ((s = abfd->sections) != NULL
+ && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS);
+
add_needed = TRUE;
if (! dynamic)
{
/* If we are creating a shared library, create all the dynamic
sections immediately. We need to attach them to something,
so we attach them to this BFD, provided it is the right
- format. FIXME: If there are no input BFD's of the same
- format as the output, we can't make a shared library. */
- if (info->shared
+ format and is not from ld --just-symbols. FIXME: If there
+ are no input BFD's of the same format as the output, we can't
+ make a shared library. */
+ if (!just_syms
+ && info->shared
&& is_elf_hash_table (htab)
&& info->output_bfd->xvec == abfd->xvec
&& !htab->dynamic_sections_created)
/* ld --just-symbols and dynamic objects don't mix very well.
ld shouldn't allow it. */
- if ((s = abfd->sections) != NULL
- && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ if (just_syms)
abort ();
/* If this dynamic lib was specified on the command line with
name = newname;
}
+ /* If this symbol has default visibility and the user has
+ requested we not re-export it, then mark it as hidden. */
+ if (definition
+ && !dynamic
+ && (abfd->no_export
+ || (abfd->my_archive && abfd->my_archive->no_export))
+ && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL)
+ isym->st_other = (STV_HIDDEN
+ | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
+
if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
sym_hash, &old_bfd, &old_weak,
&old_alignment, &skip, &override,
}
/* Add symbols from an ELF archive file to the linker hash table. We
- don't use _bfd_generic_link_add_archive_symbols because of a
- problem which arises on UnixWare. The UnixWare libc.so is an
- archive which includes an entry libc.so.1 which defines a bunch of
- symbols. The libc.so archive also includes a number of other
- object files, which also define symbols, some of which are the same
- as those defined in libc.so.1. Correct linking requires that we
- consider each object file in turn, and include it if it defines any
- symbols we need. _bfd_generic_link_add_archive_symbols does not do
- this; it looks through the list of undefined symbols, and includes
- any object file which defines them. When this algorithm is used on
- UnixWare, it winds up pulling in libc.so.1 early and defining a
- bunch of symbols. This means that some of the other objects in the
- archive are not included in the link, which is incorrect since they
- precede libc.so.1 in the archive.
+ don't use _bfd_generic_link_add_archive_symbols because we need to
+ handle versioned symbols.
Fortunately, ELF archive handling is simpler than that done by
_bfd_generic_link_add_archive_symbols, which has to allow for a.out
elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
{
symindex c;
- bfd_boolean *defined = NULL;
- bfd_boolean *included = NULL;
+ unsigned char *included = NULL;
carsym *symdefs;
bfd_boolean loop;
bfd_size_type amt;
if (c == 0)
return TRUE;
amt = c;
- amt *= sizeof (bfd_boolean);
- defined = (bfd_boolean *) bfd_zmalloc (amt);
- included = (bfd_boolean *) bfd_zmalloc (amt);
- if (defined == NULL || included == NULL)
- goto error_return;
+ amt *= sizeof (*included);
+ included = (unsigned char *) bfd_zmalloc (amt);
+ if (included == NULL)
+ return FALSE;
symdefs = bfd_ardata (abfd)->symdefs;
bed = get_elf_backend_data (abfd);
struct bfd_link_hash_entry *undefs_tail;
symindex mark;
- if (defined[i] || included[i])
+ if (included[i])
continue;
if (symdef->file_offset == last)
{
else if (h->root.type != bfd_link_hash_undefined)
{
if (h->root.type != bfd_link_hash_undefweak)
- defined[i] = TRUE;
+ /* Symbol must be defined. Don't check it again. */
+ included[i] = TRUE;
continue;
}
if (! bfd_check_format (element, bfd_object))
goto error_return;
- /* Doublecheck that we have not included this object
- already--it should be impossible, but there may be
- something wrong with the archive. */
- if (element->archive_pass != 0)
- {
- bfd_set_error (bfd_error_bad_value);
- goto error_return;
- }
- element->archive_pass = 1;
-
undefs_tail = info->hash->undefs_tail;
if (!(*info->callbacks
}
while (loop);
- free (defined);
free (included);
return TRUE;
error_return:
- if (defined != NULL)
- free (defined);
if (included != NULL)
free (included);
return FALSE;
{
bfd *ibfd;
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour
&& !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr))
return FALSE;
for (inputobj = info->input_bfds;
inputobj;
- inputobj = inputobj->link_next)
+ inputobj = inputobj->link.next)
{
asection *s;
asection *o;
for (sub = info->input_bfds; sub != NULL;
- sub = sub->link_next)
+ sub = sub->link.next)
if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
for (o = sub->sections; o != NULL; o = o->next)
if (elf_section_data (o)->this_hdr.sh_type
if (!is_elf_hash_table (info->hash))
return FALSE;
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
if ((ibfd->flags & DYNAMIC) == 0)
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
if ((sec->flags & SEC_MERGE) != 0
free (ret);
return NULL;
}
+ ret->root.hash_table_free = _bfd_elf_link_hash_table_free;
return &ret->root;
}
/* Destroy an ELF linker hash table. */
void
-_bfd_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
+_bfd_elf_link_hash_table_free (bfd *obfd)
{
- struct elf_link_hash_table *htab = (struct elf_link_hash_table *) hash;
+ struct elf_link_hash_table *htab;
+
+ htab = (struct elf_link_hash_table *) obfd->link.hash;
if (htab->dynstr != NULL)
_bfd_elf_strtab_free (htab->dynstr);
_bfd_merge_sections_free (htab->merge_info);
- _bfd_generic_link_hash_table_free (hash);
+ _bfd_generic_link_hash_table_free (obfd);
}
/* This is a hook for the ELF emulation code in the generic linker to
esdo->rela.count = 0;
}
- _bfd_elf_assign_file_positions_for_relocs (abfd);
-
/* We have now assigned file positions for all the sections except
- .symtab and .strtab. We start the .symtab section at the current
- file position, and write directly to it. We build the .strtab
- section in memory. */
+ .symtab, .strtab, and non-loaded reloc sections. We start the
+ .symtab section at the current file position, and write directly
+ to it. We build the .strtab section in memory. */
bfd_get_symcount (abfd) = 0;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
/* sh_name is set in prep_headers. */
we could write the relocs out and then read them again; I don't
know how bad the memory loss will be. */
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
sub->output_has_begun = FALSE;
for (o = abfd->sections; o != NULL; o = o->next)
{
/* Free symbol buffer if needed. */
if (!info->reduce_memory_overheads)
{
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
if (bfd_get_flavour (sub) == bfd_target_elf_flavour
&& elf_tdata (sub)->symbuf)
{
{
bfd *i;
- for (i = info->input_bfds; i; i = i->link_next)
+ for (i = info->input_bfds; i; i = i->link.next)
{
sec = bfd_get_section_by_name (i, sec_name);
if (sec)
{
bfd *ibfd;
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
asection *isec;
bfd_boolean some_kept;
unsigned long section_sym_count;
struct elf_gc_sweep_symbol_info sweep_info;
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *o;
bfd *sub;
elf_gc_mark_hook_fn gc_mark_hook;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct elf_link_hash_table *htab;
if (!bed->can_gc_sections
|| !is_elf_hash_table (info->hash))
}
bed->gc_keep (info);
+ htab = elf_hash_table (info);
/* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section
at the .eh_frame section if we can mark the FDEs individually. */
- _bfd_elf_begin_eh_frame_parsing (info);
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *sec;
struct elf_reloc_cookie cookie;
sec = bfd_get_next_section_by_name (sec);
}
}
- _bfd_elf_end_eh_frame_parsing (info);
/* Apply transitive closure to the vtable entry usage info. */
- elf_link_hash_traverse (elf_hash_table (info),
- elf_gc_propagate_vtable_entries_used,
- &ok);
+ elf_link_hash_traverse (htab, elf_gc_propagate_vtable_entries_used, &ok);
if (!ok)
return FALSE;
/* Kill the vtable relocations that were not used. */
- elf_link_hash_traverse (elf_hash_table (info),
- elf_gc_smash_unused_vtentry_relocs,
- &ok);
+ elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok);
if (!ok)
return FALSE;
/* Mark dynamically referenced symbols. */
- if (elf_hash_table (info)->dynamic_sections_created)
- elf_link_hash_traverse (elf_hash_table (info),
- bed->gc_mark_dynamic_ref,
- info);
+ if (htab->dynamic_sections_created)
+ elf_link_hash_traverse (htab, bed->gc_mark_dynamic_ref, info);
/* Grovel through relocs to find out who stays ... */
gc_mark_hook = bed->gc_mark_hook;
- for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *o;
gotoff = bed->got_header_size;
/* Do the local .got entries first. */
- for (i = info->input_bfds; i; i = i->link_next)
+ for (i = info->input_bfds; i; i = i->link.next)
{
bfd_signed_vma *local_got;
bfd_size_type j, locsymcount;
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && discarded_section (h->root.u.def.section))
+ && (h->root.u.def.section->owner != rcookie->abfd
+ || h->root.u.def.section->kept_section != NULL
+ || discarded_section (h->root.u.def.section)))
return TRUE;
- else
- return FALSE;
}
else
{
/* Need to: get the symbol; get the section. */
isym = &rcookie->locsyms[r_symndx];
isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
- if (isec != NULL && discarded_section (isec))
+ if (isec != NULL
+ && (isec->kept_section != NULL
+ || discarded_section (isec)))
return TRUE;
}
return FALSE;
}
/* Discard unneeded references to discarded sections.
- Returns TRUE if any section's size was changed. */
-/* This function assumes that the relocations are in sorted order,
- which is true for all known assemblers. */
+ Returns -1 on error, 1 if any section's size was changed, 0 if
+ nothing changed. This function assumes that the relocations are in
+ sorted order, which is true for all known assemblers. */
-bfd_boolean
+int
bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
{
struct elf_reloc_cookie cookie;
- asection *stab, *eh;
- const struct elf_backend_data *bed;
+ asection *o;
bfd *abfd;
- bfd_boolean ret = FALSE;
+ int changed = 0;
if (info->traditional_format
|| !is_elf_hash_table (info->hash))
- return FALSE;
+ return 0;
- _bfd_elf_begin_eh_frame_parsing (info);
- for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ o = bfd_get_section_by_name (output_bfd, ".stab");
+ if (o != NULL)
{
- if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
- continue;
-
- bed = get_elf_backend_data (abfd);
+ asection *i;
- eh = NULL;
- if (!info->relocatable)
+ for (i = o->map_head.s; i != NULL; i = i->map_head.s)
{
- eh = bfd_get_section_by_name (abfd, ".eh_frame");
- while (eh != NULL
- && (eh->size == 0
- || bfd_is_abs_section (eh->output_section)))
- eh = bfd_get_next_section_by_name (eh);
- }
-
- stab = bfd_get_section_by_name (abfd, ".stab");
- if (stab != NULL
- && (stab->size == 0
- || bfd_is_abs_section (stab->output_section)
- || stab->sec_info_type != SEC_INFO_TYPE_STABS))
- stab = NULL;
+ if (i->size == 0
+ || i->reloc_count == 0
+ || i->sec_info_type != SEC_INFO_TYPE_STABS)
+ continue;
- if (stab == NULL
- && eh == NULL
- && bed->elf_backend_discard_info == NULL)
- continue;
+ abfd = i->owner;
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
- if (!init_reloc_cookie (&cookie, info, abfd))
- return FALSE;
+ if (!init_reloc_cookie_for_section (&cookie, info, i))
+ return -1;
- if (stab != NULL
- && stab->reloc_count > 0
- && init_reloc_cookie_rels (&cookie, info, abfd, stab))
- {
- if (_bfd_discard_section_stabs (abfd, stab,
- elf_section_data (stab)->sec_info,
+ if (_bfd_discard_section_stabs (abfd, i,
+ elf_section_data (i)->sec_info,
bfd_elf_reloc_symbol_deleted_p,
&cookie))
- ret = TRUE;
- fini_reloc_cookie_rels (&cookie, stab);
+ changed = 1;
+
+ fini_reloc_cookie_for_section (&cookie, i);
}
+ }
+
+ o = bfd_get_section_by_name (output_bfd, ".eh_frame");
+ if (o != NULL)
+ {
+ asection *i;
- while (eh != NULL
- && init_reloc_cookie_rels (&cookie, info, abfd, eh))
+ for (i = o->map_head.s; i != NULL; i = i->map_head.s)
{
- _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
- if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
+ if (i->size == 0)
+ continue;
+
+ abfd = i->owner;
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
+
+ if (!init_reloc_cookie_for_section (&cookie, info, i))
+ return -1;
+
+ _bfd_elf_parse_eh_frame (abfd, info, i, &cookie);
+ if (_bfd_elf_discard_section_eh_frame (abfd, info, i,
bfd_elf_reloc_symbol_deleted_p,
&cookie))
- ret = TRUE;
- fini_reloc_cookie_rels (&cookie, eh);
- eh = bfd_get_next_section_by_name (eh);
+ changed = 1;
+
+ fini_reloc_cookie_for_section (&cookie, i);
}
+ }
- if (bed->elf_backend_discard_info != NULL
- && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
- ret = TRUE;
+ for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
+ {
+ const struct elf_backend_data *bed;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
- fini_reloc_cookie (&cookie, abfd);
+ bed = get_elf_backend_data (abfd);
+
+ if (bed->elf_backend_discard_info != NULL)
+ {
+ if (!init_reloc_cookie (&cookie, info, abfd))
+ return -1;
+
+ if ((*bed->elf_backend_discard_info) (abfd, &cookie, info))
+ changed = 1;
+
+ fini_reloc_cookie (&cookie, abfd);
+ }
}
- _bfd_elf_end_eh_frame_parsing (info);
if (info->eh_frame_hdr
&& !info->relocatable
&& _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info))
- ret = TRUE;
+ changed = 1;
- return ret;
+ return changed;
}
bfd_boolean
return reloc_sec;
}
-/* Copy the ELF symbol type associated with a linker hash entry. */
+/* Copy the ELF symbol type and other attributes for a linker script
+ assignment from HSRC to HDEST. Generally this should be treated as
+ if we found a strong non-dynamic definition for HDEST (except that
+ ld ignores multiple definition errors). */
void
-_bfd_elf_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_hash_entry * hdest,
- struct bfd_link_hash_entry * hsrc)
+_bfd_elf_copy_link_hash_symbol_type (bfd *abfd,
+ struct bfd_link_hash_entry *hdest,
+ struct bfd_link_hash_entry *hsrc)
{
- struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *)hdest;
- struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc;
+ struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *) hdest;
+ struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *) hsrc;
+ Elf_Internal_Sym isym;
ehdest->type = ehsrc->type;
ehdest->target_internal = ehsrc->target_internal;
+
+ isym.st_other = ehsrc->other;
+ elf_merge_st_other (abfd, ehdest, &isym, TRUE, FALSE);
}
/* Append a RELA relocation REL to section S in BFD. */