/* ELF linking support for BFD.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010
+ 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
struct elf_info_failed
{
struct bfd_link_info *info;
- struct bfd_elf_version_tree *verdefs;
bfd_boolean failed;
};
return NULL;
h = (struct elf_link_hash_entry *) bh;
h->def_regular = 1;
+ h->non_elf = 0;
h->type = STT_OBJECT;
h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
flags = bed->dynamic_sec_flags;
- s = bfd_make_section_with_flags (abfd,
- (bed->rela_plts_and_copies_p
- ? ".rela.got" : ".rel.got"),
- (bed->dynamic_sec_flags
- | SEC_READONLY));
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.got" : ".rel.got"),
+ (bed->dynamic_sec_flags
+ | SEC_READONLY));
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
htab->srelgot = s;
- s = bfd_make_section_with_flags (abfd, ".got", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (s == NULL
|| !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
if (bed->want_got_plt)
{
- s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
if (s == NULL
|| !bfd_set_section_alignment (abfd, s,
bed->s->log_file_align))
shared library does not. */
if (info->executable)
{
- s = bfd_make_section_with_flags (abfd, ".interp",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".interp",
+ flags | SEC_READONLY);
if (s == NULL)
return FALSE;
}
/* Create sections to hold version informations. These are removed
if they are not needed. */
- s = bfd_make_section_with_flags (abfd, ".gnu.version_d",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".gnu.version",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, 1))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".gnu.version_r",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_r",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".dynsym",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynsym",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".dynstr",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynstr",
+ flags | SEC_READONLY);
if (s == NULL)
return FALSE;
- s = bfd_make_section_with_flags (abfd, ".dynamic", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", flags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
if (info->emit_hash)
{
- s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".hash",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
if (info->emit_gnu_hash)
{
- s = bfd_make_section_with_flags (abfd, ".gnu.hash",
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash",
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
/* Let the backend create the rest of the sections. This lets the
backend set the right flags. The backend will normally create
the .got and .plt sections. */
- if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
+ if (bed->elf_backend_create_dynamic_sections == NULL
+ || ! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
return FALSE;
elf_hash_table (info)->dynamic_sections_created = TRUE;
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
- s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
return FALSE;
return FALSE;
}
- s = bfd_make_section_with_flags (abfd,
- (bed->rela_plts_and_copies_p
- ? ".rela.plt" : ".rel.plt"),
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.plt" : ".rel.plt"),
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
image and use a R_*_COPY reloc to tell the dynamic linker to
initialize them at run time. The linker script puts the .dynbss
section into the .bss section of the final image. */
- s = bfd_make_section_with_flags (abfd, ".dynbss",
- (SEC_ALLOC
- | SEC_LINKER_CREATED));
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynbss",
+ (SEC_ALLOC | SEC_LINKER_CREATED));
if (s == NULL)
return FALSE;
copy relocs. */
if (! info->shared)
{
- s = bfd_make_section_with_flags (abfd,
- (bed->rela_plts_and_copies_p
- ? ".rela.bss" : ".rel.bss"),
- flags | SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->rela_plts_and_copies_p
+ ? ".rela.bss" : ".rel.bss"),
+ flags | SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
return FALSE;
{
size_t *count = (size_t *) data;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
if (h->forced_local)
return TRUE;
{
size_t *count = (size_t *) data;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
if (!h->forced_local)
return TRUE;
break;
}
+ /* Differentiate strong and weak symbols. */
+ newweak = bind == STB_WEAK;
+ oldweak = (h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_undefweak);
+
/* 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
_GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
dynamic object, which we do want to handle here. */
if (abfd == oldbfd
+ && (newweak || oldweak)
&& ((abfd->flags & DYNAMIC) == 0
|| !h->def_regular))
return 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". */
- if ((ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)
- && ELF_ST_TYPE (sym->st_info) != h->type
- && oldbfd != NULL)
+ else if (oldbfd != NULL
+ && 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;
{
h->def_dynamic = 0;
h->ref_dynamic = 1;
- h->dynamic_def = 1;
}
/* FIXME: Should we check type and size for protected symbol? */
h->size = 0;
return TRUE;
}
- /* 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 (bind == STB_GNU_UNIQUE)
h->unique_global = 1;
symbols defined in dynamic objects. */
if (! ((*info->callbacks->multiple_common)
- (info, h->root.root.string, oldbfd, bfd_link_hash_common,
- h->size, abfd, bfd_link_hash_common, sym->st_size)))
+ (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
return FALSE;
if (sym->st_size > h->size)
/* Skip weak definitions of symbols that are already defined. */
if (newdef && olddef && newweak)
{
- *skip = TRUE;
+ /* Don't skip new non-IR weak syms. */
+ if (!(oldbfd != NULL
+ && (oldbfd->flags & BFD_PLUGIN) != 0
+ && (abfd->flags & BFD_PLUGIN) == 0))
+ *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
common symbol, but we don't know what to use for the section
or the alignment. */
if (! ((*info->callbacks->multiple_common)
- (info, h->root.root.string, oldbfd, bfd_link_hash_common,
- h->size, abfd, bfd_link_hash_common, sym->st_size)))
+ (info, &h->root, abfd, bfd_link_hash_common, sym->st_size)))
return FALSE;
/* If the presumed common symbol in the dynamic object is
{
if (! dynamic)
{
- if (info->shared
+ if (! info->executable
|| hi->ref_dynamic)
*dynsym = TRUE;
}
{
if (! dynamic)
{
- if (info->shared
+ if (! info->executable
|| hi->ref_dynamic)
*dynsym = TRUE;
}
{
struct elf_info_failed *eif = (struct elf_info_failed *) data;
- /* Ignore this if we won't export it. */
- if (!eif->info->export_dynamic && !h->dynamic)
- return TRUE;
-
/* Ignore indirect symbols. These are added by the versioning code. */
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ /* Ignore this if we won't export it. */
+ if (!eif->info->export_dynamic && !h->dynamic)
+ return TRUE;
if (h->dynindx == -1
- && (h->def_regular
- || h->ref_regular))
+ && (h->def_regular || h->ref_regular)
+ && ! bfd_hide_sym_by_version (eif->info->version_info,
+ h->root.root.string))
{
- bfd_boolean hide;
-
- if (eif->verdefs == NULL
- || (bfd_find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
- && !hide))
+ if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
{
- if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
- {
- eif->failed = TRUE;
- return FALSE;
- }
+ eif->failed = TRUE;
+ return FALSE;
}
}
Elf_Internal_Vernaux *a;
bfd_size_type amt;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* We only care about symbols defined in shared objects with version
information. */
if (!h->def_dynamic
sinfo = (struct elf_info_failed *) data;
info = sinfo->info;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* Fix the symbol flags. */
eif.failed = FALSE;
eif.info = info;
}
/* Look for the version. If we find it, it is no longer weak. */
- for (t = sinfo->verdefs; t != NULL; t = t->next)
+ for (t = sinfo->info->version_info; t != NULL; t = t->next)
{
if (strcmp (t->name, p) == 0)
{
version_index = 1;
/* Don't count anonymous version tag. */
- if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0)
+ if (sinfo->info->version_info != NULL
+ && sinfo->info->version_info->vernum == 0)
version_index = 0;
- for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
+ for (pp = &sinfo->info->version_info;
+ *pp != NULL;
+ pp = &(*pp)->next)
++version_index;
t->vernum = version_index;
/* If we don't have a version for this symbol, see if we can find
something. */
- if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
+ if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL)
{
bfd_boolean hide;
- h->verinfo.vertree = bfd_find_version_for_sym (sinfo->verdefs,
- h->root.root.string, &hide);
+ h->verinfo.vertree
+ = bfd_find_version_for_sym (sinfo->info->version_info,
+ h->root.root.string, &hide);
if (h->verinfo.vertree != NULL && hide)
(*bed->elf_backend_hide_symbol) (info, h, TRUE);
}
return FALSE;
}
}
- else if (r_symndx != 0)
+ else if (r_symndx != STN_UNDEF)
{
(*_bfd_error_handler)
(_("%B: non-zero symbol index (0x%lx) for offset 0x%lx in section `%A'"
according to the KEEP_MEMORY argument. If O has two relocation
sections (both REL and RELA relocations), then the REL_HDR
relocations will appear first in INTERNAL_RELOCS, followed by the
- REL_HDR2 relocations. */
+ RELA_HDR relocations. */
Elf_Internal_Rela *
_bfd_elf_link_read_relocs (bfd *abfd,
Elf_Internal_Rela *internal_relocs,
bfd_boolean keep_memory)
{
- Elf_Internal_Shdr *rel_hdr;
void *alloc1 = NULL;
Elf_Internal_Rela *alloc2 = NULL;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ struct bfd_elf_section_data *esdo = elf_section_data (o);
+ Elf_Internal_Rela *internal_rela_relocs;
- if (elf_section_data (o)->relocs != NULL)
- return elf_section_data (o)->relocs;
+ if (esdo->relocs != NULL)
+ return esdo->relocs;
if (o->reloc_count == 0)
return NULL;
- rel_hdr = &elf_section_data (o)->rel_hdr;
-
if (internal_relocs == NULL)
{
bfd_size_type size;
if (external_relocs == NULL)
{
- bfd_size_type size = rel_hdr->sh_size;
+ bfd_size_type size = 0;
+
+ if (esdo->rel.hdr)
+ size += esdo->rel.hdr->sh_size;
+ if (esdo->rela.hdr)
+ size += esdo->rela.hdr->sh_size;
- if (elf_section_data (o)->rel_hdr2)
- size += elf_section_data (o)->rel_hdr2->sh_size;
alloc1 = bfd_malloc (size);
if (alloc1 == NULL)
goto error_return;
external_relocs = alloc1;
}
- if (!elf_link_read_relocs_from_section (abfd, o, rel_hdr,
- external_relocs,
- internal_relocs))
- goto error_return;
- if (elf_section_data (o)->rel_hdr2
- && (!elf_link_read_relocs_from_section
- (abfd, o,
- elf_section_data (o)->rel_hdr2,
- ((bfd_byte *) external_relocs) + rel_hdr->sh_size,
- internal_relocs + (NUM_SHDR_ENTRIES (rel_hdr)
- * bed->s->int_rels_per_ext_rel))))
+ internal_rela_relocs = internal_relocs;
+ if (esdo->rel.hdr)
+ {
+ if (!elf_link_read_relocs_from_section (abfd, o, esdo->rel.hdr,
+ external_relocs,
+ internal_relocs))
+ goto error_return;
+ external_relocs = (((bfd_byte *) external_relocs)
+ + esdo->rel.hdr->sh_size);
+ internal_rela_relocs += (NUM_SHDR_ENTRIES (esdo->rel.hdr)
+ * bed->s->int_rels_per_ext_rel);
+ }
+
+ if (esdo->rela.hdr
+ && (!elf_link_read_relocs_from_section (abfd, o, esdo->rela.hdr,
+ external_relocs,
+ internal_rela_relocs)))
goto error_return;
/* Cache the results for next time, if we can. */
if (keep_memory)
- elf_section_data (o)->relocs = internal_relocs;
+ esdo->relocs = internal_relocs;
if (alloc1 != NULL)
free (alloc1);
static bfd_boolean
_bfd_elf_link_size_reloc_section (bfd *abfd,
- Elf_Internal_Shdr *rel_hdr,
- asection *o)
+ struct bfd_elf_section_reloc_data *reldata)
{
- bfd_size_type reloc_count;
- bfd_size_type num_rel_hashes;
-
- /* Figure out how many relocations there will be. */
- if (rel_hdr == &elf_section_data (o)->rel_hdr)
- reloc_count = elf_section_data (o)->rel_count;
- else
- reloc_count = elf_section_data (o)->rel_count2;
-
- num_rel_hashes = o->reloc_count;
- if (num_rel_hashes < reloc_count)
- num_rel_hashes = reloc_count;
+ Elf_Internal_Shdr *rel_hdr = reldata->hdr;
/* That allows us to calculate the size of the section. */
- rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
+ rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->count;
/* The contents field must last into write_object_contents, so we
allocate it with bfd_alloc rather than malloc. Also since we
if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
return FALSE;
- /* We only allocate one set of hash entries, so we only do it the
- first time we are called. */
- if (elf_section_data (o)->rel_hashes == NULL
- && num_rel_hashes)
+ if (reldata->hashes == NULL && reldata->count)
{
struct elf_link_hash_entry **p;
p = (struct elf_link_hash_entry **)
- bfd_zmalloc (num_rel_hashes * sizeof (struct elf_link_hash_entry *));
+ bfd_zmalloc (reldata->count * sizeof (struct elf_link_hash_entry *));
if (p == NULL)
return FALSE;
- elf_section_data (o)->rel_hashes = p;
+ reldata->hashes = p;
}
return TRUE;
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend;
bfd_byte *erel;
- Elf_Internal_Shdr *output_rel_hdr;
+ struct bfd_elf_section_reloc_data *output_reldata;
asection *output_section;
- unsigned int *rel_countp = NULL;
const struct elf_backend_data *bed;
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+ struct bfd_elf_section_data *esdo;
output_section = input_section->output_section;
- output_rel_hdr = NULL;
- if (elf_section_data (output_section)->rel_hdr.sh_entsize
- == input_rel_hdr->sh_entsize)
+ bed = get_elf_backend_data (output_bfd);
+ esdo = elf_section_data (output_section);
+ if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize)
{
- output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
- rel_countp = &elf_section_data (output_section)->rel_count;
+ output_reldata = &esdo->rel;
+ swap_out = bed->s->swap_reloc_out;
}
- else if (elf_section_data (output_section)->rel_hdr2
- && (elf_section_data (output_section)->rel_hdr2->sh_entsize
- == input_rel_hdr->sh_entsize))
+ else if (esdo->rela.hdr
+ && esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize)
{
- output_rel_hdr = elf_section_data (output_section)->rel_hdr2;
- rel_countp = &elf_section_data (output_section)->rel_count2;
+ output_reldata = &esdo->rela;
+ swap_out = bed->s->swap_reloca_out;
}
else
{
return FALSE;
}
- bed = get_elf_backend_data (output_bfd);
- if (input_rel_hdr->sh_entsize == bed->s->sizeof_rel)
- swap_out = bed->s->swap_reloc_out;
- else if (input_rel_hdr->sh_entsize == bed->s->sizeof_rela)
- swap_out = bed->s->swap_reloca_out;
- else
- abort ();
-
- erel = output_rel_hdr->contents;
- erel += *rel_countp * input_rel_hdr->sh_entsize;
+ erel = output_reldata->hdr->contents;
+ erel += output_reldata->count * input_rel_hdr->sh_entsize;
irela = internal_relocs;
irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
* bed->s->int_rels_per_ext_rel);
/* Bump the counter, so that we know where to add the next set of
relocations. */
- *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr);
+ output_reldata->count += NUM_SHDR_ENTRIES (input_rel_hdr);
return TRUE;
}
over to the real definition. */
if (h->u.weakdef != NULL)
{
- struct elf_link_hash_entry *weakdef;
-
- weakdef = h->u.weakdef;
- if (h->root.type == bfd_link_hash_indirect)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- BFD_ASSERT (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak);
- BFD_ASSERT (weakdef->def_dynamic);
-
/* If the real definition is defined by a regular object file,
don't do anything special. See the longer description in
_bfd_elf_adjust_dynamic_symbol, below. */
- if (weakdef->def_regular)
+ if (h->u.weakdef->def_regular)
h->u.weakdef = NULL;
else
{
+ struct elf_link_hash_entry *weakdef = h->u.weakdef;
+
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak);
+ BFD_ASSERT (weakdef->def_dynamic);
BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
|| weakdef->root.type == bfd_link_hash_defweak);
(*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h);
if (! is_elf_hash_table (eif->info->hash))
return FALSE;
- if (h->root.type == bfd_link_hash_warning)
- {
- h->got = elf_hash_table (eif->info)->init_got_offset;
- h->plt = elf_hash_table (eif->info)->init_plt_offset;
-
- /* When warning symbols are created, they **replace** the "real"
- entry in the hash table, thus we never get to see the real
- symbol in a hash traversal. So look at it now. */
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- }
-
/* Ignore indirect symbols. These are added by the versioning code. */
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
if (h->u.weakdef != NULL)
{
- /* If we get to this point, we know there is an implicit
- reference by a regular object file via the weak symbol H.
- FIXME: Is this really true? What if the traversal finds
- H->U.WEAKDEF before it finds H? */
+ /* If we get to this point, there is an implicit reference to
+ H->U.WEAKDEF by a regular object file via the weak symbol H. */
h->u.weakdef->ref_regular = 1;
+ /* Ensure that the backend adjust_dynamic_symbol function sees
+ H->U.WEAKDEF before H by recursively calling ourselves. */
if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif))
return FALSE;
}
{
asection *sec;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& ((sec = h->root.u.def.section)->flags & SEC_MERGE)
bfd_boolean
_bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
struct bfd_link_info *info,
- bfd_boolean ignore_protected)
+ bfd_boolean not_local_protected)
{
bfd_boolean binding_stays_local_p;
const struct elf_backend_data *bed;
/* Proper resolution for function pointer equality may require
that these symbols perhaps be resolved dynamically, even though
we should be resolving them to the current module. */
- if (!ignore_protected || !bed->is_function_type (h->type))
+ if (!not_local_protected || !bed->is_function_type (h->type))
binding_stays_local_p = TRUE;
break;
}
/* If it isn't defined locally, then clearly it's dynamic. */
- if (!h->def_regular)
+ if (!h->def_regular && !ELF_COMMON_DEF_P (h))
return TRUE;
/* Otherwise, the symbol is dynamic if binding rules don't tell
/* Return true if the symbol referred to by H should be considered
to resolve local to the current module, and false otherwise. Differs
from (the inverse of) _bfd_elf_dynamic_symbol_p in the treatment of
- undefined symbols and weak symbols. */
+ undefined symbols. The two functions are virtually identical except
+ for the place where forced_local and dynindx == -1 are tested. If
+ either of those tests are true, _bfd_elf_dynamic_symbol_p will say
+ the symbol is local, while _bfd_elf_symbol_refs_local_p will say
+ the symbol is local only for defined symbols.
+ It might seem that _bfd_elf_dynamic_symbol_p could be rewritten as
+ !_bfd_elf_symbol_refs_local_p, except that targets differ in their
+ treatment of undefined weak symbols. For those that do not make
+ undefined weak symbols dynamic, both functions may return false. */
bfd_boolean
_bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
return TRUE;
/* Function pointer equality tests may require that STV_PROTECTED
- symbols be treated as dynamic symbols, even when we know that the
- dynamic linker will resolve them locally. */
+ symbols be treated as dynamic symbols. If the address of a
+ function not defined in an executable is set to that function's
+ plt entry in the executable, then the address of the function in
+ a shared library must also be the plt entry in the executable. */
return local_protected;
}
{
struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
if (h->dynindx != -1)
h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
return TRUE;
.gnu.warning.SYMBOL are treated as warning symbols for the given
symbol. This differs from .gnu.warning sections, which generate
warnings when they are included in an output file. */
- if (info->executable)
+ /* PR 12761: Also generate this warning when building shared libraries. */
+ if (info->executable || info->shared)
{
asection *s;
/* 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))
+ notice_as_needed, 0, NULL))
goto error_free_vers;
/* Clone the symbol table and sym hashes. Remember some
sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (sec == NULL)
sec = bfd_abs_section_ptr;
- else if (sec->kept_section)
+ else if (elf_discarded_section (sec))
{
/* Symbols from discarded section are undefined. We keep
its visibility. */
goto error_free_vers;
if (isym->st_shndx == SHN_COMMON
- && ELF_ST_TYPE (isym->st_info) == STT_TLS
- && !info->relocatable)
+ && (abfd->flags & BFD_PLUGIN) != 0)
+ {
+ asection *xc = bfd_get_section_by_name (abfd, "COMMON");
+
+ if (xc == NULL)
+ {
+ flagword sflags = (SEC_ALLOC | SEC_IS_COMMON | SEC_KEEP
+ | SEC_EXCLUDE);
+ xc = bfd_make_section_with_flags (abfd, "COMMON", sflags);
+ if (xc == NULL)
+ goto error_free_vers;
+ }
+ sec = xc;
+ }
+ else if (isym->st_shndx == SHN_COMMON
+ && ELF_ST_TYPE (isym->st_info) == STT_TLS
+ && !info->relocatable)
{
asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
if (tcomm == NULL)
{
- tcomm = bfd_make_section_with_flags (abfd, ".tcommon",
- (SEC_ALLOC
- | SEC_IS_COMMON
- | SEC_LINKER_CREATED
- | SEC_THREAD_LOCAL));
+ flagword sflags = (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_IS_COMMON
+ | SEC_LINKER_CREATED);
+ tcomm = bfd_make_section_with_flags (abfd, ".tcommon", sflags);
if (tcomm == NULL)
goto error_free_vers;
}
h = (struct elf_link_hash_entry *) h->root.u.i.link;
*sym_hash = h;
- h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
+ if (is_elf_hash_table (htab))
+ h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
new_weakdef = FALSE;
if (dynamic
We need to get the alignment from the section. */
align = new_sec->alignment_power;
}
- if (align > old_alignment
- /* Permit an alignment power of zero if an alignment of one
- is specified and no other alignments have been specified. */
- || (isym->st_value == 1 && old_alignment == 0))
+ if (align > old_alignment)
h->root.u.c.p->alignment_power = align;
else
h->root.u.c.p->alignment_power = old_alignment;
{
h->def_dynamic = 0;
h->ref_dynamic = 1;
- h->dynamic_def = 1;
}
}
if (! info->executable
if (! definition)
h->ref_dynamic = 1;
else
- h->def_dynamic = 1;
+ {
+ h->def_dynamic = 1;
+ h->dynamic_def = 1;
+ }
if (h->def_regular
|| h->ref_regular
|| (h->u.weakdef != NULL
dynsym = TRUE;
}
+ /* We don't want to make debug symbol dynamic. */
if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
- {
- /* We don't want to make debug symbol dynamic. */
- dynsym = FALSE;
- }
+ dynsym = FALSE;
+
+ /* Nor should we make plugin symbols dynamic. */
+ if ((abfd->flags & BFD_PLUGIN) != 0)
+ dynsym = FALSE;
+
+ if (definition)
+ h->target_internal = isym->st_target_internal;
/* Check to see if we need to add an indirect symbol for
the default name. */
{
struct bfd_hash_entry *p;
struct elf_link_hash_entry *h;
+ bfd_size_type size;
+ unsigned int alignment_power;
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
if (h->dynindx >= old_dynsymcount)
_bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
+ /* Preserve the maximum alignment and size for common
+ symbols even if this dynamic lib isn't on DT_NEEDED
+ since it can still be loaded at the run-time by another
+ dynamic lib. */
+ if (h->root.type == bfd_link_hash_common)
+ {
+ size = h->root.u.c.size;
+ alignment_power = h->root.u.c.p->alignment_power;
+ }
+ else
+ {
+ size = 0;
+ alignment_power = 0;
+ }
memcpy (p, old_ent, htab->root.table.entsize);
old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) p;
memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
old_ent = (char *) old_ent + htab->root.table.entsize;
}
+ else if (h->root.type == bfd_link_hash_common)
+ {
+ if (size > h->root.u.c.size)
+ h->root.u.c.size = size;
+ if (alignment_power > h->root.u.c.p->alignment_power)
+ h->root.u.c.p->alignment_power = alignment_power;
+ }
}
}
/* 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))
+ notice_not_needed, 0, NULL))
goto error_free_vers;
free (old_tab);
if (old_tab != NULL)
{
if (!(*info->callbacks->notice) (info, NULL, abfd, NULL,
- notice_needed))
+ notice_needed, 0, NULL))
goto error_free_vers;
free (old_tab);
old_tab = NULL;
if (! dynamic
&& is_elf_hash_table (htab)
&& bed->check_relocs != NULL
+ && elf_object_id (abfd) == elf_hash_table_id (htab)
&& (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
{
asection *o;
char *p, *copy;
size_t len, first;
- h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+ h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, TRUE);
if (h != NULL)
return h;
memcpy (copy, name, first);
memcpy (copy + first, name + first + 1, len - first);
- h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, FALSE);
+ h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, TRUE);
if (h == NULL)
{
/* We also need to check references to the symbol without the
version. */
copy[first - 1] = '\0';
h = elf_link_hash_lookup (elf_hash_table (info), copy,
- FALSE, FALSE, FALSE);
+ FALSE, FALSE, TRUE);
}
bfd_release (abfd, copy);
undefs_tail = info->hash->undefs_tail;
- if (! (*info->callbacks->add_archive_element) (info, element,
- symdef->name))
+ if (!(*info->callbacks
+ ->add_archive_element) (info, element, symdef->name, &element))
goto error_return;
- if (! bfd_link_add_symbols (element, info))
+ if (!bfd_link_add_symbols (element, info))
goto error_return;
/* If there are any new undefined symbols, we need to make
unsigned long ha;
char *alc = NULL;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* Ignore indirect symbols. These are added by the versioning code. */
if (h->dynindx == -1)
return TRUE;
unsigned long ha;
char *alc = NULL;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* Ignore indirect symbols. These are added by the versioning code. */
if (h->dynindx == -1)
return TRUE;
unsigned long int bucket;
unsigned long int val;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* Ignore indirect symbols. */
if (h->dynindx == -1)
return TRUE;
Therefore the result is always a good payoff between few collisions
(= short chain lengths) and table size. */
static size_t
-compute_bucket_count (struct bfd_link_info *info,
+compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
unsigned long int *hashcodes ATTRIBUTE_UNUSED,
unsigned long int nsyms,
int gnu_hash)
const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
unsigned long int *counts;
bfd_size_type amt;
+ unsigned int no_improvement_count = 0;
/* Possible optimization parameters: if we have NSYMS symbols we say
that the hashing table must at least have NSYMS/4 and at most
{
best_chlen = max;
best_size = i;
+ no_improvement_count = 0;
}
+ /* PR 11843: Avoid futile long searches for the best bucket size
+ when there are a large number of symbols. */
+ else if (++no_improvement_count == 100)
+ break;
}
free (counts);
return best_size;
}
+/* Size any SHT_GROUP section for ld -r. */
+
+bfd_boolean
+_bfd_elf_size_group_sections (struct bfd_link_info *info)
+{
+ bfd *ibfd;
+
+ 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;
+ 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
const char *depaudit,
const char * const *auxiliary_filters,
struct bfd_link_info *info,
- asection **sinterpptr,
- struct bfd_elf_version_tree *verdefs)
+ asection **sinterpptr)
{
bfd_size_type soname_indx;
bfd *dynobj;
{
asection *s;
- if (inputobj->flags & (DYNAMIC | EXEC_P | BFD_LINKER_CREATED))
+ if (inputobj->flags
+ & (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED))
continue;
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
if (s)
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
}
eif.info = info;
- eif.verdefs = verdefs;
eif.failed = FALSE;
/* If we are supposed to export all symbols into the dynamic symbol
}
/* Make all global versions with definition. */
- for (t = verdefs; t != NULL; t = t->next)
+ for (t = info->version_info; t != NULL; t = t->next)
for (d = t->globals.list; d != NULL; d = d->next)
if (!d->symver && d->literal)
{
const char *verstr, *name;
size_t namelen, verlen, newlen;
- char *newname, *p;
+ char *newname, *p, leading_char;
struct elf_link_hash_entry *newh;
+ leading_char = bfd_get_symbol_leading_char (output_bfd);
name = d->pattern;
- namelen = strlen (name);
+ namelen = strlen (name) + (leading_char != '\0');
verstr = t->name;
verlen = strlen (verstr);
newlen = namelen + verlen + 3;
newname = (char *) bfd_malloc (newlen);
if (newname == NULL)
return FALSE;
- memcpy (newname, name, namelen);
+ newname[0] = leading_char;
+ memcpy (newname + (leading_char != '\0'), name, namelen);
/* Check the hidden versioned definition. */
p = newname + namelen;
/* Attach all the symbols to their version information. */
asvinfo.info = info;
- asvinfo.verdefs = verdefs;
asvinfo.failed = FALSE;
elf_link_hash_traverse (elf_hash_table (info),
{
/* Check if all global versions have a definition. */
all_defined = TRUE;
- for (t = verdefs; t != NULL; t = t->next)
+ for (t = info->version_info; t != NULL; t = t->next)
for (d = t->globals.list; d != NULL; d = d->next)
if (d->literal && !d->symver && !d->script)
{
if (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. */
/* We may have created additional version definitions if we are
just linking a regular application. */
- verdefs = asvinfo.verdefs;
+ verdefs = info->version_info;
/* Skip anonymous version tag. */
if (verdefs != NULL && verdefs->vernum == 0)
{
struct bfd_elf_version_deps *n;
+ /* Don't emit base version twice. */
+ if (t->vernum == 0)
+ continue;
+
size += sizeof (Elf_External_Verdef);
size += sizeof (Elf_External_Verdaux);
++cdefs;
unsigned int cdeps;
struct bfd_elf_version_deps *n;
+ /* Don't emit the base version twice. */
+ if (t->vernum == 0)
+ continue;
+
cdeps = 0;
for (n = t->deps; n != NULL; n = n->next)
++cdeps;
def.vd_hash = bfd_elf_hash (t->name);
def.vd_aux = sizeof (Elf_External_Verdef);
def.vd_next = 0;
- if (t->next != NULL)
+
+ /* If a basever node is next, it *must* be the last node in
+ the chain, otherwise Verdef construction breaks. */
+ if (t->next != NULL && t->next->vernum == 0)
+ BFD_ASSERT (t->next->next == NULL);
+
+ if (t->next != NULL && t->next->vernum != 0)
def.vd_next = (sizeof (Elf_External_Verdef)
+ (cdeps + 1) * sizeof (Elf_External_Verdaux));
unsigned int crefs;
bfd_byte *p;
- /* Build the version definition section. */
+ /* Build the version dependency section. */
size = 0;
crefs = 0;
for (t = elf_tdata (output_bfd)->verref;
}
else
{
- unsigned long int maskwords, maskbitslog2;
+ unsigned long int maskwords, maskbitslog2, x;
BFD_ASSERT (cinfo.min_dynindx != -1);
- maskbitslog2 = bfd_log2 (cinfo.nsyms) + 1;
+ x = cinfo.nsyms;
+ maskbitslog2 = 1;
+ while ((x >>= 1) != 0)
+ ++maskbitslog2;
if (maskbitslog2 < 3)
maskbitslog2 = 5;
else if ((1 << (maskbitslog2 - 2)) & cinfo.nsyms)
struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
struct bfd_hash_table *,
const char *),
- unsigned int entsize)
+ unsigned int entsize,
+ enum elf_target_id target_id)
{
bfd_boolean ret;
int can_refcount = get_elf_backend_data (abfd)->can_refcount;
table->dynsymcount = 1;
ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
+
table->root.type = bfd_link_elf_hash_table;
+ table->hash_table_id = target_id;
return ret;
}
return NULL;
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
- sizeof (struct elf_link_hash_entry)))
+ sizeof (struct elf_link_hash_entry),
+ GENERIC_ELF_DATA))
{
free (ret);
return NULL;
"chunksz %ld, start %ld, len %ld, oplen %ld\n"
" dest: %8.8lx, mask: %8.8lx, reloc: %8.8lx\n",
lsb0_p, signed_p, trunc_p, wordsz, chunksz, start, len,
- oplen, x, mask, relocation);
+ oplen, (unsigned long) x, (unsigned long) mask,
+ (unsigned long) relocation);
#endif
r = bfd_reloc_ok;
" shifted mask: %8.8lx\n"
" shifted/masked reloc: %8.8lx\n"
" result: %8.8lx\n",
- relocation, (mask << shift),
- ((relocation & mask) << shift), x);
+ (unsigned long) relocation, (unsigned long) (mask << shift),
+ (unsigned long) ((relocation & mask) << shift), (unsigned long) x);
#endif
/* FIXME: octets_per_byte. */
put_value (wordsz, chunksz, input_bfd, x, contents + rel->r_offset);
/* When performing a relocatable link, the input relocations are
preserved. But, if they reference global symbols, the indices
- referenced must be updated. Update all the relocations in
- REL_HDR (there are COUNT of them), using the data in REL_HASH. */
+ referenced must be updated. Update all the relocations found in
+ RELDATA. */
static void
elf_link_adjust_relocs (bfd *abfd,
- Elf_Internal_Shdr *rel_hdr,
- unsigned int count,
- struct elf_link_hash_entry **rel_hash)
+ struct bfd_elf_section_reloc_data *reldata)
{
unsigned int i;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
bfd_vma r_type_mask;
int r_sym_shift;
+ unsigned int count = reldata->count;
+ struct elf_link_hash_entry **rel_hash = reldata->hashes;
- if (rel_hdr->sh_entsize == bed->s->sizeof_rel)
+ if (reldata->hdr->sh_entsize == bed->s->sizeof_rel)
{
swap_in = bed->s->swap_reloc_in;
swap_out = bed->s->swap_reloc_out;
}
- else if (rel_hdr->sh_entsize == bed->s->sizeof_rela)
+ else if (reldata->hdr->sh_entsize == bed->s->sizeof_rela)
{
swap_in = bed->s->swap_reloca_in;
swap_out = bed->s->swap_reloca_out;
r_sym_shift = 32;
}
- erela = rel_hdr->contents;
- for (i = 0; i < count; i++, rel_hash++, erela += rel_hdr->sh_entsize)
+ erela = reldata->hdr->contents;
+ for (i = 0; i < count; i++, rel_hash++, erela += reldata->hdr->sh_entsize)
{
Elf_Internal_Rela irela[MAX_INT_RELS_PER_EXT_REL];
unsigned int j;
global symbols. */
static bfd_boolean
-elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
+elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
{
+ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh;
struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
struct elf_final_link_info *finfo = eoinfo->finfo;
bfd_boolean strip;
ignore_undef = bed->elf_backend_ignore_undef_symbol (h);
/* If we are reporting errors for this situation then do so now. */
- if (ignore_undef == FALSE
+ if (!ignore_undef
&& h->ref_dynamic
&& (!h->ref_regular || finfo->info->gc_sections)
&& ! elf_link_check_versioned_symbol (finfo->info, bed, h)
h->ref_regular ? NULL : h->root.u.undef.abfd,
NULL, 0, finfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR)))
{
+ bfd_set_error (bfd_error_bad_value);
eoinfo->failed = TRUE;
return FALSE;
}
/* We should also warn if a forced local symbol is referenced from
shared libraries. */
- if (! finfo->info->relocatable
- && (! finfo->info->shared)
+ if (!finfo->info->relocatable
+ && finfo->info->executable
&& h->forced_local
&& h->ref_dynamic
+ && h->def_regular
&& !h->dynamic_def
&& !h->dynamic_weak
&& ! elf_link_check_versioned_symbol (finfo->info, bed, h))
{
- (*_bfd_error_handler)
- (_("%B: %s symbol `%s' in %B is referenced by DSO"),
- finfo->output_bfd,
- h->root.u.def.section == bfd_abs_section_ptr
- ? finfo->output_bfd : h->root.u.def.section->owner,
- ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
- ? "internal"
- : ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
- ? "hidden" : "local",
- h->root.root.string);
+ bfd *def_bfd;
+ const char *msg;
+
+ if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
+ msg = _("%B: internal symbol `%s' in %B is referenced by DSO");
+ else if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+ msg = _("%B: hidden symbol `%s' in %B is referenced by DSO");
+ else
+ msg = _("%B: local symbol `%s' in %B is referenced by DSO");
+ def_bfd = finfo->output_bfd;
+ if (h->root.u.def.section != bfd_abs_section_ptr)
+ def_bfd = h->root.u.def.section->owner;
+ (*_bfd_error_handler) (msg, finfo->output_bfd, def_bfd,
+ h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
eoinfo->failed = TRUE;
return FALSE;
}
&& bfd_hash_lookup (finfo->info->keep_hash,
h->root.root.string, FALSE, FALSE) == NULL)
strip = TRUE;
- else if (finfo->info->strip_discarded
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && elf_discarded_section (h->root.u.def.section))
+ else if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && ((finfo->info->strip_discarded
+ && elf_discarded_section (h->root.u.def.section))
+ || (h->root.u.def.section->owner != NULL
+ && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)))
+ strip = TRUE;
+ else if ((h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak)
+ && h->root.u.undef.abfd != NULL
+ && (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0)
strip = TRUE;
else
strip = FALSE;
sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
else
sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
+ sym.st_target_internal = h->target_internal;
switch (h->root.type)
{
(*_bfd_error_handler)
(_("%B: could not find output section %A for input section %A"),
finfo->output_bfd, input_sec->output_section, input_sec);
+ bfd_set_error (bfd_error_nonrepresentable_section);
eoinfo->failed = TRUE;
return FALSE;
}
&& h->root.type == bfd_link_hash_undefined
&& !h->def_regular)
{
- (*_bfd_error_handler)
- (_("%B: %s symbol `%s' isn't defined"),
- finfo->output_bfd,
- ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED
- ? "protected"
- : ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL
- ? "internal" : "hidden",
- h->root.root.string);
+ const char *msg;
+
+ if (ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED)
+ msg = _("%B: protected symbol `%s' isn't defined");
+ else if (ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL)
+ msg = _("%B: internal symbol `%s' isn't defined");
+ else
+ msg = _("%B: hidden symbol `%s' isn't defined");
+ (*_bfd_error_handler) (msg, finfo->output_bfd, h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
eoinfo->failed = TRUE;
return FALSE;
}
/* If this symbol should be put in the .dynsym section, then put it
there now. We already know the symbol index. We also fill in
the entry in the .hash section. */
- if (h->dynindx != -1
+ if (finfo->dynsym_sec != NULL
+ && h->dynindx != -1
&& elf_hash_table (finfo->info)->dynamic_sections_created)
{
bfd_byte *esym;
asection *o;
const struct elf_backend_data *bed;
struct elf_link_hash_entry **sym_hashes;
+ bfd_size_type address_size;
+ bfd_vma r_type_mask;
+ int r_sym_shift;
output_bfd = finfo->output_bfd;
bed = get_elf_backend_data (output_bfd);
*pindex = indx;
}
+ if (bed->s->arch_size == 32)
+ {
+ r_type_mask = 0xff;
+ r_sym_shift = 8;
+ address_size = 4;
+ }
+ else
+ {
+ r_type_mask = 0xffffffff;
+ r_sym_shift = 32;
+ address_size = 8;
+ }
+
/* Relocate the contents of each section. */
sym_hashes = elf_sym_hashes (input_bfd);
for (o = input_bfd->sections; o != NULL; o = o->next)
contents = elf_section_data (o)->this_hdr.contents;
else
{
- bfd_size_type amt = o->rawsize ? o->rawsize : o->size;
-
contents = finfo->contents;
- if (! bfd_get_section_contents (input_bfd, o, contents, 0, amt))
+ if (! bfd_get_full_section_contents (input_bfd, o, &contents))
return FALSE;
}
{
Elf_Internal_Rela *internal_relocs;
Elf_Internal_Rela *rel, *relend;
- bfd_vma r_type_mask;
- int r_sym_shift;
int action_discarded;
int ret;
&& o->reloc_count > 0)
return FALSE;
- if (bed->s->arch_size == 32)
+ /* We need to reverse-copy input .ctors/.dtors sections if
+ they are placed in .init_array/.finit_array for output. */
+ if (o->size > address_size
+ && ((strncmp (o->name, ".ctors", 6) == 0
+ && strcmp (o->output_section->name,
+ ".init_array") == 0)
+ || (strncmp (o->name, ".dtors", 6) == 0
+ && strcmp (o->output_section->name,
+ ".fini_array") == 0))
+ && (o->name[6] == 0 || o->name[6] == '.'))
{
- r_type_mask = 0xff;
- r_sym_shift = 8;
- }
- else
- {
- r_type_mask = 0xffffffff;
- r_sym_shift = 32;
+ if (o->size != o->reloc_count * address_size)
+ {
+ (*_bfd_error_handler)
+ (_("error: %B: size of section %A is not "
+ "multiple of address size"),
+ input_bfd, o);
+ bfd_set_error (bfd_error_on_input);
+ return FALSE;
+ }
+ o->flags |= SEC_ELF_REVERSE_COPY;
}
action_discarded = -1;
#ifdef DEBUG
printf ("Encountered a complex symbol!");
printf (" (input_bfd %s, section %s, reloc %ld\n",
- input_bfd->filename, o->name, rel - internal_relocs);
+ input_bfd->filename, o->name,
+ (long) (rel - internal_relocs));
printf (" symbol: idx %8.8lx, name %s\n",
r_symndx, sym_name);
printf (" reloc : info %8.8lx, addr %8.8lx\n",
discarded section. */
if ((sec = *ps) != NULL && elf_discarded_section (sec))
{
- BFD_ASSERT (r_symndx != 0);
+ BFD_ASSERT (r_symndx != STN_UNDEF);
if (action_discarded & COMPLAIN)
(*finfo->info->callbacks->einfo)
(_("%X`%s' referenced in section `%A' of %B: "
|| finfo->info->emitrelocations)
{
Elf_Internal_Rela *irela;
- Elf_Internal_Rela *irelaend;
+ Elf_Internal_Rela *irelaend, *irelamid;
bfd_vma last_offset;
struct elf_link_hash_entry **rel_hash;
- struct elf_link_hash_entry **rel_hash_list;
- Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2;
+ struct elf_link_hash_entry **rel_hash_list, **rela_hash_list;
+ Elf_Internal_Shdr *input_rel_hdr, *input_rela_hdr;
unsigned int next_erel;
bfd_boolean rela_normal;
+ struct bfd_elf_section_data *esdi, *esdo;
- input_rel_hdr = &elf_section_data (o)->rel_hdr;
- rela_normal = (bed->rela_normal
- && (input_rel_hdr->sh_entsize
- == bed->s->sizeof_rela));
+ esdi = elf_section_data (o);
+ esdo = elf_section_data (o->output_section);
+ rela_normal = FALSE;
/* Adjust the reloc addresses and symbol indices. */
irela = internal_relocs;
irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
- rel_hash = (elf_section_data (o->output_section)->rel_hashes
- + elf_section_data (o->output_section)->rel_count
- + elf_section_data (o->output_section)->rel_count2);
+ rel_hash = esdo->rel.hashes + esdo->rel.count;
+ /* We start processing the REL relocs, if any. When we reach
+ IRELAMID in the loop, we switch to the RELA relocs. */
+ irelamid = irela;
+ if (esdi->rel.hdr != NULL)
+ irelamid += (NUM_SHDR_ENTRIES (esdi->rel.hdr)
+ * bed->s->int_rels_per_ext_rel);
rel_hash_list = rel_hash;
+ rela_hash_list = NULL;
last_offset = o->output_offset;
if (!finfo->info->relocatable)
last_offset += o->output_section->vma;
next_erel = 0;
}
+ if (irela == irelamid)
+ {
+ rel_hash = esdo->rela.hashes + esdo->rela.count;
+ rela_hash_list = rel_hash;
+ rela_normal = bed->rela_normal;
+ }
+
irela->r_offset = _bfd_elf_section_offset (output_bfd,
finfo->info, o,
irela->r_offset);
/* I suppose the backend ought to fill in the
section of any STT_SECTION symbol against a
processor specific section. */
- r_symndx = 0;
+ r_symndx = STN_UNDEF;
if (bfd_is_abs_section (sec))
;
else if (sec == NULL || sec->owner == NULL)
if (!bfd_is_abs_section (osec))
{
r_symndx = osec->target_index;
- if (r_symndx == 0)
+ if (r_symndx == STN_UNDEF)
{
- struct elf_link_hash_table *htab;
- asection *oi;
-
- htab = elf_hash_table (finfo->info);
- oi = htab->text_index_section;
- if ((osec->flags & SEC_READONLY) == 0
- && htab->data_index_section != NULL)
- oi = htab->data_index_section;
-
- if (oi != NULL)
- {
- irela->r_addend += osec->vma - oi->vma;
- r_symndx = oi->target_index;
- }
+ irela->r_addend += osec->vma;
+ osec = _bfd_nearby_section (output_bfd, osec,
+ osec->vma);
+ irela->r_addend -= osec->vma;
+ r_symndx = osec->target_index;
}
-
- BFD_ASSERT (r_symndx != 0);
}
}
}
/* Swap out the relocs. */
- if (input_rel_hdr->sh_size != 0
- && !bed->elf_backend_emit_relocs (output_bfd, o,
- input_rel_hdr,
- internal_relocs,
- rel_hash_list))
- return FALSE;
-
- input_rel_hdr2 = elf_section_data (o)->rel_hdr2;
- if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0)
+ input_rel_hdr = esdi->rel.hdr;
+ if (input_rel_hdr && input_rel_hdr->sh_size != 0)
{
+ if (!bed->elf_backend_emit_relocs (output_bfd, o,
+ input_rel_hdr,
+ internal_relocs,
+ rel_hash_list))
+ return FALSE;
internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
* bed->s->int_rels_per_ext_rel);
rel_hash_list += NUM_SHDR_ENTRIES (input_rel_hdr);
+ }
+
+ input_rela_hdr = esdi->rela.hdr;
+ if (input_rela_hdr && input_rela_hdr->sh_size != 0)
+ {
if (!bed->elf_backend_emit_relocs (output_bfd, o,
- input_rel_hdr2,
+ input_rela_hdr,
internal_relocs,
- rel_hash_list))
+ rela_hash_list))
return FALSE;
}
}
default:
{
/* FIXME: octets_per_byte. */
- if (! (o->flags & SEC_EXCLUDE)
- && ! (o->output_section->flags & SEC_NEVER_LOAD)
- && ! bfd_set_section_contents (output_bfd, o->output_section,
- contents,
- (file_ptr) o->output_offset,
- o->size))
- return FALSE;
+ if (! (o->flags & SEC_EXCLUDE))
+ {
+ file_ptr offset = (file_ptr) o->output_offset;
+ bfd_size_type todo = o->size;
+ if ((o->flags & SEC_ELF_REVERSE_COPY))
+ {
+ /* Reverse-copy input section to output. */
+ do
+ {
+ todo -= address_size;
+ if (! bfd_set_section_contents (output_bfd,
+ o->output_section,
+ contents + todo,
+ offset,
+ address_size))
+ return FALSE;
+ if (todo == 0)
+ break;
+ offset += address_size;
+ }
+ while (1);
+ }
+ else if (! bfd_set_section_contents (output_bfd,
+ o->output_section,
+ contents,
+ offset, todo))
+ return FALSE;
+ }
}
break;
}
long indx;
bfd_vma offset;
bfd_vma addend;
+ struct bfd_elf_section_reloc_data *reldata;
struct elf_link_hash_entry **rel_hash_ptr;
Elf_Internal_Shdr *rel_hdr;
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
Elf_Internal_Rela irel[MAX_INT_RELS_PER_EXT_REL];
bfd_byte *erel;
unsigned int i;
+ struct bfd_elf_section_data *esdo = elf_section_data (output_section);
howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
if (howto == NULL)
addend = link_order->u.reloc.p->addend;
+ if (esdo->rel.hdr)
+ reldata = &esdo->rel;
+ else if (esdo->rela.hdr)
+ reldata = &esdo->rela;
+ else
+ {
+ reldata = NULL;
+ BFD_ASSERT (0);
+ }
+
/* Figure out the symbol index. */
- rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
- + elf_section_data (output_section)->rel_count
- + elf_section_data (output_section)->rel_count2);
+ rel_hash_ptr = reldata->hashes + reldata->count;
if (link_order->type == bfd_section_reloc_link_order)
{
indx = link_order->u.reloc.p->u.section->target_index;
else
irel[0].r_info = ELF64_R_INFO (indx, howto->type);
- rel_hdr = &elf_section_data (output_section)->rel_hdr;
+ rel_hdr = reldata->hdr;
erel = rel_hdr->contents;
if (rel_hdr->sh_type == SHT_REL)
{
- erel += (elf_section_data (output_section)->rel_count
- * bed->s->sizeof_rel);
+ erel += reldata->count * bed->s->sizeof_rel;
(*bed->s->swap_reloc_out) (output_bfd, irel, erel);
}
else
{
irel[0].r_addend = addend;
- erel += (elf_section_data (output_section)->rel_count
- * bed->s->sizeof_rela);
+ erel += reldata->count * bed->s->sizeof_rela;
(*bed->s->swap_reloca_out) (output_bfd, irel, erel);
}
- ++elf_section_data (output_section)->rel_count;
+ ++reldata->count;
return TRUE;
}
{
finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
- BFD_ASSERT (finfo.dynsym_sec != NULL);
+ /* Note that dynsym_sec can be NULL (on VMS). */
finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version");
/* Note that it is OK if symver_sec is NULL. */
}
{
unsigned int reloc_count = 0;
struct bfd_elf_section_data *esdi = NULL;
- unsigned int *rel_count1;
if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
if ((sec->flags & SEC_RELOC) != 0)
{
- size_t ext_size;
+ size_t ext_size = 0;
+
+ if (esdi->rel.hdr != NULL)
+ ext_size = esdi->rel.hdr->sh_size;
+ if (esdi->rela.hdr != NULL)
+ ext_size += esdi->rela.hdr->sh_size;
- ext_size = elf_section_data (sec)->rel_hdr.sh_size;
if (ext_size > max_external_reloc_size)
max_external_reloc_size = ext_size;
if (sec->reloc_count > max_internal_reloc_count)
o->reloc_count += reloc_count;
- /* MIPS may have a mix of REL and RELA relocs on sections.
- To support this curious ABI we keep reloc counts in
- elf_section_data too. We must be careful to add the
- relocations from the input section to the right output
- count. FIXME: Get rid of one count. We have
- o->reloc_count == esdo->rel_count + esdo->rel_count2. */
- rel_count1 = &esdo->rel_count;
- if (esdi != NULL)
+ if (p->type == bfd_indirect_link_order
+ && (info->relocatable || info->emitrelocations))
{
- bfd_boolean same_size;
- bfd_size_type entsize1;
-
- entsize1 = esdi->rel_hdr.sh_entsize;
- /* PR 9827: If the header size has not been set yet then
- assume that it will match the output section's reloc type. */
- if (entsize1 == 0)
- entsize1 = o->use_rela_p ? bed->s->sizeof_rela : bed->s->sizeof_rel;
+ if (esdi->rel.hdr)
+ esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr);
+ if (esdi->rela.hdr)
+ esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr);
+ }
+ else
+ {
+ if (o->use_rela_p)
+ esdo->rela.count += reloc_count;
else
- BFD_ASSERT (entsize1 == bed->s->sizeof_rel
- || entsize1 == bed->s->sizeof_rela);
- same_size = !o->use_rela_p == (entsize1 == bed->s->sizeof_rel);
-
- if (!same_size)
- rel_count1 = &esdo->rel_count2;
-
- if (esdi->rel_hdr2 != NULL)
- {
- bfd_size_type entsize2 = esdi->rel_hdr2->sh_entsize;
- unsigned int alt_count;
- unsigned int *rel_count2;
-
- BFD_ASSERT (entsize2 != entsize1
- && (entsize2 == bed->s->sizeof_rel
- || entsize2 == bed->s->sizeof_rela));
-
- rel_count2 = &esdo->rel_count2;
- if (!same_size)
- rel_count2 = &esdo->rel_count;
-
- /* The following is probably too simplistic if the
- backend counts output relocs unusually. */
- BFD_ASSERT (bed->elf_backend_count_relocs == NULL);
- alt_count = NUM_SHDR_ENTRIES (esdi->rel_hdr2);
- *rel_count2 += alt_count;
- reloc_count -= alt_count;
- }
+ esdo->rel.count += reloc_count;
}
- *rel_count1 += reloc_count;
}
if (o->reloc_count > 0)
/* Set sizes, and assign file positions for reloc sections. */
for (o = abfd->sections; o != NULL; o = o->next)
{
+ struct bfd_elf_section_data *esdo = elf_section_data (o);
if ((o->flags & SEC_RELOC) != 0)
{
- if (!(_bfd_elf_link_size_reloc_section
- (abfd, &elf_section_data (o)->rel_hdr, o)))
+ if (esdo->rel.hdr
+ && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel)))
goto error_return;
- if (elf_section_data (o)->rel_hdr2
- && !(_bfd_elf_link_size_reloc_section
- (abfd, elf_section_data (o)->rel_hdr2, o)))
+ if (esdo->rela.hdr
+ && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela)))
goto error_return;
}
/* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
to count upwards while actually outputting the relocations. */
- elf_section_data (o)->rel_count = 0;
- elf_section_data (o)->rel_count2 = 0;
+ esdo->rel.count = 0;
+ esdo->rela.count = 0;
}
_bfd_elf_assign_file_positions_for_relocs (abfd);
elfsym.st_info = 0;
elfsym.st_other = 0;
elfsym.st_shndx = SHN_UNDEF;
+ elfsym.st_target_internal = 0;
if (elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
NULL) != 1)
goto error_return;
elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
elfsym.st_other = 0;
elfsym.st_value = 0;
+ elfsym.st_target_internal = 0;
for (i = 1; i < elf_numsections (abfd); i++)
{
o = bfd_section_from_elf_index (abfd, i);
end = sec->vma + size;
}
base = elf_hash_table (info)->tls_sec->vma;
- end = align_power (end, elf_hash_table (info)->tls_sec->alignment_power);
+ /* Only align end of TLS section if static TLS doesn't have special
+ alignment requirements. */
+ if (bed->static_tls_alignment == 1)
+ end = align_power (end,
+ elf_hash_table (info)->tls_sec->alignment_power);
elf_hash_table (info)->tls_size = end - base;
}
else
{
if (! _bfd_default_link_order (abfd, info, o, p))
- goto error_return;
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour (sub)
+ == bfd_target_elf_flavour)
+ && (elf_elfheader (sub)->e_ident[EI_CLASS]
+ != bed->s->elfclass))
+ {
+ const char *iclass, *oclass;
+
+ if (bed->s->elfclass == ELFCLASS64)
+ {
+ iclass = "ELFCLASS32";
+ oclass = "ELFCLASS64";
+ }
+ else
+ {
+ iclass = "ELFCLASS64";
+ oclass = "ELFCLASS32";
+ }
+
+ bfd_set_error (bfd_error_wrong_format);
+ (*_bfd_error_handler)
+ (_("%B: file class %s incompatible with %s"),
+ sub, iclass, oclass);
+ }
+
+ goto error_return;
+ }
}
}
}
eoinfo.failed = FALSE;
eoinfo.finfo = &finfo;
eoinfo.localsyms = TRUE;
- elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
- &eoinfo);
+ bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
return FALSE;
symtab_hdr->sh_info = bfd_get_symcount (abfd);
if (dynamic
+ && finfo.dynsym_sec != NULL
&& finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
{
Elf_Internal_Sym sym;
sym.st_name = 0;
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
sym.st_other = 0;
+ sym.st_target_internal = 0;
for (s = abfd->sections; s != NULL; s = s->next)
{
eoinfo.failed = FALSE;
eoinfo.localsyms = FALSE;
eoinfo.finfo = &finfo;
- elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
- &eoinfo);
+ bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
return FALSE;
/* Adjust the relocs to have the correct symbol indices. */
for (o = abfd->sections; o != NULL; o = o->next)
{
+ struct bfd_elf_section_data *esdo = elf_section_data (o);
if ((o->flags & SEC_RELOC) == 0)
continue;
- elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
- elf_section_data (o)->rel_count,
- elf_section_data (o)->rel_hashes);
- if (elf_section_data (o)->rel_hdr2 != NULL)
- elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
- elf_section_data (o)->rel_count2,
- (elf_section_data (o)->rel_hashes
- + elf_section_data (o)->rel_count));
+ if (esdo->rel.hdr != NULL)
+ elf_link_adjust_relocs (abfd, &esdo->rel);
+ if (esdo->rela.hdr != NULL)
+ elf_link_adjust_relocs (abfd, &esdo->rela);
/* Set the reloc_count field to 0 to prevent write_relocs from
trying to swap the relocs out itself. */
(_("%B: could not find output section %s"), abfd, name);
goto error_return;
}
+ if (elf_section_data (o->output_section)->this_hdr.sh_type == SHT_NOTE)
+ {
+ (*_bfd_error_handler)
+ (_("warning: section '%s' is being made into a note"), name);
+ bfd_set_error (bfd_error_nonrepresentable_section);
+ goto error_return;
+ }
dyn.d_un.d_ptr = o->vma;
break;
goto error_return;
/* Check for DT_TEXTREL (late, in case the backend removes it). */
- if (info->warn_shared_textrel && info->shared)
+ if (((info->warn_shared_textrel && info->shared)
+ || info->error_textrel)
+ && (o = bfd_get_section_by_name (dynobj, ".dynamic")) != NULL)
{
bfd_byte *dyncon, *dynconend;
- /* Fix up .dynamic entries. */
- o = bfd_get_section_by_name (dynobj, ".dynamic");
- BFD_ASSERT (o != NULL);
-
dyncon = o->contents;
dynconend = o->contents + o->size;
for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
if (dyn.d_tag == DT_TEXTREL)
{
- info->callbacks->einfo
- (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
+ if (info->error_textrel)
+ info->callbacks->einfo
+ (_("%P%X: read-only segment has dynamic relocations.\n"));
+ else
+ info->callbacks->einfo
+ (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
break;
}
}
continue;
if ((elf_section_data (o->output_section)->this_hdr.sh_type
!= SHT_STRTAB)
- || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
+ && (strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0))
{
/* FIXME: octets_per_byte. */
if (! bfd_set_section_contents (abfd, o->output_section,
free (finfo.symshndxbuf);
for (o = abfd->sections; o != NULL; o = o->next)
{
- if ((o->flags & SEC_RELOC) != 0
- && elf_section_data (o)->rel_hashes != NULL)
- free (elf_section_data (o)->rel_hashes);
+ struct bfd_elf_section_data *esdo = elf_section_data (o);
+ if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL)
+ free (esdo->rel.hashes);
+ if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL)
+ free (esdo->rela.hashes);
}
elf_tdata (abfd)->linker = TRUE;
free (finfo.symshndxbuf);
for (o = abfd->sections; o != NULL; o = o->next)
{
- if ((o->flags & SEC_RELOC) != 0
- && elf_section_data (o)->rel_hashes != NULL)
- free (elf_section_data (o)->rel_hashes);
+ struct bfd_elf_section_data *esdo = elf_section_data (o);
+ if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL)
+ free (esdo->rel.hashes);
+ if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL)
+ free (esdo->rela.hashes);
}
return FALSE;
struct elf_link_hash_entry *h;
r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
- if (r_symndx == 0)
+ if (r_symndx == STN_UNDEF)
return NULL;
if (r_symndx >= cookie->locsymcount
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;
+ h->mark = 1;
+ /* If this symbol is weak and there is a non-weak definition, we
+ keep the non-weak definition because many backends put
+ dynamic reloc info on the non-weak definition for code
+ handling copy relocs. */
+ if (h->u.weakdef != NULL)
+ h->u.weakdef->mark = 1;
return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
}
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
if (rsec && !rsec->gc_mark)
{
- if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+ if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
+ || (rsec->owner->flags & DYNAMIC) != 0)
rsec->gc_mark = 1;
else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
return FALSE;
return ret;
}
+/* Keep debug and special sections. */
+
+bfd_boolean
+_bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
+ elf_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED)
+{
+ bfd *ibfd;
+
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ {
+ asection *isec;
+ bfd_boolean some_kept;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ continue;
+
+ /* Ensure all linker created sections are kept, and see whether
+ any other section is already marked. */
+ some_kept = FALSE;
+ for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+ {
+ if ((isec->flags & SEC_LINKER_CREATED) != 0)
+ isec->gc_mark = 1;
+ else if (isec->gc_mark)
+ some_kept = TRUE;
+ }
+
+ /* If no section in this file will be kept, then we can
+ toss out debug sections. */
+ if (!some_kept)
+ continue;
+
+ /* Keep debug and special sections like .comment when they are
+ not part of a group, or when we have single-member groups. */
+ for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+ if ((elf_next_in_group (isec) == NULL
+ || elf_next_in_group (isec) == isec)
+ && ((isec->flags & SEC_DEBUGGING) != 0
+ || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0))
+ isec->gc_mark = 1;
+ }
+ return TRUE;
+}
+
/* Sweep symbols in swept sections. Called via elf_link_hash_traverse. */
struct elf_gc_sweep_symbol_info
static bfd_boolean
elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
{
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- if ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && !h->root.u.def.section->gc_mark
- && !(h->root.u.def.section->owner->flags & DYNAMIC))
+ if (!h->mark
+ && (((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && !(h->def_regular
+ && h->root.u.def.section->gc_mark))
+ || h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
{
- struct elf_gc_sweep_symbol_info *inf =
- (struct elf_gc_sweep_symbol_info *) data;
+ struct elf_gc_sweep_symbol_info *inf;
+
+ inf = (struct elf_gc_sweep_symbol_info *) data;
(*inf->hide_symbol) (inf->info, h, TRUE);
+ h->def_regular = 0;
+ h->ref_regular = 0;
+ h->ref_regular_nonweak = 0;
}
return TRUE;
asection *first = elf_next_in_group (o);
o->gc_mark = first->gc_mark;
}
- else if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
- || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0
- || elf_section_data (o)->this_hdr.sh_type == SHT_NOTE)
- {
- /* Keep debug, special and SHT_NOTE sections. */
- o->gc_mark = 1;
- }
if (o->gc_mark)
continue;
static bfd_boolean
elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
{
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* Those that are not vtables. */
if (h->vtable == NULL || h->vtable->parent == NULL)
return TRUE;
const struct elf_backend_data *bed;
unsigned int log_file_align;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* Take care of both those symbols that do not describe vtables as
well as those that are not loaded. */
if (h->vtable == NULL || h->vtable->parent == NULL)
{
struct bfd_link_info *info = (struct bfd_link_info *) inf;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->ref_dynamic
- || (!info->executable
+ || ((!info->executable || info->export_dynamic)
&& h->def_regular
&& ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
- && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN)))
+ && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
+ && (strchr (h->root.root.string, ELF_VER_CHR) != NULL
+ || !bfd_hide_sym_by_version (info->version_info,
+ h->root.root.string)))))
h->root.u.def.section->flags |= SEC_KEEP;
return TRUE;
if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
continue;
+ /* Start at sections marked with SEC_KEEP (ref _bfd_elf_gc_keep).
+ Also treat note sections as a root, if the section is not part
+ of a group. */
for (o = sub->sections; o != NULL; o = o->next)
- if ((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP && !o->gc_mark)
- if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
- return FALSE;
+ if (!o->gc_mark
+ && (o->flags & SEC_EXCLUDE) == 0
+ && ((o->flags & SEC_KEEP) != 0
+ || (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
+ && elf_next_in_group (o) == NULL )))
+ {
+ if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+ return FALSE;
+ }
}
/* Allow the backend to mark additional target specific sections. */
- if (bed->gc_mark_extra_sections)
- bed->gc_mark_extra_sections (info, gc_mark_hook);
+ bed->gc_mark_extra_sections (info, gc_mark_hook);
/* ... and mark SEC_EXCLUDE for those that go. */
return elf_gc_sweep (abfd, info);
return TRUE;
}
+/* Map an ELF section header flag to its corresponding string. */
+typedef struct
+{
+ char *flag_name;
+ flagword flag_value;
+} elf_flags_to_name_table;
+
+static elf_flags_to_name_table elf_flags_to_names [] =
+{
+ { "SHF_WRITE", SHF_WRITE },
+ { "SHF_ALLOC", SHF_ALLOC },
+ { "SHF_EXECINSTR", SHF_EXECINSTR },
+ { "SHF_MERGE", SHF_MERGE },
+ { "SHF_STRINGS", SHF_STRINGS },
+ { "SHF_INFO_LINK", SHF_INFO_LINK},
+ { "SHF_LINK_ORDER", SHF_LINK_ORDER},
+ { "SHF_OS_NONCONFORMING", SHF_OS_NONCONFORMING},
+ { "SHF_GROUP", SHF_GROUP },
+ { "SHF_TLS", SHF_TLS },
+ { "SHF_MASKOS", SHF_MASKOS },
+ { "SHF_EXCLUDE", SHF_EXCLUDE },
+};
+
+void
+bfd_elf_lookup_section_flags (struct bfd_link_info *info,
+ struct flag_info *finfo)
+{
+ bfd *output_bfd = info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+ struct flag_info_list *tf = finfo->flag_list;
+ int with_hex = 0;
+ int without_hex = 0;
+
+ for (tf = finfo->flag_list; tf != NULL; tf = tf->next)
+ {
+ int i;
+ if (bed->elf_backend_lookup_section_flags_hook)
+ {
+ flagword hexval =
+ (*bed->elf_backend_lookup_section_flags_hook) ((char *) tf->name);
+
+ if (hexval != 0)
+ {
+ if (tf->with == with_flags)
+ with_hex |= hexval;
+ else if (tf->with == without_flags)
+ without_hex |= hexval;
+ tf->valid = TRUE;
+ continue;
+ }
+ }
+ for (i = 0; i < 12; i++)
+ {
+ if (!strcmp (tf->name, elf_flags_to_names[i].flag_name))
+ {
+ if (tf->with == with_flags)
+ with_hex |= elf_flags_to_names[i].flag_value;
+ else if (tf->with == without_flags)
+ without_hex |= elf_flags_to_names[i].flag_value;
+ tf->valid = TRUE;
+ continue;
+ }
+ }
+ if (tf->valid == FALSE)
+ {
+ info->callbacks->einfo
+ (_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name);
+ return;
+ }
+ }
+ finfo->flags_initialized = TRUE;
+ finfo->only_with_flags |= with_hex;
+ finfo->not_with_flags |= without_hex;
+
+ return;
+}
+
struct alloc_got_off_arg {
bfd_vma gotoff;
struct bfd_link_info *info;
bfd *obfd = gofarg->info->output_bfd;
const struct elf_backend_data *bed = get_elf_backend_data (obfd);
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
if (h->got.refcount > 0)
{
h->got.offset = gofarg->gotoff;
continue;
r_symndx = rcookie->rel->r_info >> rcookie->r_sym_shift;
- if (r_symndx == SHN_UNDEF)
+ if (r_symndx == STN_UNDEF)
return TRUE;
if (r_symndx >= rcookie->locsymcount
return ret;
}
-/* For a SHT_GROUP section, return the group signature. For other
- sections, return the normal section name. */
-
-static const char *
-section_signature (asection *sec)
-{
- if ((sec->flags & SEC_GROUP) != 0
- && elf_next_in_group (sec) != NULL
- && elf_group_name (elf_next_in_group (sec)) != NULL)
- return elf_group_name (elf_next_in_group (sec));
- return sec->name;
-}
-
-void
-_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
+bfd_boolean
+_bfd_elf_section_already_linked (bfd *abfd,
+ asection *sec,
struct bfd_link_info *info)
{
flagword flags;
- const char *name, *p;
+ const char *name, *key;
struct bfd_section_already_linked *l;
struct bfd_section_already_linked_hash_entry *already_linked_list;
if (sec->output_section == bfd_abs_section_ptr)
- return;
+ return FALSE;
flags = sec->flags;
/* Return if it isn't a linkonce section. A comdat group section
also has SEC_LINK_ONCE set. */
if ((flags & SEC_LINK_ONCE) == 0)
- return;
+ return FALSE;
/* Don't put group member sections on our list of already linked
sections. They are handled as a group via their group section. */
if (elf_sec_group (sec) != NULL)
- return;
-
- /* FIXME: When doing a relocatable link, we may have trouble
- copying relocations in other sections that refer to local symbols
- in the section being discarded. Those relocations will have to
- be converted somehow; as of this writing I'm not sure that any of
- the backends handle that correctly.
-
- It is tempting to instead not discard link once sections when
- doing a relocatable link (technically, they should be discarded
- whenever we are building constructors). However, that fails,
- because the linker winds up combining all the link once sections
- into a single large link once section, which defeats the purpose
- of having link once sections in the first place.
-
- Also, not merging link once sections in a relocatable link
- causes trouble for MIPS ELF, which relies on link once semantics
- to handle the .reginfo section correctly. */
-
- name = section_signature (sec);
+ return FALSE;
- if (CONST_STRNEQ (name, ".gnu.linkonce.")
- && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
- p++;
+ /* For a SHT_GROUP section, use the group signature as the key. */
+ name = sec->name;
+ if ((flags & SEC_GROUP) != 0
+ && elf_next_in_group (sec) != NULL
+ && elf_group_name (elf_next_in_group (sec)) != NULL)
+ key = elf_group_name (elf_next_in_group (sec));
else
- p = name;
+ {
+ /* Otherwise we should have a .gnu.linkonce.<type>.<key> section. */
+ if (CONST_STRNEQ (name, ".gnu.linkonce.")
+ && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
+ key++;
+ else
+ /* Must be a user linkonce section that doesn't follow gcc's
+ naming convention. In this case we won't be matching
+ single member groups. */
+ key = name;
+ }
- already_linked_list = bfd_section_already_linked_table_lookup (p);
+ already_linked_list = bfd_section_already_linked_table_lookup (key);
for (l = already_linked_list->entry; l != NULL; l = l->next)
{
/* We may have 2 different types of sections on the list: group
- sections and linkonce sections. Match like sections. */
- if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
- && strcmp (name, section_signature (l->sec)) == 0
- && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+ sections with a signature of <key> (<key> is some string),
+ and linkonce sections named .gnu.linkonce.<type>.<key>.
+ Match like sections. LTO plugin sections are an exception.
+ They are always named .gnu.linkonce.t.<key> and match either
+ type of section. */
+ if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
+ && ((flags & SEC_GROUP) != 0
+ || strcmp (name, l->sec->name) == 0))
+ || (l->sec->owner->flags & BFD_PLUGIN) != 0)
{
/* The section has already been linked. See if we should
issue a warning. */
- switch (flags & SEC_LINK_DUPLICATES)
- {
- default:
- abort ();
-
- case SEC_LINK_DUPLICATES_DISCARD:
- break;
-
- case SEC_LINK_DUPLICATES_ONE_ONLY:
- (*_bfd_error_handler)
- (_("%B: ignoring duplicate section `%A'"),
- abfd, sec);
- break;
-
- case SEC_LINK_DUPLICATES_SAME_SIZE:
- if (sec->size != l->sec->size)
- (*_bfd_error_handler)
- (_("%B: duplicate section `%A' has different size"),
- abfd, sec);
- break;
-
- case SEC_LINK_DUPLICATES_SAME_CONTENTS:
- if (sec->size != l->sec->size)
- (*_bfd_error_handler)
- (_("%B: duplicate section `%A' has different size"),
- abfd, sec);
- else if (sec->size != 0)
- {
- bfd_byte *sec_contents, *l_sec_contents;
-
- if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents))
- (*_bfd_error_handler)
- (_("%B: warning: could not read contents of section `%A'"),
- abfd, sec);
- else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
- &l_sec_contents))
- (*_bfd_error_handler)
- (_("%B: warning: could not read contents of section `%A'"),
- l->sec->owner, l->sec);
- else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
- (*_bfd_error_handler)
- (_("%B: warning: duplicate section `%A' has different contents"),
- abfd, sec);
-
- if (sec_contents)
- free (sec_contents);
- if (l_sec_contents)
- free (l_sec_contents);
- }
- break;
- }
-
- /* Set the output_section field so that lang_add_section
- does not create a lang_input_section structure for this
- section. Since there might be a symbol in the section
- being discarded, we must retain a pointer to the section
- which we are really going to use. */
- sec->output_section = bfd_abs_section_ptr;
- sec->kept_section = l->sec;
+ if (!_bfd_handle_already_linked (sec, l, info))
+ return FALSE;
if (flags & SEC_GROUP)
{
}
}
- return;
+ return TRUE;
}
}
/* A single member comdat group section may be discarded by a
linkonce section and vice versa. */
-
if ((flags & SEC_GROUP) != 0)
{
asection *first = elf_next_in_group (sec);
/* Check this single member group against linkonce sections. */
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, first, info))
{
first->output_section = bfd_abs_section_ptr;
}
/* This is the first section with this name. Record it. */
- if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
+ if (!bfd_section_already_linked_table_insert (already_linked_list, sec))
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
+ return sec->output_section == bfd_abs_section_ptr;
}
bfd_boolean
/* Routines to support the creation of dynamic relocs. */
-/* Return true if NAME is a name of a relocation
- section associated with section S. */
-
-static bfd_boolean
-is_reloc_section (bfd_boolean rela, const char * name, asection * s)
-{
- if (rela)
- return CONST_STRNEQ (name, ".rela")
- && strcmp (bfd_get_section_name (NULL, s), name + 5) == 0;
-
- return CONST_STRNEQ (name, ".rel")
- && strcmp (bfd_get_section_name (NULL, s), name + 4) == 0;
-}
-
/* Returns the name of the dynamic reloc section associated with SEC. */
static const char *
asection * sec,
bfd_boolean is_rela)
{
- const char * name;
- unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
- unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
+ char *name;
+ const char *old_name = bfd_get_section_name (NULL, sec);
+ const char *prefix = is_rela ? ".rela" : ".rel";
- name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
- if (name == NULL)
+ if (old_name == NULL)
return NULL;
- if (! is_reloc_section (is_rela, name, sec))
- {
- static bfd_boolean complained = FALSE;
-
- if (! complained)
- {
- (*_bfd_error_handler)
- (_("%B: bad relocation section name `%s\'"), abfd, name);
- complained = TRUE;
- }
- name = NULL;
- }
+ name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1);
+ sprintf (name, "%s%s", prefix, old_name);
return name;
}
struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *)hsrc;
ehdest->type = ehsrc->type;
+ ehdest->target_internal = ehsrc->target_internal;
+}
+
+/* Append a RELA relocation REL to section S in BFD. */
+
+void
+elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela);
+ BFD_ASSERT (loc + bed->s->sizeof_rela <= s->contents + s->size);
+ bed->s->swap_reloca_out (abfd, rel, loc);
+}
+
+/* Append a REL relocation REL to section S in BFD. */
+
+void
+elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rel);
+ BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size);
+ bed->s->swap_reloca_out (abfd, rel, loc);
}