Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
-This file is part of BFD, the Binary File Descriptor library.
+ This file is part of BFD, the Binary File Descriptor library.
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
h = (struct elf_link_hash_entry *) bh;
h->def_regular = 1;
h->type = STT_OBJECT;
+ h->other = STV_HIDDEN;
if (! info->executable
&& ! bfd_elf_link_record_dynamic_symbol (info, h))
flags = bed->dynamic_sec_flags;
pltflags = flags;
- pltflags |= SEC_CODE;
if (bed->plt_not_loaded)
+ /* We do not clear SEC_ALLOC here because we still want the OS to
+ allocate space for the section; it's just that there's nothing
+ to read in from the object file. */
pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
+ else
+ pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD;
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
bfd *dynobj = elf_hash_table (info)->dynobj;
if (dynobj != NULL
- && (ip = bfd_get_section_by_name (dynobj, p->name))
- != NULL
+ && (ip = bfd_get_section_by_name (dynobj, p->name)) != NULL
&& (ip->flags & SEC_LINKER_CREATED)
&& ip->output_section == p)
return TRUE;
if (! is_elf_hash_table (hash_table))
return FALSE;
+ if (info->warn_shared_textrel && info->shared && tag == DT_TEXTREL)
+ _bfd_error_handler
+ (_("warning: creating a DT_TEXTREL in a shared object."));
+
bed = get_elf_backend_data (hash_table->dynobj);
s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
BFD_ASSERT (s != NULL);
_bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p,
&def);
p += sizeof (Elf_External_Verdef);
+ if (def.vd_aux != sizeof (Elf_External_Verdef))
+ continue;
for (i = 0; i < def.vd_cnt; ++i)
{
_bfd_elf_swap_verdaux_in (output_bfd,
(*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 (isym->st_other != 0 && !dynamic)
{
unsigned char hvis, symvis, other, nvis;
if (verdefs != NULL && verdefs->vernum == 0)
verdefs = verdefs->next;
- if (verdefs == NULL)
+ if (verdefs == NULL && !info->create_default_symver)
_bfd_strip_section_from_output (info, s);
else
{
bfd_byte *p;
Elf_Internal_Verdef def;
Elf_Internal_Verdaux defaux;
+ struct bfd_link_hash_entry *bh;
+ struct elf_link_hash_entry *h;
+ const char *name;
cdefs = 0;
size = 0;
size += sizeof (Elf_External_Verdaux);
++cdefs;
+ /* Make space for the default version. */
+ if (info->create_default_symver)
+ {
+ size += sizeof (Elf_External_Verdef);
+ ++cdefs;
+ }
+
for (t = verdefs; t != NULL; t = t->next)
{
struct bfd_elf_version_deps *n;
def.vd_flags = VER_FLG_BASE;
def.vd_ndx = 1;
def.vd_cnt = 1;
- def.vd_aux = sizeof (Elf_External_Verdef);
- def.vd_next = (sizeof (Elf_External_Verdef)
- + sizeof (Elf_External_Verdaux));
+ if (info->create_default_symver)
+ {
+ def.vd_aux = 2 * sizeof (Elf_External_Verdef);
+ def.vd_next = sizeof (Elf_External_Verdef);
+ }
+ else
+ {
+ def.vd_aux = sizeof (Elf_External_Verdef);
+ def.vd_next = (sizeof (Elf_External_Verdef)
+ + sizeof (Elf_External_Verdaux));
+ }
if (soname_indx != (bfd_size_type) -1)
{
soname_indx);
def.vd_hash = bfd_elf_hash (soname);
defaux.vda_name = soname_indx;
+ name = soname;
}
else
{
- const char *name;
bfd_size_type indx;
name = basename (output_bfd->filename);
_bfd_elf_swap_verdef_out (output_bfd, &def,
(Elf_External_Verdef *) p);
p += sizeof (Elf_External_Verdef);
+ if (info->create_default_symver)
+ {
+ /* Add a symbol representing this version. */
+ bh = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, dynobj, name, BSF_GLOBAL, bfd_abs_section_ptr,
+ 0, NULL, FALSE,
+ get_elf_backend_data (dynobj)->collect, &bh)))
+ return FALSE;
+ h = (struct elf_link_hash_entry *) bh;
+ h->non_elf = 0;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+ h->verinfo.vertree = NULL;
+
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+
+ /* Create a duplicate of the base version with the same
+ aux block, but different flags. */
+ def.vd_flags = 0;
+ def.vd_ndx = 2;
+ def.vd_aux = sizeof (Elf_External_Verdef);
+ if (verdefs)
+ def.vd_next = (sizeof (Elf_External_Verdef)
+ + sizeof (Elf_External_Verdaux));
+ else
+ def.vd_next = 0;
+ _bfd_elf_swap_verdef_out (output_bfd, &def,
+ (Elf_External_Verdef *) p);
+ p += sizeof (Elf_External_Verdef);
+ }
_bfd_elf_swap_verdaux_out (output_bfd, &defaux,
(Elf_External_Verdaux *) p);
p += sizeof (Elf_External_Verdaux);
{
unsigned int cdeps;
struct bfd_elf_version_deps *n;
- struct elf_link_hash_entry *h;
- struct bfd_link_hash_entry *bh;
cdeps = 0;
for (n = t->deps; n != NULL; n = n->next)
&& t->locals.list == NULL
&& ! t->used)
def.vd_flags |= VER_FLG_WEAK;
- def.vd_ndx = t->vernum + 1;
+ def.vd_ndx = t->vernum + (info->create_default_symver ? 2 : 1);
def.vd_cnt = cdeps + 1;
def.vd_hash = bfd_elf_hash (t->name);
def.vd_aux = sizeof (Elf_External_Verdef);
s = bfd_get_section_by_name (dynobj, ".gnu.version");
BFD_ASSERT (s != NULL);
if (dynsymcount == 0
- || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
+ || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL
+ && !info->create_default_symver))
{
_bfd_strip_section_from_output (info, s);
/* The DYNSYMCOUNT might have changed if we were going to
bfd_byte *erel, *erelend;
asection *o = lo->u.indirect.section;
+ if (o->contents == NULL && o->size != 0)
+ {
+ /* This is a reloc section that is being handled as a normal
+ section. See bfd_section_from_shdr. We can't combine
+ relocs in this case. */
+ free (sort);
+ return 0;
+ }
erel = o->contents;
erelend = o->contents + o->size;
p = sort + o->output_offset / ext_size * sort_elt;
iversym.vs_vers = 1;
else
iversym.vs_vers = h->verinfo.vertree->vernum + 1;
+ if (finfo->info->create_default_symver)
+ iversym.vs_vers++;
}
if (h->hidden)
return FALSE;
}
-/* Return TRUE if we should complain about a reloc in SEC against a
- symbol defined in a discarded section. */
-
-static bfd_boolean
-elf_section_complain_discarded (asection *sec)
+enum action_discarded
+ {
+ COMPLAIN = 1,
+ PRETEND = 2
+ };
+
+/* Return a mask saying how ld should treat relocations in SEC against
+ symbols defined in discarded sections. If this function returns
+ COMPLAIN set, ld will issue a warning message. If this function
+ returns PRETEND set, and the discarded section was link-once and the
+ same size as the kept link-once section, ld will pretend that the
+ symbol was actually defined in the kept section. Otherwise ld will
+ zero the reloc (at least that is the intent, but some cooperation by
+ the target dependent code is needed, particularly for REL targets). */
+
+static unsigned int
+elf_action_discarded (asection *sec)
{
- if (strncmp (".stab", sec->name, 5) == 0
- && (!sec->name[5] ||
- (sec->name[5] == '.' && ISDIGIT (sec->name[6]))))
- return FALSE;
+ if (sec->flags & SEC_DEBUGGING)
+ return PRETEND;
if (strcmp (".eh_frame", sec->name) == 0)
- return FALSE;
+ return 0;
if (strcmp (".gcc_except_table", sec->name) == 0)
- return FALSE;
+ return 0;
if (strcmp (".PARISC.unwind", sec->name) == 0)
- return FALSE;
+ return 0;
if (strcmp (".fixup", sec->name) == 0)
- return FALSE;
+ return 0;
- return TRUE;
+ return COMPLAIN | PRETEND;
}
/* Find a match between a section and a member of a section group. */
if (!elf_section_ignore_discarded_relocs (o))
{
Elf_Internal_Rela *rel, *relend;
- bfd_boolean complain = elf_section_complain_discarded (o);
+ unsigned int action = elf_action_discarded (o);
rel = internal_relocs;
relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
discarded section. */
if ((sec = *ps) != NULL && elf_discarded_section (sec))
{
- if ((o->flags & SEC_DEBUGGING) != 0)
- {
- BFD_ASSERT (r_symndx != 0);
-
- /* Try to preserve debug information.
- FIXME: This is quite broken. Modifying
- the symbol here means we will be changing
- all uses of the symbol, not just those in
- debug sections. The only thing that makes
- this half reasonable is that debug sections
- tend to come after other sections. Of
- course, that doesn't help with globals.
- ??? All link-once sections of the same name
- ought to define the same set of symbols, so
- it would seem that globals ought to always
- be defined in the kept section. */
- if (sec->kept_section != NULL)
- {
- asection *member;
+ asection *kept;
- /* Check if it is a linkonce section or
- member of a comdat group. */
- if (elf_sec_group (sec) == NULL
- && sec->size == sec->kept_section->size)
- {
- *ps = sec->kept_section;
- continue;
- }
- else if (elf_sec_group (sec) != NULL
- && (member = match_group_member (sec, sec->kept_section))
- && sec->size == member->size)
- {
- *ps = member;
- continue;
- }
- }
- }
- else if (complain)
+ BFD_ASSERT (r_symndx != 0);
+ if (action & COMPLAIN)
{
(*_bfd_error_handler)
(_("`%s' referenced in section `%A' of %B: "
o, input_bfd, sec, sec->owner, sym_name);
}
+ /* Try to do the best we can to support buggy old
+ versions of gcc. If we've warned, or this is
+ debugging info, pretend that the symbol is
+ really defined in the kept linkonce section.
+ FIXME: This is quite broken. Modifying the
+ symbol here means we will be changing all later
+ uses of the symbol, not just in this section.
+ The only thing that makes this half reasonable
+ is that we warn in non-debug sections, and
+ debug sections tend to come after other
+ sections. */
+ kept = sec->kept_section;
+ if (kept != NULL && (action & PRETEND))
+ {
+ if (elf_sec_group (sec) != NULL)
+ kept = match_group_member (sec, kept);
+ if (kept != NULL
+ && sec->size == kept->size)
+ {
+ *ps = kept;
+ continue;
+ }
+ }
+
/* Remove the symbol reference from the reloc, but
don't kill the reloc completely. This is so that
a zero value will be written into the section,
else
sym_name = link_order->u.reloc.p->u.name;
if (! ((*info->callbacks->reloc_overflow)
- (info, sym_name, howto->name, addend, NULL, NULL, 0)))
+ (info, NULL, sym_name, howto->name, addend, NULL,
+ NULL, (bfd_vma) 0)))
{
free (buf);
return FALSE;
return ret;
}
-struct already_linked_section
-{
- asection *sec;
- asection *linked;
-};
-
-/* Check if the member of a single member comdat group matches a
- linkonce section and vice versa. */
-static bfd_boolean
-try_match_symbols_in_sections
- (struct bfd_section_already_linked_hash_entry *h, void *info)
-{
- struct bfd_section_already_linked *l;
- struct already_linked_section *s
- = (struct already_linked_section *) info;
-
- if (elf_sec_group (s->sec) == NULL)
- {
- /* It is a linkonce section. Try to match it with the member of a
- single member comdat group. */
- for (l = h->entry; l != NULL; l = l->next)
- if ((l->sec->flags & SEC_GROUP))
- {
- asection *first = elf_next_in_group (l->sec);
-
- if (first != NULL
- && elf_next_in_group (first) == first
- && bfd_elf_match_symbols_in_sections (first, s->sec))
- {
- s->linked = first;
- return FALSE;
- }
- }
- }
- else
- {
- /* It is the member of a single member comdat group. Try to match
- it with a linkonce section. */
- for (l = h->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, s->sec))
- {
- s->linked = l->sec;
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static bfd_boolean
-already_linked (asection *sec, asection *group)
-{
- struct already_linked_section result;
-
- result.sec = sec;
- result.linked = NULL;
-
- bfd_section_already_linked_table_traverse
- (try_match_symbols_in_sections, &result);
-
- if (result.linked)
- {
- sec->output_section = bfd_abs_section_ptr;
- sec->kept_section = result.linked;
-
- /* Also discard the group section. */
- if (group)
- group->output_section = bfd_abs_section_ptr;
-
- return TRUE;
- }
-
- return FALSE;
-}
-
void
_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
{
flagword flags;
- const char *name;
+ const char *name, *p;
struct bfd_section_already_linked *l;
struct bfd_section_already_linked_hash_entry *already_linked_list;
asection *group;
name = bfd_get_section_name (abfd, sec);
- already_linked_list = bfd_section_already_linked_table_lookup (name);
+ if (strncmp (name, ".gnu.linkonce.", sizeof (".gnu.linkonce.") - 1) == 0
+ && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
+ p++;
+ else
+ p = name;
+
+ already_linked_list = bfd_section_already_linked_table_lookup (p);
for (l = already_linked_list->entry; l != NULL; l = l->next)
{
a linkonce section with a linkonce section, and ignore comdat
section. */
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)
{
/* The section has already been linked. See if we should
- issue a warning. */
+ issue a warning. */
switch (flags & SEC_LINK_DUPLICATES)
{
default:
section. We only record the discarded comdat group. Otherwise
the undiscarded group will be discarded incorrectly later since
itself has been recorded. */
- if (! already_linked (elf_next_in_group (sec), group))
+ 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;
}
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. */
- already_linked (sec, group);
-
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ if (l->sec->flags & SEC_GROUP)
+ {
+ asection *first = elf_next_in_group (l->sec);
+
+ if (first != NULL
+ && elf_next_in_group (first) == first
+ && bfd_elf_match_symbols_in_sections (first, sec))
+ {
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = l->sec;
+ break;
+ }
+ }
+
/* This is the first section with this name. Record it. */
bfd_section_already_linked_table_insert (already_linked_list, sec);
}