/* ELF linking support for BFD.
- Copyright 1995-2013 Free Software Foundation, Inc.
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
h->def_regular = 1;
h->non_elf = 0;
h->type = STT_OBJECT;
- h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+ if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+ h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
bed = get_elf_backend_data (abfd);
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
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));
}
}
bed = get_elf_backend_data (abfd);
- /* This code is for coping with dynamic objects, and is only useful
- if we are doing an ELF link. */
- if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
- return TRUE;
-
/* For merging, we only care about real symbols. But we need to make
sure that indirect symbol dynamic flags are updated. */
hi = h;
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the
+ existing symbol. */
+
+ oldbfd = NULL;
+ oldsec = NULL;
+ switch (h->root.type)
+ {
+ default:
+ break;
+
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ oldbfd = h->root.u.undef.abfd;
+ break;
+
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ oldbfd = h->root.u.def.section->owner;
+ oldsec = h->root.u.def.section;
+ break;
+
+ case bfd_link_hash_common:
+ oldbfd = h->root.u.c.p->section->owner;
+ oldsec = h->root.u.c.p->section;
+ if (pold_alignment)
+ *pold_alignment = h->root.u.c.p->alignment_power;
+ break;
+ }
+ if (poldbfd && *poldbfd == NULL)
+ *poldbfd = oldbfd;
+
+ /* Differentiate strong and weak symbols. */
+ 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;
+
+ /* This code is for coping with dynamic objects, and is only useful
+ if we are doing an ELF link. */
+ if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
+ return TRUE;
+
/* We have to check it for every instance since the first few may be
references and not all compilers emit symbol type for undefined
symbols. */
return TRUE;
}
- /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the
- existing symbol. */
-
- switch (h->root.type)
- {
- default:
- oldbfd = NULL;
- oldsec = NULL;
- break;
-
- case bfd_link_hash_undefined:
- case bfd_link_hash_undefweak:
- oldbfd = h->root.u.undef.abfd;
- oldsec = NULL;
- break;
-
- case bfd_link_hash_defined:
- case bfd_link_hash_defweak:
- oldbfd = h->root.u.def.section->owner;
- oldsec = h->root.u.def.section;
- break;
-
- case bfd_link_hash_common:
- oldbfd = h->root.u.c.p->section->owner;
- oldsec = h->root.u.c.p->section;
- if (pold_alignment)
- *pold_alignment = h->root.u.c.p->alignment_power;
- break;
- }
- if (poldbfd && *poldbfd == NULL)
- *poldbfd = oldbfd;
-
- /* Differentiate strong and weak symbols. */
- 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
confusion that results if we try to override a symbol with
/* When we try to create a default indirect symbol from the dynamic
definition with the default version, we skip it if its type and
- the type of existing regular definition mismatch. We only do it
- if the existing regular definition won't be dynamic. */
+ the type of existing regular definition mismatch. */
if (pold_alignment == NULL
- && !info->shared
- && !info->export_dynamic
- && !h->ref_dynamic
&& newdyn
&& newdef
&& !olddyn
- && (olddef || h->root.type == bfd_link_hash_common)
- && ELF_ST_TYPE (sym->st_info) != h->type
- && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
- && h->type != STT_NOTYPE
- && !(newfunc && oldfunc))
+ && (((olddef || h->root.type == bfd_link_hash_common)
+ && ELF_ST_TYPE (sym->st_info) != h->type
+ && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE
+ && h->type != STT_NOTYPE
+ && !(newfunc && oldfunc))
+ || (olddef
+ && ((h->type == STT_GNU_IFUNC)
+ != (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))))
{
*skip = TRUE;
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 (!(oldbfd != NULL
&& (oldbfd->flags & BFD_PLUGIN) != 0
&& (abfd->flags & BFD_PLUGIN) == 0))
- *skip = TRUE;
+ {
+ newdef = FALSE;
+ *skip = TRUE;
+ }
/* Merge st_other. If the symbol already has a dynamic index,
but visibility says it should not be visible, turn it into a
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
(*bed->elf_backend_copy_indirect_symbol) (info, ht, hi);
+ /* A reference to the SHORTNAME symbol from a dynamic library
+ will be satisfied by the versioned symbol at runtime. In
+ effect, we have a reference to the versioned symbol. */
+ ht->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
+ hi->dynamic_def |= ht->dynamic_def;
+
/* See if the new flags lead us to realize that the symbol must
be dynamic. */
if (! *dynsym)
size_change_ok = FALSE;
tmp_sec = sec;
if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
- &hi, NULL, NULL, NULL, &skip, &override,
+ &hi, poldbfd, NULL, NULL, &skip, &override,
&type_change_ok, &size_change_ok))
return FALSE;
if (hi->root.type == bfd_link_hash_indirect)
{
(*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
+ h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
+ hi->dynamic_def |= h->dynamic_def;
/* See if the new flags lead us to realize that the symbol
must be dynamic. */
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;
return ibed->relocs_compatible == obed->relocs_compatible;
}
+/* Make a special call to the linker "notice" function to tell it that
+ we are about to handle an as-needed lib, or have finished
+ processing the lib. */
+
+bfd_boolean
+_bfd_elf_notice_as_needed (bfd *ibfd,
+ struct bfd_link_info *info,
+ enum notice_asneeded_action act)
+{
+ return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static bfd_boolean
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
/* Make a special call to the linker "notice" function to
tell it that we are about to handle an as-needed lib. */
- if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
- notice_as_needed, 0, NULL))
+ if (!(*bed->notice_as_needed) (abfd, info, notice_as_needed))
goto error_free_vers;
/* Clone the symbol table. Remember some pointers into the
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,
int ret;
const char *soname = elf_dt_name (abfd);
+ info->callbacks->minfo ("%!", soname, old_bfd,
+ h->root.root.string);
+
/* A symbol from a library loaded via DT_NEEDED of some
other library is referenced by a regular object.
Add a DT_NEEDED entry for it. Issue an error if
unsigned int i;
/* Restore the symbol table. */
- if (bed->as_needed_cleanup)
- (*bed->as_needed_cleanup) (abfd, info);
old_ent = (char *) old_tab + tabsize;
memset (elf_sym_hashes (abfd), 0,
extsymcount * sizeof (struct elf_link_hash_entry *));
/* Make a special call to the linker "notice" function to
tell it that symbols added for crefs may need to be removed. */
- if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
- notice_not_needed, 0, NULL))
+ if (!(*bed->notice_as_needed) (abfd, info, notice_not_needed))
goto error_free_vers;
free (old_tab);
if (old_tab != NULL)
{
- if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
- notice_needed, 0, NULL))
+ if (!(*bed->notice_as_needed) (abfd, info, notice_needed))
goto error_free_vers;
free (old_tab);
old_tab = NULL;
}
/* 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
bfd_boolean localsyms;
bfd_boolean need_second_pass;
bfd_boolean second_pass;
+ bfd_boolean file_sym_done;
struct elf_final_link_info *flinfo;
};
|| h->root.type == bfd_link_hash_defweak)
&& h->root.u.def.section->output_section != NULL))
return TRUE;
+
+ if (!eoinfo->file_sym_done
+ && (eoinfo->second_pass ? eoinfo->flinfo->filesym_count == 1
+ : eoinfo->flinfo->filesym_count > 1))
+ {
+ /* Output a FILE symbol so that following locals are not associated
+ with the wrong input file. */
+ memset (&sym, 0, sizeof (sym));
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+ sym.st_shndx = SHN_ABS;
+ if (!elf_link_output_sym (eoinfo->flinfo, NULL, &sym,
+ bfd_und_section_ptr, NULL))
+ return FALSE;
+
+ eoinfo->file_sym_done = TRUE;
+ }
}
else
{
file, so the contents field will not have been set by any of
the routines which work on output files. */
if (elf_section_data (o)->this_hdr.contents != NULL)
- contents = elf_section_data (o)->this_hdr.contents;
+ {
+ contents = elf_section_data (o)->this_hdr.contents;
+ if (bed->caches_rawsize
+ && o->rawsize != 0
+ && o->rawsize < o->size)
+ {
+ memcpy (flinfo->contents, contents, o->rawsize);
+ contents = flinfo->contents;
+ }
+ }
else
{
contents = flinfo->contents;
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)
{
}
}
- /* 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.localsyms = TRUE;
eoinfo.need_second_pass = FALSE;
eoinfo.second_pass = FALSE;
+ eoinfo.file_sym_done = 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 *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;
info we collected before. */
if (gc_sweep_hook
&& (o->flags & SEC_RELOC) != 0
- && o->reloc_count > 0
+ && o->reloc_count != 0
+ && !((info->strip == strip_all || info->strip == strip_debugger)
+ && (o->flags & SEC_DEBUGGING) != 0)
&& !bfd_is_abs_section (o->output_section))
{
Elf_Internal_Rela *internal_relocs;
bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ struct bfd_elf_dynamic_list *d = info->dynamic_list;
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->ref_dynamic
- || ((!info->executable || info->export_dynamic)
- && h->def_regular
+ || (h->def_regular
&& ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
+ && (!info->executable
+ || info->export_dynamic
+ || (h->dynamic
+ && d != NULL
+ && (*d->match) (&d->head, NULL, h->root.root.string)))
&& (strchr (h->root.root.string, ELF_VER_CHR) != NULL
|| !bfd_hide_sym_by_version (info->version_info,
h->root.root.string)))))
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;
+ asection *i;
- bed = get_elf_backend_data (abfd);
-
- 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);
}
+ }
- while (eh != NULL
- && init_reloc_cookie_rels (&cookie, info, abfd, eh))
+ o = bfd_get_section_by_name (output_bfd, ".eh_frame");
+ if (o != NULL)
+ {
+ asection *i;
+
+ 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);
}
+ }
+
+ 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;
- if (bed->elf_backend_discard_info != NULL
- && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
- ret = TRUE;
+ bed = get_elf_backend_data (abfd);
- fini_reloc_cookie (&cookie, 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. */