/* ELF linking support for BFD.
- Copyright (C) 1995-2020 Free Software Foundation, Inc.
+ Copyright (C) 1995-2021 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "plugin.h"
#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
/* This struct is used to pass information to routines called via
elf_link_hash_traverse which must return failure. */
const char *name;
size_t indx;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ /* An IR symbol should not be made dynamic. */
+ if (h->root.u.def.section != NULL
+ && h->root.u.def.section->owner != NULL
+ && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)
+ return TRUE;
+ }
+
/* XXX: The ABI draft says the linker must turn hidden and
internal symbols into STB_LOCAL symbols when producing the
DSO. However, if ld.so honors st_other in the dynamic table,
bfd *input_bfd,
long input_indx)
{
- bfd_size_type amt;
+ size_t amt;
struct elf_link_local_dynamic_entry *entry;
struct elf_link_hash_table *eht;
struct elf_strtab_hash *dynstr;
static void
elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
- const Elf_Internal_Sym *isym, asection *sec,
+ unsigned int st_other, asection *sec,
bfd_boolean definition, bfd_boolean dynamic)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
/* If st_other has a processor-specific meaning, specific
code might be needed here. */
if (bed->elf_backend_merge_symbol_attribute)
- (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
+ (*bed->elf_backend_merge_symbol_attribute) (h, st_other, definition,
dynamic);
if (!dynamic)
{
- unsigned symvis = ELF_ST_VISIBILITY (isym->st_other);
+ unsigned symvis = ELF_ST_VISIBILITY (st_other);
unsigned hvis = ELF_ST_VISIBILITY (h->other);
/* Keep the most constraining visibility. Leave the remainder
h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1));
}
else if (definition
- && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT
+ && ELF_ST_VISIBILITY (st_other) != STV_DEFAULT
&& (sec->flags & SEC_READONLY) == 0)
h->protected_def = 1;
}
bfd_boolean *pold_weak,
unsigned int *pold_alignment,
bfd_boolean *skip,
- bfd_boolean *override,
+ bfd **override,
bfd_boolean *type_change_ok,
bfd_boolean *size_change_ok,
bfd_boolean *matched)
bfd_boolean default_sym = *matched;
*skip = FALSE;
- *override = FALSE;
+ *override = NULL;
sec = *psec;
bind = ELF_ST_BIND (sym->st_info);
|| (h->root.type == bfd_link_hash_common
&& (newweak || newfunc))))
{
- *override = TRUE;
+ *override = abfd;
newdef = FALSE;
newdyncommon = FALSE;
if (newdyncommon
&& h->root.type == bfd_link_hash_common)
{
- *override = TRUE;
+ *override = oldbfd;
newdef = FALSE;
newdyncommon = FALSE;
*pvalue = sym->st_size;
/* Merge st_other. If the symbol already has a dynamic index,
but visibility says it should not be visible, turn it into a
local symbol. */
- elf_merge_st_other (abfd, h, sym, sec, newdef, newdyn);
+ elf_merge_st_other (abfd, h, sym->st_other, sec, newdef, newdyn);
if (h->dynindx != -1)
switch (ELF_ST_VISIBILITY (h->other))
{
const struct elf_backend_data *bed;
bfd_boolean collect;
bfd_boolean dynamic;
- bfd_boolean override;
+ bfd *override;
char *p;
size_t len, shortlen;
asection *tmp_sec;
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
(*bed->elf_backend_copy_indirect_symbol) (info, ht, hi);
+ /* If we first saw a reference to SHORTNAME with non-default
+ visibility, merge that visibility to the @@VER symbol. */
+ elf_merge_st_other (abfd, ht, hi->other, sec, TRUE, dynamic);
+
/* A reference to the SHORTNAME symbol from a dynamic library
will be satisfied by the versioned symbol at runtime. In
effect, we have a reference to the versioned symbol. */
/* We also need to define an indirection from the nondefault version
of the symbol. */
-nondefault:
+ nondefault:
len = strlen (name);
shortname = (char *) bfd_hash_allocate (&info->hash->table, len);
if (shortname == NULL)
return FALSE;
if (skip)
- return TRUE;
-
- if (override)
+ {
+ if (!dynamic
+ && h->root.type == bfd_link_hash_defweak
+ && hi->root.type == bfd_link_hash_defined)
+ {
+ /* We are handling a weak sym@@ver and attempting to define
+ a weak sym@ver, but _bfd_elf_merge_symbol said to skip the
+ new weak sym@ver because there is already a strong sym@ver.
+ However, sym@ver and sym@@ver are really the same symbol.
+ The existing strong sym@ver ought to override sym@@ver. */
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = hi->root.u.def.section;
+ h->root.u.def.value = hi->root.u.def.value;
+ hi->root.type = bfd_link_hash_indirect;
+ hi->root.u.i.link = &h->root;
+ }
+ else
+ return TRUE;
+ }
+ else if (override)
{
/* Here SHORTNAME is a versioned name, so we don't expect to see
the type of override we do in the case above unless it is
/* xgettext:c-format */
(_("%pB: unexpected redefinition of indirect versioned symbol `%s'"),
abfd, shortname);
+ return TRUE;
}
else
{
bfd_ind_section_ptr, 0, name, FALSE, collect, &bh)))
return FALSE;
hi = (struct elf_link_hash_entry *) bh;
+ }
- /* If there is a duplicate definition somewhere, then HI may not
- point to an indirect symbol. We will have reported an error
- to the user in that case. */
+ /* If there is a duplicate definition somewhere, then HI may not
+ point to an indirect symbol. We will have reported an error
+ to the user in that case. */
+ if (hi->root.type == bfd_link_hash_indirect)
+ {
+ (*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
+ h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
+ hi->dynamic_def |= h->dynamic_def;
- if (hi->root.type == bfd_link_hash_indirect)
- {
- (*bed->elf_backend_copy_indirect_symbol) (info, h, hi);
- h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak;
- hi->dynamic_def |= h->dynamic_def;
+ /* If we first saw a reference to @VER symbol with
+ non-default visibility, merge that visibility to the
+ @@VER symbol. */
+ elf_merge_st_other (abfd, h, hi->other, sec, TRUE, dynamic);
- /* See if the new flags lead us to realize that the symbol
- must be dynamic. */
- if (! *dynsym)
+ /* See if the new flags lead us to realize that the symbol
+ must be dynamic. */
+ if (! *dynsym)
+ {
+ if (! dynamic)
{
- if (! dynamic)
- {
- if (! bfd_link_executable (info)
- || hi->ref_dynamic)
- *dynsym = TRUE;
- }
- else
- {
- if (hi->ref_regular)
- *dynsym = TRUE;
- }
+ if (! bfd_link_executable (info)
+ || hi->ref_dynamic)
+ *dynsym = TRUE;
+ }
+ else
+ {
+ if (hi->ref_regular)
+ *dynsym = TRUE;
}
}
}
struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data;
Elf_Internal_Verneed *t;
Elf_Internal_Vernaux *a;
- bfd_size_type amt;
+ size_t amt;
/* We only care about symbols defined in shared objects with version
information. */
if (keep_memory)
esdo->relocs = internal_relocs;
- if (alloc1 != NULL)
- free (alloc1);
+ free (alloc1);
/* Don't free alloc2, since if it was allocated we are passing it
back (under the name of internal_relocs). */
return internal_relocs;
error_return:
- if (alloc1 != NULL)
- free (alloc1);
+ free (alloc1);
if (alloc2 != NULL)
{
if (keep_memory)
elf_hash_table (info)->tls_sec = tls;
- /* Ensure the alignment of the first section is the largest alignment,
- so that the tls segment starts aligned. */
+ /* Ensure the alignment of the first section (usually .tdata) is the largest
+ alignment, so that the tls segment starts aligned. */
if (tls != NULL)
tls->alignment_power = align;
return TRUE;
}
-/* Add a DT_NEEDED entry for this dynamic object if DO_IT is true,
- otherwise just check whether one already exists. Returns -1 on error,
+/* Strip zero-sized dynamic sections. */
+
+bfd_boolean
+_bfd_elf_strip_zero_sized_dynamic_sections (struct bfd_link_info *info)
+{
+ struct elf_link_hash_table *hash_table;
+ const struct elf_backend_data *bed;
+ asection *s, *sdynamic, **pp;
+ asection *rela_dyn, *rel_dyn;
+ Elf_Internal_Dyn dyn;
+ bfd_byte *extdyn, *next;
+ void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+ bfd_boolean strip_zero_sized;
+ bfd_boolean strip_zero_sized_plt;
+
+ if (bfd_link_relocatable (info))
+ return TRUE;
+
+ hash_table = elf_hash_table (info);
+ if (!is_elf_hash_table (hash_table))
+ return FALSE;
+
+ if (!hash_table->dynobj)
+ return TRUE;
+
+ sdynamic= bfd_get_linker_section (hash_table->dynobj, ".dynamic");
+ if (!sdynamic)
+ return TRUE;
+
+ bed = get_elf_backend_data (hash_table->dynobj);
+ swap_dyn_in = bed->s->swap_dyn_in;
+
+ strip_zero_sized = FALSE;
+ strip_zero_sized_plt = FALSE;
+
+ /* Strip zero-sized dynamic sections. */
+ rela_dyn = bfd_get_section_by_name (info->output_bfd, ".rela.dyn");
+ rel_dyn = bfd_get_section_by_name (info->output_bfd, ".rel.dyn");
+ for (pp = &info->output_bfd->sections; (s = *pp) != NULL;)
+ if (s->size == 0
+ && (s == rela_dyn
+ || s == rel_dyn
+ || s == hash_table->srelplt->output_section
+ || s == hash_table->splt->output_section))
+ {
+ *pp = s->next;
+ info->output_bfd->section_count--;
+ strip_zero_sized = TRUE;
+ if (s == rela_dyn)
+ s = rela_dyn;
+ if (s == rel_dyn)
+ s = rel_dyn;
+ else if (s == hash_table->splt->output_section)
+ {
+ s = hash_table->splt;
+ strip_zero_sized_plt = TRUE;
+ }
+ else
+ s = hash_table->srelplt;
+ s->flags |= SEC_EXCLUDE;
+ s->output_section = bfd_abs_section_ptr;
+ }
+ else
+ pp = &s->next;
+
+ if (strip_zero_sized_plt)
+ for (extdyn = sdynamic->contents;
+ extdyn < sdynamic->contents + sdynamic->size;
+ extdyn = next)
+ {
+ next = extdyn + bed->s->sizeof_dyn;
+ swap_dyn_in (hash_table->dynobj, extdyn, &dyn);
+ switch (dyn.d_tag)
+ {
+ default:
+ break;
+ case DT_JMPREL:
+ case DT_PLTRELSZ:
+ case DT_PLTREL:
+ /* Strip DT_PLTRELSZ, DT_JMPREL and DT_PLTREL entries if
+ the procedure linkage table (the .plt section) has been
+ removed. */
+ memmove (extdyn, next,
+ sdynamic->size - (next - sdynamic->contents));
+ next = extdyn;
+ }
+ }
+
+ if (strip_zero_sized)
+ {
+ /* Regenerate program headers. */
+ elf_seg_map (info->output_bfd) = NULL;
+ return _bfd_elf_map_sections_to_segments (info->output_bfd, info);
+ }
+
+ return TRUE;
+}
+
+/* Add a DT_NEEDED entry for this dynamic object. Returns -1 on error,
1 if a DT_NEEDED tag already exists, and 0 on success. */
-static int
-elf_add_dt_needed_tag (bfd *abfd,
- struct bfd_link_info *info,
- const char *soname,
- bfd_boolean do_it)
+int
+bfd_elf_add_dt_needed_tag (bfd *abfd, struct bfd_link_info *info)
{
struct elf_link_hash_table *hash_table;
size_t strindex;
+ const char *soname;
if (!_bfd_elf_link_create_dynstrtab (abfd, info))
return -1;
hash_table = elf_hash_table (info);
+ soname = elf_dt_name (abfd);
strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE);
if (strindex == (size_t) -1)
return -1;
}
}
- if (do_it)
- {
- if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
- return -1;
+ if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info))
+ return -1;
- if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
- return -1;
- }
- else
- /* We were just checking for existence of the tag. */
- _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
+ if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+ return -1;
return 0;
}
_bfd_elf_strtab_finalize (dynstr);
size = _bfd_elf_strtab_size (dynstr);
+ /* Allow the linker to examine the dynsymtab now it's fully populated. */
+
+ if (info->callbacks->examine_strtab)
+ info->callbacks->examine_strtab (dynstr);
+
bed = get_elf_backend_data (dynobj);
sdyn = bfd_get_linker_section (dynobj, ".dynamic");
BFD_ASSERT (sdyn != NULL);
Elf_Internal_Rela *internal_relocs;
bfd_boolean ok;
- /* Don't check relocations in excluded sections. */
- if ((o->flags & SEC_RELOC) == 0
+ /* Don't check relocations in excluded sections. Don't do
+ anything special with non-loaded, non-alloced sections.
+ In particular, any relocs in such sections should not
+ affect GOT and PLT reference counting (ie. we don't
+ allow them to create GOT or PLT entries), there's no
+ possibility or desire to optimize TLS relocs, and
+ there's not much point in propagating relocs to shared
+ libs that the dynamic linker won't relocate. */
+ if ((o->flags & SEC_ALLOC) == 0
+ || (o->flags & SEC_RELOC) == 0
|| (o->flags & SEC_EXCLUDE) != 0
|| o->reloc_count == 0
|| ((info->strip == strip_all || info->strip == strip_debugger)
const struct elf_backend_data *bed;
bfd_boolean add_needed;
struct elf_link_hash_table *htab;
- bfd_size_type amt;
void *alloc_mark = NULL;
struct bfd_hash_entry **old_table = NULL;
unsigned int old_size = 0;
char *audit = NULL;
struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
const Elf_Internal_Phdr *phdr;
- int ret;
+ struct elf_link_loaded_list *loaded_lib;
/* ld --just-symbols and dynamic objects don't mix very well.
ld shouldn't allow it. */
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
{
-error_free_dyn:
+ error_free_dyn:
free (dynbuf);
goto error_return;
}
struct bfd_link_needed_list *n, **pn;
char *fnm, *anm;
unsigned int tagv = dyn.d_un.d_val;
+ size_t amt = sizeof (struct bfd_link_needed_list);
- amt = sizeof (struct bfd_link_needed_list);
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
struct bfd_link_needed_list *n, **pn;
char *fnm, *anm;
unsigned int tagv = dyn.d_un.d_val;
+ size_t amt = sizeof (struct bfd_link_needed_list);
- amt = sizeof (struct bfd_link_needed_list);
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
struct bfd_link_needed_list *n, **pn;
char *fnm, *anm;
unsigned int tagv = dyn.d_un.d_val;
+ size_t amt = sizeof (struct bfd_link_needed_list);
- amt = sizeof (struct bfd_link_needed_list);
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
if (phdr->p_type == PT_GNU_RELRO)
{
for (s = abfd->sections; s != NULL; s = s->next)
- if ((s->flags & SEC_ALLOC) != 0
- && s->vma >= phdr->p_vaddr
- && s->vma + s->size <= phdr->p_vaddr + phdr->p_memsz)
- s->flags |= SEC_READONLY;
+ {
+ unsigned int opb = bfd_octets_per_byte (abfd, s);
+
+ if ((s->flags & SEC_ALLOC) != 0
+ && s->vma * opb >= phdr->p_vaddr
+ && s->vma * opb + s->size <= phdr->p_vaddr + phdr->p_memsz)
+ s->flags |= SEC_READONLY;
+ }
break;
}
will need to know it. */
elf_dt_name (abfd) = soname;
- ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
- if (ret < 0)
- goto error_return;
-
/* If we have already included this dynamic object in the
link, just ignore it. There is no reason to include a
particular dynamic object more than once. */
- if (ret > 0)
- return TRUE;
+ for (loaded_lib = htab->dyn_loaded;
+ loaded_lib != NULL;
+ loaded_lib = loaded_lib->next)
+ {
+ if (strcmp (elf_dt_name (loaded_lib->abfd), soname) == 0)
+ return TRUE;
+ }
+
+ /* Create dynamic sections for backends that require that be done
+ before setup_gnu_properties. */
+ if (add_needed
+ && !_bfd_elf_link_create_dynamic_sections (abfd, info))
+ return FALSE;
/* Save the DT_AUDIT entry for the linker emulation code. */
elf_dt_audit (abfd) = audit;
{
/* We store a pointer to the hash table entry for each
external symbol. */
- amt = extsymcount;
- amt *= sizeof (struct elf_link_hash_entry *);
+ size_t amt = extsymcount * sizeof (struct elf_link_hash_entry *);
sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt);
if (sym_hash == NULL)
goto error_free_sym;
to internal format. */
if (elf_dynversym (abfd) != 0)
{
- Elf_Internal_Shdr *versymhdr;
+ Elf_Internal_Shdr *versymhdr = &elf_tdata (abfd)->dynversym_hdr;
+ bfd_size_type amt = versymhdr->sh_size;
- versymhdr = &elf_tdata (abfd)->dynversym_hdr;
- amt = versymhdr->sh_size;
- extversym = (Elf_External_Versym *) bfd_malloc (amt);
+ if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0)
+ goto error_free_sym;
+ extversym = (Elf_External_Versym *)
+ _bfd_malloc_and_read (abfd, amt, amt);
if (extversym == NULL)
goto error_free_sym;
- if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (extversym, amt, abfd) != amt)
- goto error_free_vers;
- extversym_end = extversym + (amt / sizeof (* extversym));
+ extversym_end = extversym + amt / sizeof (*extversym);
}
}
h = (struct elf_link_hash_entry *) p;
entsize += htab->root.table.entsize;
if (h->root.type == bfd_link_hash_warning)
- entsize += htab->root.table.entsize;
+ {
+ entsize += htab->root.table.entsize;
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+ if (h->root.type == bfd_link_hash_common)
+ entsize += sizeof (*h->root.u.c.p);
}
}
old_table = htab->root.table.table;
old_size = htab->root.table.size;
old_count = htab->root.table.count;
- old_strtab = _bfd_elf_strtab_save (htab->dynstr);
- if (old_strtab == NULL)
- goto error_free_vers;
+ old_strtab = NULL;
+ if (htab->dynstr != NULL)
+ {
+ old_strtab = _bfd_elf_strtab_save (htab->dynstr);
+ if (old_strtab == NULL)
+ goto error_free_vers;
+ }
for (i = 0; i < htab->root.table.size; i++)
{
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
- memcpy (old_ent, p, htab->root.table.entsize);
- old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) p;
+ memcpy (old_ent, h, htab->root.table.entsize);
+ old_ent = (char *) old_ent + htab->root.table.entsize;
if (h->root.type == bfd_link_hash_warning)
{
- memcpy (old_ent, h->root.u.i.link, htab->root.table.entsize);
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ memcpy (old_ent, h, htab->root.table.entsize);
old_ent = (char *) old_ent + htab->root.table.entsize;
}
+ if (h->root.type == bfd_link_hash_common)
+ {
+ memcpy (old_ent, h->root.u.c.p, sizeof (*h->root.u.c.p));
+ old_ent = (char *) old_ent + sizeof (*h->root.u.c.p);
+ }
}
}
}
bfd_boolean type_change_ok;
bfd_boolean new_weak;
bfd_boolean old_weak;
- bfd_boolean override;
+ bfd *override;
bfd_boolean common;
bfd_boolean discarded;
unsigned int old_alignment;
bfd *old_bfd;
bfd_boolean matched;
- override = FALSE;
+ override = NULL;
flags = BSF_NO_FLAGS;
sec = NULL;
}
if (! (_bfd_generic_link_add_one_symbol
- (info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect,
+ (info, override ? override : abfd, name, flags, sec, value,
+ NULL, FALSE, bed->collect,
(struct bfd_link_hash_entry **) sym_hash)))
goto error_free_vers;
object and a shared object. */
bfd_boolean dynsym = FALSE;
- /* Plugin symbols aren't normal. Don't set def_regular or
- ref_regular for them, or make them dynamic. */
+ /* Plugin symbols aren't normal. Don't set def/ref flags. */
if ((abfd->flags & BFD_PLUGIN) != 0)
;
- else if (! dynamic)
+ else if (!dynamic)
{
if (! definition)
{
h->ref_dynamic = 1;
}
}
-
- /* If the indirect symbol has been forced local, don't
- make the real symbol dynamic. */
- if ((h == hi || !hi->forced_local)
- && (bfd_link_dll (info)
- || h->def_dynamic
- || h->ref_dynamic))
- dynsym = TRUE;
}
else
{
h->def_dynamic = 1;
hi->def_dynamic = 1;
}
+ }
- /* If the indirect symbol has been forced local, don't
- make the real symbol dynamic. */
- if ((h == hi || !hi->forced_local)
- && (h->def_regular
- || h->ref_regular
- || (h->is_weakalias
- && weakdef (h)->dynindx != -1)))
+ /* If an indirect symbol has been forced local, don't
+ make the real symbol dynamic. */
+ if (h != hi && hi->forced_local)
+ ;
+ else if (!dynamic)
+ {
+ if (bfd_link_dll (info)
+ || h->def_dynamic
+ || h->ref_dynamic)
+ dynsym = TRUE;
+ }
+ else
+ {
+ if (h->def_regular
+ || h->ref_regular
+ || (h->is_weakalias
+ && weakdef (h)->dynindx != -1))
dynsym = TRUE;
}
/* Check to see if we need to add an indirect symbol for
the default name. */
- if (definition
- || (!override && h->root.type == bfd_link_hash_common))
+ if ((definition
+ || (!override && h->root.type == bfd_link_hash_common))
+ && !(hi != h
+ && hi->versioned == versioned_hidden))
if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
sec, value, &old_bfd, &dynsym))
goto error_free_vers;
}
/* Merge st_other field. */
- elf_merge_st_other (abfd, h, isym, sec, definition, dynamic);
+ elf_merge_st_other (abfd, h, isym->st_other, sec,
+ definition, dynamic);
/* We don't want to make debug symbol dynamic. */
if (definition
aliases can be checked. */
if (!nondeflt_vers)
{
- amt = ((isymend - isym + 1)
- * sizeof (struct elf_link_hash_entry *));
+ size_t amt = ((isymend - isym + 1)
+ * sizeof (struct elf_link_hash_entry *));
nondeflt_vers
= (struct elf_link_hash_entry **) bfd_malloc (amt);
if (!nondeflt_vers)
break;
}
- /* Don't add DT_NEEDED for references from the dummy bfd nor
- for unmatched symbol. */
if (!add_needed
&& matched
&& definition
&& ((dynsym
- && h->ref_regular_nonweak
- && (old_bfd == NULL
- || (old_bfd->flags & BFD_PLUGIN) == 0))
+ && h->ref_regular_nonweak)
+ || (old_bfd != NULL
+ && (old_bfd->flags & BFD_PLUGIN) != 0
+ && bind != STB_WEAK)
|| (h->ref_dynamic_nonweak
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0
&& !on_needed_list (elf_dt_name (abfd),
htab->needed, NULL))))
{
- int ret;
const char *soname = elf_dt_name (abfd);
info->callbacks->minfo ("%!", soname, old_bfd,
elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
(elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);
+ /* Create dynamic sections for backends that require
+ that be done before setup_gnu_properties. */
+ if (!_bfd_elf_link_create_dynamic_sections (abfd, info))
+ return FALSE;
add_needed = TRUE;
- ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed);
- if (ret < 0)
- goto error_free_vers;
-
- BFD_ASSERT (ret == 0);
}
}
}
}
}
- if (extversym != NULL)
- {
- free (extversym);
- extversym = NULL;
- }
-
- if (isymbuf != NULL)
- {
- free (isymbuf);
- isymbuf = NULL;
- }
+ free (extversym);
+ extversym = NULL;
+ free (isymbuf);
+ isymbuf = NULL;
if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)
{
memcpy (htab->root.table.table, old_tab, tabsize);
htab->root.undefs = old_undefs;
htab->root.undefs_tail = old_undefs_tail;
- _bfd_elf_strtab_restore (htab->dynstr, old_strtab);
+ if (htab->dynstr != NULL)
+ _bfd_elf_strtab_restore (htab->dynstr, old_strtab);
free (old_strtab);
old_strtab = NULL;
for (i = 0; i < htab->root.table.size; i++)
{
struct bfd_hash_entry *p;
struct elf_link_hash_entry *h;
- bfd_size_type size;
- unsigned int alignment_power;
unsigned int non_ir_ref_dynamic;
for (p = htab->root.table.table[i]; p != NULL; p = p->next)
{
- h = (struct elf_link_hash_entry *) p;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- /* 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 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;
- }
/* Preserve non_ir_ref_dynamic so that this symbol
will be exported when the dynamic lib becomes needed
in the second pass. */
+ h = (struct elf_link_hash_entry *) p;
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
non_ir_ref_dynamic = h->root.non_ir_ref_dynamic;
- 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, old_ent, htab->root.table.entsize);
+ old_ent = (char *) old_ent + htab->root.table.entsize;
if (h->root.type == bfd_link_hash_warning)
{
- memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
- old_ent = (char *) old_ent + htab->root.table.entsize;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ memcpy (h, old_ent, htab->root.table.entsize);
+ old_ent = (char *) old_ent + htab->root.table.entsize;
}
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;
+ memcpy (h->root.u.c.p, old_ent, sizeof (*h->root.u.c.p));
+ old_ent = (char *) old_ent + sizeof (*h->root.u.c.p);
}
h->root.non_ir_ref_dynamic = non_ir_ref_dynamic;
}
free (old_tab);
objalloc_free_block ((struct objalloc *) htab->root.table.memory,
alloc_mark);
- if (nondeflt_vers != NULL)
- free (nondeflt_vers);
+ free (nondeflt_vers);
return TRUE;
}
{
struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi;
char *shortname, *p;
+ size_t amt;
p = strchr (h->root.root.string, ELF_VER_CHR);
if (p == NULL
struct elf_link_hash_entry **hppend;
struct elf_link_hash_entry **sorted_sym_hash;
struct elf_link_hash_entry *h;
- size_t sym_count;
+ size_t sym_count, amt;
/* Since we have to search the whole symbol list for each weak
defined symbol, search time for N weak defined symbols will be
O(N^2). Binary search will cut it down to O(NlogN). */
- amt = extsymcount;
- amt *= sizeof (*sorted_sym_hash);
+ amt = extsymcount * sizeof (*sorted_sym_hash);
sorted_sym_hash = bfd_malloc (amt);
if (sorted_sym_hash == NULL)
goto error_return;
}
}
- if (is_elf_hash_table (htab) && add_needed)
+ if (dynamic && add_needed)
{
/* Add this bfd to the loaded list. */
struct elf_link_loaded_list *n;
if (n == NULL)
goto error_return;
n->abfd = abfd;
- n->next = htab->loaded;
- htab->loaded = n;
+ n->next = htab->dyn_loaded;
+ htab->dyn_loaded = n;
}
+ if (dynamic && !add_needed
+ && (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) != 0)
+ elf_dyn_lib_class (abfd) |= DYN_NO_NEEDED;
return TRUE;
error_free_vers:
- if (old_tab != NULL)
- free (old_tab);
- if (old_strtab != NULL)
- free (old_strtab);
- if (nondeflt_vers != NULL)
- free (nondeflt_vers);
- if (extversym != NULL)
- free (extversym);
+ free (old_tab);
+ free (old_strtab);
+ free (nondeflt_vers);
+ free (extversym);
error_free_sym:
- if (isymbuf != NULL)
- free (isymbuf);
+ free (isymbuf);
error_return:
return FALSE;
}
unsigned char *included = NULL;
carsym *symdefs;
bfd_boolean loop;
- bfd_size_type amt;
+ size_t amt;
const struct elf_backend_data *bed;
struct elf_link_hash_entry * (*archive_symbol_lookup)
(bfd *, struct bfd_link_info *, const char *);
c = bfd_ardata (abfd)->symdef_count;
if (c == 0)
return TRUE;
- amt = c;
- amt *= sizeof (*included);
+ amt = c * sizeof (*included);
included = (unsigned char *) bfd_zmalloc (amt);
if (included == NULL)
return FALSE;
if (h == NULL)
continue;
- if (h->root.type == bfd_link_hash_common)
+ if (h->root.type == bfd_link_hash_undefined)
+ {
+ /* If the archive element has already been loaded then one
+ of the symbols defined by that element might have been
+ made undefined due to being in a discarded section. */
+ if (h->indx == -3)
+ continue;
+ }
+ else if (h->root.type == bfd_link_hash_common)
{
/* We currently have a common symbol. The archive map contains
a reference to this symbol, so we may want to include it. We
if (! elf_link_is_defined_archive_symbol (abfd, symdef))
continue;
}
- else if (h->root.type != bfd_link_hash_undefined)
+ else
{
if (h->root.type != bfd_link_hash_undefweak)
/* Symbol must be defined. Don't check it again. */
while (loop);
free (included);
-
return TRUE;
error_return:
- if (included != NULL)
- free (included);
+ free (included);
return FALSE;
}
later. */
h->u.elf_hash_value = ha;
- if (alc != NULL)
- free (alc);
-
+ free (alc);
return TRUE;
}
if (s->min_dynindx < 0 || s->min_dynindx > h->dynindx)
s->min_dynindx = h->dynindx;
- if (alc != NULL)
- free (alc);
-
+ free (alc);
return TRUE;
}
{
size_t indx;
- name = lbasename (output_bfd->filename);
+ name = lbasename (bfd_get_filename (output_bfd));
def.vd_hash = bfd_elf_hash (name);
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
name, FALSE);
indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
elf_dt_name (vn->vn_bfd) != NULL
? elf_dt_name (vn->vn_bfd)
- : lbasename (vn->vn_bfd->filename),
+ : lbasename (bfd_get_filename
+ (vn->vn_bfd)),
FALSE);
if (indx == (size_t) -1)
return FALSE;
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMENT,
- bed->s->sizeof_sym))
+ bed->s->sizeof_sym)
+ || (info->gnu_flags_1
+ && !_bfd_elf_add_dynamic_entry (info, DT_GNU_FLAGS_1,
+ info->gnu_flags_1)))
return FALSE;
}
}
{
struct elf_link_hash_table *htab;
+ if (ind->dyn_relocs != NULL)
+ {
+ if (dir->dyn_relocs != NULL)
+ {
+ struct elf_dyn_relocs **pp;
+ struct elf_dyn_relocs *p;
+
+ /* Add reloc counts against the indirect sym to the direct sym
+ list. Merge any entries against the same section. */
+ for (pp = &ind->dyn_relocs; (p = *pp) != NULL; )
+ {
+ struct elf_dyn_relocs *q;
+
+ for (q = dir->dyn_relocs; q != NULL; q = q->next)
+ if (q->sec == p->sec)
+ {
+ q->pc_count += p->pc_count;
+ q->count += p->count;
+ *pp = p->next;
+ break;
+ }
+ if (q == NULL)
+ pp = &p->next;
+ }
+ *pp = dir->dyn_relocs;
+ }
+
+ dir->dyn_relocs = ind->dyn_relocs;
+ ind->dyn_relocs = NULL;
+ }
+
/* Copy down any references that we may have already seen to the
symbol which just became indirect. */
table->root.type = bfd_link_elf_hash_table;
table->hash_table_id = target_id;
+ table->target_os = get_elf_backend_data (abfd)->target_os;
return ret;
}
_bfd_elf_link_hash_table_create (bfd *abfd)
{
struct elf_link_hash_table *ret;
- bfd_size_type amt = sizeof (struct elf_link_hash_table);
+ size_t amt = sizeof (struct elf_link_hash_table);
ret = (struct elf_link_hash_table *) bfd_zmalloc (amt);
if (ret == NULL)
const char *string;
struct bfd_link_needed_list *l;
unsigned int tagv = dyn.d_un.d_val;
- bfd_size_type amt;
+ size_t amt;
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (string == NULL)
return TRUE;
error_return:
- if (dynbuf != NULL)
- free (dynbuf);
+ free (dynbuf);
return FALSE;
}
Elf_Internal_Sym **ind, **indbufend, **indbuf;
struct elf_symbuf_symbol *ssym;
struct elf_symbuf_head *ssymbuf, *ssymhead;
- size_t i, shndx_count, total_size;
+ size_t i, shndx_count, total_size, amt;
- indbuf = (Elf_Internal_Sym **) bfd_malloc2 (symcount, sizeof (*indbuf));
+ amt = symcount * sizeof (*indbuf);
+ indbuf = (Elf_Internal_Sym **) bfd_malloc (amt);
if (indbuf == NULL)
return NULL;
if (isymbuf1 == NULL)
goto done;
- if (!info->reduce_memory_overheads)
+ if (info != NULL && !info->reduce_memory_overheads)
{
ssymbuf1 = elf_create_symbuf (symcount1, isymbuf1);
elf_tdata (bfd1)->symbuf = ssymbuf1;
if (isymbuf2 == NULL)
goto done;
- if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
+ if (ssymbuf1 != NULL && info != NULL && !info->reduce_memory_overheads)
{
ssymbuf2 = elf_create_symbuf (symcount2, isymbuf2);
elf_tdata (bfd2)->symbuf = ssymbuf2;
result = TRUE;
-done:
- if (symtable1)
- free (symtable1);
- if (symtable2)
- free (symtable2);
- if (isymbuf1)
- free (isymbuf1);
- if (isymbuf2)
- free (isymbuf2);
+ done:
+ free (symtable1);
+ free (symtable2);
+ free (isymbuf1);
+ free (isymbuf2);
return result;
}
Elf_External_Sym_Shndx *symshndxbuf;
/* Number of STT_FILE syms seen. */
size_t filesym_count;
+ /* Local symbol hash table. */
+ struct bfd_hash_table local_hash_table;
};
+struct local_hash_entry
+{
+ /* Base hash table entry structure. */
+ struct bfd_hash_entry root;
+ /* Size of the local symbol name. */
+ size_t size;
+ /* Number of the duplicated local symbol names. */
+ long count;
+};
+
+/* Create an entry in the local symbol hash table. */
+
+static struct bfd_hash_entry *
+local_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (entry == NULL)
+ {
+ entry = bfd_hash_allocate (table,
+ sizeof (struct local_hash_entry));
+ if (entry == NULL)
+ return entry;
+ }
+
+ /* Call the allocation method of the superclass. */
+ entry = bfd_hash_newfunc (entry, table, string);
+ if (entry != NULL)
+ {
+ ((struct local_hash_entry *) entry)->count = 0;
+ ((struct local_hash_entry *) entry)->size = 0;
+ }
+
+ return entry;
+}
+
/* This struct is used to pass information to elf_link_output_extsym. */
struct elf_outext_info
implementation of them consists of two parts: complex symbols, and the
relocations themselves.
- The relocations are use a reserved elf-wide relocation type code (R_RELC
+ The relocations use a reserved elf-wide relocation type code (R_RELC
external / BFD_RELOC_RELC internal) and an encoding of relocation field
information (start bit, end bit, word width, etc) into the addend. This
information is extracted from CGEN-generated operand tables within gas.
- Complex symbols are mangled symbols (BSF_RELC external / STT_RELC
+ Complex symbols are mangled symbols (STT_RELC external / BSF_RELC
internal) representing prefix-notation expressions, including but not
limited to those sorts of expressions normally encoded as addends in the
addend field. The symbol mangling format is:
/* xgettext:c-format */
_bfd_error_handler (_("undefined %s reference in complex symbol: %s"),
reftype, name);
+ bfd_set_error (bfd_error_bad_value);
}
static bfd_boolean
return TRUE; \
}
-#define BINARY_OP(op) \
+#define BINARY_OP_HEAD(op) \
if (strncmp (sym, #op, strlen (#op)) == 0) \
{ \
sym += strlen (#op); \
++*symp; \
if (!eval_symbol (&b, symp, input_bfd, flinfo, dot, \
isymbuf, locsymcount, signed_p)) \
- return FALSE; \
+ return FALSE;
+#define BINARY_OP_TAIL(op) \
if (signed_p) \
*result = ((bfd_signed_vma) a) op ((bfd_signed_vma) b); \
else \
*result = a op b; \
return TRUE; \
}
+#define BINARY_OP(op) BINARY_OP_HEAD(op) BINARY_OP_TAIL(op)
default:
UNARY_OP (0-);
- BINARY_OP (<<);
- BINARY_OP (>>);
+ BINARY_OP_HEAD (<<);
+ if (b >= sizeof (a) * CHAR_BIT)
+ {
+ *result = 0;
+ return TRUE;
+ }
+ signed_p = 0;
+ BINARY_OP_TAIL (<<);
+ BINARY_OP_HEAD (>>);
+ if (b >= sizeof (a) * CHAR_BIT)
+ {
+ *result = signed_p && (bfd_signed_vma) a < 0 ? -1 : 0;
+ return TRUE;
+ }
+ BINARY_OP_TAIL (>>);
BINARY_OP (==);
BINARY_OP (!=);
BINARY_OP (<=);
UNARY_OP (~);
UNARY_OP (!);
BINARY_OP (*);
- BINARY_OP (/);
- BINARY_OP (%);
+ BINARY_OP_HEAD (/);
+ if (b == 0)
+ {
+ _bfd_error_handler (_("division by zero"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ BINARY_OP_TAIL (/);
+ BINARY_OP_HEAD (%);
+ if (b == 0)
+ {
+ _bfd_error_handler (_("division by zero"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ BINARY_OP_TAIL (%);
BINARY_OP (^);
BINARY_OP (|);
BINARY_OP (&);
{
/* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
to get the final offset for st_name. */
+ char *versioned_name = (char *) name;
+ if (h != NULL)
+ {
+ if (h->versioned == versioned && h->def_dynamic)
+ {
+ /* Keep only one '@' for versioned symbols defined in
+ shared objects. */
+ char *version = strrchr (name, ELF_VER_CHR);
+ char *base_end = strchr (name, ELF_VER_CHR);
+ if (version != base_end)
+ {
+ size_t base_len;
+ size_t len = strlen (name);
+ versioned_name = bfd_alloc (flinfo->output_bfd, len);
+ if (versioned_name == NULL)
+ return 0;
+ base_len = base_end - name;
+ memcpy (versioned_name, name, base_len);
+ memcpy (versioned_name + base_len, version,
+ len - base_len);
+ }
+ }
+ }
+ else if (flinfo->info->unique_symbol
+ && ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
+ {
+ struct local_hash_entry *lh;
+ switch (ELF_ST_TYPE (elfsym->st_info))
+ {
+ case STT_FILE:
+ case STT_SECTION:
+ break;
+ default:
+ lh = (struct local_hash_entry *) bfd_hash_lookup
+ (&flinfo->local_hash_table, name, TRUE, FALSE);
+ if (lh == NULL)
+ return 0;
+ if (lh->count)
+ {
+ /* Append ".COUNT" to duplicated local symbols. */
+ size_t count_len;
+ size_t base_len = lh->size;
+ char buf[30];
+ sprintf (buf, "%lx", lh->count);
+ if (!base_len)
+ {
+ base_len = strlen (name);
+ lh->size = base_len;
+ }
+ count_len = strlen (buf);
+ versioned_name = bfd_alloc (flinfo->output_bfd,
+ base_len + count_len + 2);
+ if (versioned_name == NULL)
+ return 0;
+ memcpy (versioned_name, name, base_len);
+ versioned_name[base_len] = '.';
+ memcpy (versioned_name + base_len + 1, buf,
+ count_len + 1);
+ }
+ lh->count++;
+ break;
+ }
+ }
elfsym->st_name
= (unsigned long) _bfd_elf_strtab_add (flinfo->symstrtab,
- name, FALSE);
+ versioned_name, FALSE);
if (elfsym->st_name == (unsigned long) -1)
return 0;
}
elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
{
struct elf_link_hash_table *hash_table = elf_hash_table (flinfo->info);
- bfd_size_type amt;
+ size_t amt;
size_t i;
const struct elf_backend_data *bed;
bfd_byte *symbuf;
}
}
+ /* Now swap out the symbols. */
for (i = 0; i < hash_table->strtabcount; i++)
{
struct elf_sym_strtab *elfsym = &hash_table->strtab[i];
elfsym->sym.st_name
= (unsigned long) _bfd_elf_strtab_offset (flinfo->symstrtab,
elfsym->sym.st_name);
+
+ /* Inform the linker of the addition of this symbol. */
+
+ if (flinfo->info->callbacks->ctf_new_symbol)
+ flinfo->info->callbacks->ctf_new_symbol (elfsym->dest_index,
+ &elfsym->sym);
+
bed->s->swap_symbol_out (flinfo->output_bfd, &elfsym->sym,
((bfd_byte *) symbuf
+ (elfsym->dest_index
+ elfsym->destshndx_index));
}
- /* Allow the linker to examine the strtab and symtab now they are
- populated. */
-
- if (flinfo->info->callbacks->examine_strtab)
- flinfo->info->callbacks->examine_strtab (hash_table->strtab,
- hash_table->strtabcount,
- flinfo->symstrtab);
-
hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
pos = hdr->sh_offset + hdr->sh_size;
amt = hash_table->strtabcount * bed->s->sizeof_sym;
}
BFD_ASSERT (abfd != NULL);
- for (loaded = elf_hash_table (info)->loaded;
+ for (loaded = elf_hash_table (info)->dyn_loaded;
loaded != NULL;
loaded = loaded->next)
{
/* We check each DSO for a possible hidden versioned definition. */
if (input == abfd
- || (input->flags & DYNAMIC) == 0
|| elf_dynversym (input) == 0)
continue;
/* Read in any version definitions. */
versymhdr = &elf_tdata (input)->dynversym_hdr;
- extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
- if (extversym == NULL)
- goto error_ret;
-
if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0
- || (bfd_bread (extversym, versymhdr->sh_size, input)
- != versymhdr->sh_size))
+ || (extversym = (Elf_External_Versym *)
+ _bfd_malloc_and_read (input, versymhdr->sh_size,
+ versymhdr->sh_size)) == NULL)
{
- free (extversym);
- error_ret:
free (isymbuf);
return FALSE;
}
&& (!h->ref_regular || flinfo->info->gc_sections)
&& !elf_link_check_versioned_symbol (flinfo->info, bed, h)
&& flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
- (*flinfo->info->callbacks->undefined_symbol)
- (flinfo->info, h->root.root.string,
- h->ref_regular ? NULL : h->root.u.undef.abfd,
- NULL, 0,
- flinfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR);
+ {
+ flinfo->info->callbacks->undefined_symbol
+ (flinfo->info, h->root.root.string,
+ h->ref_regular ? NULL : h->root.u.undef.abfd, NULL, 0,
+ flinfo->info->unresolved_syms_in_shared_libs == RM_DIAGNOSE
+ && !flinfo->info->warn_unresolved_syms);
+ }
/* Strip a global symbol defined in a discarded section. */
if (h->indx == -3)
eoinfo->failed = TRUE;
return FALSE;
}
+
+ /* Inform the linker of the addition of this symbol. */
+
+ if (flinfo->info->callbacks->ctf_new_dynsym)
+ flinfo->info->callbacks->ctf_new_dynsym (h->dynindx, &sym);
+
bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0);
if (flinfo->hash_sec != NULL)
{
if ((kept->flags & SEC_GROUP) != 0)
kept = match_group_member (sec, kept, info);
- if (kept != NULL
- && ((sec->rawsize != 0 ? sec->rawsize : sec->size)
- != (kept->rawsize != 0 ? kept->rawsize : kept->size)))
- kept = NULL;
+ if (kept != NULL)
+ {
+ if ((sec->rawsize != 0 ? sec->rawsize : sec->size)
+ != (kept->rawsize != 0 ? kept->rawsize : kept->size))
+ kept = NULL;
+ else
+ {
+ /* Get the real kept section. */
+ asection *next;
+ for (next = kept->kept_section;
+ next != NULL;
+ next = next->kept_section)
+ kept = next;
+ }
+ }
sec->kept_section = kept;
}
return kept;
extsymoff = symtab_hdr->sh_info;
}
+ /* Enable GNU OSABI features in the output BFD that are used in the input
+ BFD. */
+ if (bed->elf_osabi == ELFOSABI_NONE
+ || bed->elf_osabi == ELFOSABI_GNU
+ || bed->elf_osabi == ELFOSABI_FREEBSD)
+ elf_tdata (output_bfd)->has_gnu_osabi
+ |= (elf_tdata (input_bfd)->has_gnu_osabi
+ & (bfd_link_relocatable (flinfo->info)
+ ? -1 : ~elf_gnu_osabi_retain));
+
/* Read the local symbols. */
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL && locsymcount != 0)
/* If this symbol is defined in a section which we are
discarding, we don't need to keep it. */
+ if (isym->st_shndx != SHN_UNDEF
+ && isym->st_shndx < SHN_LORESERVE
+ && isec->output_section == NULL
+ && flinfo->info->non_contiguous_regions
+ && flinfo->info->non_contiguous_regions_warnings)
+ {
+ _bfd_error_handler (_("warning: --enable-non-contiguous-regions "
+ "discards section `%s' from '%s'\n"),
+ isec->name, bfd_get_filename (isec->owner));
+ continue;
+ }
+
if (isym->st_shndx != SHN_UNDEF
&& isym->st_shndx < SHN_LORESERVE
&& bfd_section_removed_from_list (output_bfd,
osym.st_shndx = SHN_ABS;
if (!elf_link_output_symstrtab (flinfo,
(input_bfd->lto_output ? NULL
- : input_bfd->filename),
+ : bfd_get_filename (input_bfd)),
&osym, bfd_abs_section_ptr,
NULL))
return FALSE;
#ifdef DEBUG
printf ("Encountered a complex symbol!");
printf (" (input_bfd %s, section %s, reloc %ld\n",
- input_bfd->filename, o->name,
+ bfd_get_filename (input_bfd), o->name,
(long) (rel - internal_relocs));
printf (" symbol: idx %8.8lx, name %s\n",
r_symndx, sym_name);
struct bfd_link_order *p;
bfd *sub;
struct bfd_link_order **sections;
- asection *s, *other_sec, *linkorder_sec;
- bfd_vma offset;
+ asection *other_sec, *linkorder_sec;
+ bfd_vma offset; /* Octets. */
other_sec = NULL;
linkorder_sec = NULL;
{
if (p->type == bfd_indirect_link_order)
{
- s = p->u.indirect.section;
+ asection *s = p->u.indirect.section;
sub = s->owner;
if ((s->flags & SEC_LINKER_CREATED) == 0
&& bfd_get_flavour (sub) == bfd_target_elf_flavour
for (n = 0; n < seen_linkorder; n++)
{
bfd_vma mask;
- s = sections[n]->u.indirect.section;
- mask = ~(bfd_vma) 0 << s->alignment_power;
+ asection *s = sections[n]->u.indirect.section;
+ unsigned int opb = bfd_octets_per_byte (abfd, s);
+
+ mask = ~(bfd_vma) 0 << s->alignment_power * opb;
offset = (offset + ~mask) & mask;
- s->output_offset = offset / bfd_octets_per_byte (abfd, s);
- sections[n]->offset = offset;
+ sections[n]->offset = s->output_offset = offset / opb;
offset += sections[n]->size;
}
long symcount;
long src_count;
elf_symbol_type *osymbuf;
+ size_t amt;
implib_bfd = info->out_implib_bfd;
bed = get_elf_backend_data (abfd);
/* Make symbols absolute. */
- osymbuf = (elf_symbol_type *) bfd_alloc2 (implib_bfd, symcount,
- sizeof (*osymbuf));
+ amt = symcount * sizeof (*osymbuf);
+ osymbuf = (elf_symbol_type *) bfd_alloc (implib_bfd, amt);
if (osymbuf == NULL)
goto free_sym_buf;
ret = TRUE;
-free_sym_buf:
+ free_sym_buf:
free (sympp);
return ret;
}
if (flinfo->symstrtab != NULL)
_bfd_elf_strtab_free (flinfo->symstrtab);
- if (flinfo->contents != NULL)
- free (flinfo->contents);
- if (flinfo->external_relocs != NULL)
- free (flinfo->external_relocs);
- if (flinfo->internal_relocs != NULL)
- free (flinfo->internal_relocs);
- if (flinfo->external_syms != NULL)
- free (flinfo->external_syms);
- if (flinfo->locsym_shndx != NULL)
- free (flinfo->locsym_shndx);
- if (flinfo->internal_syms != NULL)
- free (flinfo->internal_syms);
- if (flinfo->indices != NULL)
- free (flinfo->indices);
- if (flinfo->sections != NULL)
- free (flinfo->sections);
- if (flinfo->symshndxbuf != NULL
- && flinfo->symshndxbuf != (Elf_External_Sym_Shndx *) -1)
+ free (flinfo->contents);
+ free (flinfo->external_relocs);
+ free (flinfo->internal_relocs);
+ free (flinfo->external_syms);
+ free (flinfo->locsym_shndx);
+ free (flinfo->internal_syms);
+ free (flinfo->indices);
+ free (flinfo->sections);
+ if (flinfo->symshndxbuf != (Elf_External_Sym_Shndx *) -1)
free (flinfo->symshndxbuf);
for (o = obfd->sections; o != NULL; o = o->next)
{
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);
+ free (esdo->rel.hashes);
+ free (esdo->rela.hashes);
}
}
const char *std_attrs_section;
struct elf_link_hash_table *htab = elf_hash_table (info);
bfd_boolean sections_removed;
+ bfd_boolean ret;
if (!is_elf_hash_table (htab))
return FALSE;
emit_relocs = (bfd_link_relocatable (info)
|| info->emitrelocations);
+ memset (&flinfo, 0, sizeof (flinfo));
flinfo.info = info;
flinfo.output_bfd = abfd;
flinfo.symstrtab = _bfd_elf_strtab_init ();
/* Note that it is OK if symver_sec is NULL. */
}
- flinfo.contents = NULL;
- flinfo.external_relocs = NULL;
- flinfo.internal_relocs = NULL;
- flinfo.external_syms = NULL;
- flinfo.locsym_shndx = NULL;
- flinfo.internal_syms = NULL;
- flinfo.indices = NULL;
- flinfo.sections = NULL;
- flinfo.symshndxbuf = NULL;
- flinfo.filesym_count = 0;
+ if (info->unique_symbol
+ && !bfd_hash_table_init (&flinfo.local_hash_table,
+ local_hash_newfunc,
+ sizeof (struct local_hash_entry)))
+ return FALSE;
/* The object attributes have been merged. Remove the input
sections from the link, and set the contents of the output
if (info->strip != strip_all || emit_relocs)
{
+ bfd_boolean name_local_sections;
+ const char *name;
+
file_ptr off = elf_next_file_pos (abfd);
_bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE);
/* Output a symbol for each section. We output these even if we are
discarding local symbols, since they are used for relocs. These
- symbols have no names. We store the index of each one in the
- index field of the section, so that we can find it again when
+ symbols usually have no names. We store the index of each one in
+ the index field of the section, so that we can find it again when
outputting relocs. */
+ name_local_sections
+ = (bed->elf_backend_name_local_section_symbols
+ && bed->elf_backend_name_local_section_symbols (abfd));
+
+ name = NULL;
elfsym.st_size = 0;
elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
elfsym.st_other = 0;
elfsym.st_shndx = i;
if (!bfd_link_relocatable (info))
elfsym.st_value = o->vma;
- if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, o,
+ if (name_local_sections)
+ name = o->name;
+ if (elf_link_output_symstrtab (&flinfo, name, &elfsym, o,
NULL) != 1)
goto error_return;
}
}
}
+ /* On some targets like Irix 5 the symbol split between local and global
+ ones recorded in the sh_info field needs to be done between section
+ and all other symbols. */
+ if (bed->elf_backend_elfsym_local_is_section
+ && bed->elf_backend_elfsym_local_is_section (abfd))
+ symtab_hdr->sh_info = bfd_get_symcount (abfd);
+
/* Allocate some memory to hold information read in from the input
files. */
if (max_contents_size != 0)
if (htab->tls_sec)
{
- bfd_vma base, end = 0;
+ bfd_vma base, end = 0; /* Both bytes. */
asection *sec;
for (sec = htab->tls_sec;
sec = sec->next)
{
bfd_size_type size = sec->size;
+ unsigned int opb = bfd_octets_per_byte (abfd, sec);
if (size == 0
&& (sec->flags & SEC_HAS_CONTENTS) == 0)
struct bfd_link_order *ord = sec->map_tail.link_order;
if (ord != NULL)
- size = ord->offset + ord->size;
+ size = ord->offset * opb + ord->size;
}
- end = sec->vma + size;
+ end = sec->vma + size / opb;
}
base = htab->tls_sec->vma;
/* Only align end of TLS section if static TLS doesn't have special
if (!info->reduce_memory_overheads)
{
for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
- if (bfd_get_flavour (sub) == bfd_target_elf_flavour
- && elf_tdata (sub)->symbuf)
+ if (bfd_get_flavour (sub) == bfd_target_elf_flavour)
{
free (elf_tdata (sub)->symbuf);
elf_tdata (sub)->symbuf = NULL;
}
}
+ ret = TRUE;
+
/* Output any global symbols that got converted to local in a
version script or due to symbol visibility. We do this in a
separate step since ELF requires all local symbols to appear
eoinfo.file_sym_done = FALSE;
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* If backend needs to output some local symbols not present in the hash
table, do it now. */
if (! ((*bed->elf_backend_output_arch_local_syms)
(abfd, info, &flinfo,
(out_sym_func) elf_link_output_symstrtab)))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
/* That wrote out all the local symbols. Finish up the symbol table
converted to local in a version script. */
/* The sh_info field records the index of the first non local symbol. */
- symtab_hdr->sh_info = bfd_get_symcount (abfd);
+ if (!symtab_hdr->sh_info)
+ symtab_hdr->sh_info = bfd_get_symcount (abfd);
if (dynamic
&& htab->dynsym != NULL
BFD_ASSERT (indx > 0);
sym.st_shndx = indx;
if (! check_dynsym (abfd, &sym))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
sym.st_value = s->vma;
dest = dynsym + dynindx * bed->s->sizeof_sym;
+
+ /* Inform the linker of the addition of this symbol. */
+
+ if (info->callbacks->ctf_new_dynsym)
+ info->callbacks->ctf_new_dynsym (dynindx, &sym);
+
bed->s->swap_symbol_out (abfd, &sym, dest, 0);
}
}
the original st_name with the dynstr_index. */
sym = e->isym;
sym.st_other &= ~ELF_ST_VISIBILITY (-1);
+ sym.st_shndx = SHN_UNDEF;
s = bfd_section_from_elf_index (e->input_bfd,
e->isym.st_shndx);
- if (s != NULL)
+ if (s != NULL
+ && s->output_section != NULL
+ && elf_section_data (s->output_section) != NULL)
{
sym.st_shndx =
elf_section_data (s->output_section)->this_idx;
if (! check_dynsym (abfd, &sym))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
sym.st_value = (s->output_section->vma
+ s->output_offset
+ e->isym.st_value);
}
+ /* Inform the linker of the addition of this symbol. */
+
+ if (info->callbacks->ctf_new_dynsym)
+ info->callbacks->ctf_new_dynsym (e->dynindx, &sym);
+
dest = dynsym + e->dynindx * bed->s->sizeof_sym;
bed->s->swap_symbol_out (abfd, &sym, dest, 0);
}
eoinfo.flinfo = &flinfo;
bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
if (eoinfo.failed)
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* If backend needs to output some symbols not present in the hash
table, do it now. */
if (! ((*bed->elf_backend_output_arch_syms)
(abfd, info, &flinfo,
(out_sym_func) elf_link_output_symstrtab)))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
/* Finalize the .strtab section. */
/* Swap out the .strtab section. */
if (!elf_link_swap_symbols_out (&flinfo))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* Now we know the size of the symtab section. */
if (bfd_get_symcount (abfd) > 0)
if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
|| (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
}
if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
|| ! _bfd_elf_strtab_emit (abfd, flinfo.symstrtab))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
}
if (info->out_implib_bfd && !elf_output_implib (abfd, info))
{
_bfd_error_handler (_("%pB: failed to generate import library"),
info->out_implib_bfd);
- return FALSE;
+ ret = FALSE;
+ goto return_local_hash_table;
}
/* Adjust the relocs to have the correct symbol indices. */
sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o);
if (esdo->rel.hdr != NULL
&& !elf_link_adjust_relocs (abfd, o, &esdo->rel, sort, info))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
if (esdo->rela.hdr != NULL
&& !elf_link_adjust_relocs (abfd, o, &esdo->rela, sort, info))
- return FALSE;
+ {
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
/* Set the reloc_count field to 0 to prevent write_relocs from
trying to swap the relocs out itself. */
if (bed->dtrel_excludes_plt && htab->srelplt != NULL)
{
+ unsigned int opb = bfd_octets_per_byte (abfd, o);
+
/* Don't count procedure linkage table relocs in the
overall reloc count. */
sh_size -= htab->srelplt->size;
/* If .rela.plt is the first .rela section, exclude
it from DT_RELA. */
else if (sh_addr == (htab->srelplt->output_section->vma
- + htab->srelplt->output_offset))
+ + htab->srelplt->output_offset) * opb)
sh_addr += htab->srelplt->size;
}
goto error_return;
/* Check for DT_TEXTREL (late, in case the backend removes it). */
- if (((info->warn_shared_textrel && bfd_link_pic (info))
- || info->error_textrel)
+ if (bfd_link_textrel_check (info)
&& (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
{
bfd_byte *dyncon, *dynconend;
if (dyn.d_tag == DT_TEXTREL)
{
- if (info->error_textrel)
+ if (info->textrel_check == textrel_check_error)
info->callbacks->einfo
(_("%P%X: read-only segment has dynamic relocations\n"));
+ else if (bfd_link_dll (info))
+ info->callbacks->einfo
+ (_("%P: warning: creating DT_TEXTREL in a shared object\n"));
else
info->callbacks->einfo
- (_("%P: warning: creating a DT_TEXTREL in a shared object\n"));
+ (_("%P: warning: creating DT_TEXTREL in a PIE\n"));
break;
}
}
{
bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size);
if (contents == NULL)
- return FALSE; /* Bail out and fail. */
+ {
+ /* Bail out and fail. */
+ ret = FALSE;
+ goto return_local_hash_table;
+ }
bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
free (contents);
}
- return TRUE;
+ return_local_hash_table:
+ if (info->unique_symbol)
+ bfd_hash_table_free (&flinfo.local_hash_table);
+ return ret;
error_return:
elf_final_link_free (abfd, &flinfo);
- return FALSE;
+ ret = FALSE;
+ goto return_local_hash_table;
}
\f
/* Initialize COOKIE for input bfd ABFD. */
Elf_Internal_Shdr *symtab_hdr;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- if (cookie->locsyms != NULL
- && symtab_hdr->contents != (unsigned char *) cookie->locsyms)
+ if (symtab_hdr->contents != (unsigned char *) cookie->locsyms)
free (cookie->locsyms);
}
fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
asection *sec)
{
- if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels)
+ if (elf_section_data (sec)->relocs != cookie->rels)
free (cookie->rels);
}
bfd_boolean
_bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
- elf_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED)
+ elf_gc_mark_hook_fn mark_hook)
{
bfd *ibfd;
&& (isec->flags & SEC_ALLOC) != 0
&& elf_section_type (isec) != SHT_NOTE)
some_kept = TRUE;
+ else
+ {
+ /* Since all sections, except for backend specific ones,
+ have been garbage collected, call mark_hook on this
+ section if any of its linked-to sections is marked. */
+ asection *linked_to_sec = elf_linked_to_section (isec);
+ for (; linked_to_sec != NULL;
+ linked_to_sec = elf_linked_to_section (linked_to_sec))
+ if (linked_to_sec->gc_mark)
+ {
+ if (!_bfd_elf_gc_mark (info, isec, mark_hook))
+ return FALSE;
+ break;
+ }
+ }
if (!debug_frag_seen
&& (isec->flags & SEC_DEBUGGING)
&& CONST_STRNEQ (isec->name, ".debug_line."))
debug_frag_seen = TRUE;
+ else if (strcmp (bfd_section_name (isec),
+ "__patchable_function_entries") == 0
+ && elf_linked_to_section (isec) == NULL)
+ info->callbacks->einfo (_("%F%P: %pB(%pA): error: "
+ "need linked-to section "
+ "for --gc-sections\n"),
+ isec->owner, isec);
}
/* If no non-note alloc section in this file will be kept, then
/* Keep debug and special sections like .comment when they are
not part of a group. Also keep section groups that contain
- just debug sections or special sections. */
+ just debug sections or special sections. NB: Sections with
+ linked-to section has been handled above. */
for (isec = ibfd->sections; isec != NULL; isec = isec->next)
{
if ((isec->flags & SEC_GROUP) != 0)
_bfd_elf_gc_mark_debug_special_section_group (isec);
else if (((isec->flags & SEC_DEBUGGING) != 0
|| (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
- && elf_next_in_group (isec) == NULL)
+ && elf_next_in_group (isec) == NULL
+ && elf_linked_to_section (isec) == NULL)
isec->gc_mark = 1;
if (isec->gc_mark && (isec->flags & SEC_DEBUGGING) != 0)
has_kept_debug_info = TRUE;
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && !bfd_is_abs_section (h->root.u.def.section)
- && !bfd_is_und_section (h->root.u.def.section))
+ && !bfd_is_const_section (h->root.u.def.section))
h->root.u.def.section->flags |= SEC_KEEP;
}
}
|| (elf_section_data (o)->this_hdr.sh_type
== SHT_FINI_ARRAY)))
|| (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
- && elf_next_in_group (o) == NULL )))
+ && elf_next_in_group (o) == NULL
+ && elf_linked_to_section (o) == NULL)
+ || ((elf_tdata (sub)->has_gnu_osabi & elf_gnu_osabi_retain)
+ && (elf_section_flags (o) & SHF_GNU_RETAIN))))
{
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
flagword flag_value;
} elf_flags_to_name_table;
-static elf_flags_to_name_table elf_flags_to_names [] =
+static const elf_flags_to_name_table elf_flags_to_names [] =
{
{ "SHF_WRITE", SHF_WRITE },
{ "SHF_ALLOC", SHF_ALLOC },
{
asection *i;
int eh_changed = 0;
- unsigned int eh_alignment;
+ unsigned int eh_alignment; /* Octets. */
for (i = o->map_head.s; i != NULL; i = i->map_head.s)
{
fini_reloc_cookie_for_section (&cookie, i);
}
- eh_alignment = 1 << o->alignment_power;
+ eh_alignment = ((1 << o->alignment_power)
+ * bfd_octets_per_byte (output_bfd, o));
/* Skip over zero terminator, and prevent empty sections from
adding alignment padding at the end. */
for (i = o->map_tail.s; i != NULL; i = i->map_tail.s)
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)
+ || (l->sec->owner->flags & BFD_PLUGIN) != 0
+ || (sec->owner->flags & BFD_PLUGIN) != 0)
{
/* The section has already been linked. See if we should
issue a warning. */
ehdest->target_internal = ehsrc->target_internal;
isym.st_other = ehsrc->other;
- elf_merge_st_other (abfd, ehdest, &isym, NULL, TRUE, FALSE);
+ elf_merge_st_other (abfd, ehdest, isym.st_other, NULL, TRUE, FALSE);
}
/* Append a RELA relocation REL to section S in BFD. */
h = elf_link_hash_lookup (elf_hash_table (info), symbol,
FALSE, FALSE, TRUE);
+ /* NB: Common symbols will be turned into definition later. */
if (h != NULL
&& (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak
- || ((h->ref_regular || h->def_dynamic) && !h->def_regular)))
+ || ((h->ref_regular || h->def_dynamic)
+ && !h->def_regular
+ && h->root.type != bfd_link_hash_common)))
{
bfd_boolean was_dynamic = h->ref_dynamic || h->def_dynamic;
+ h->verinfo.verdef = NULL;
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = sec;
h->root.u.def.value = 0;
else
{
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_PROTECTED;
+ h->other = ((h->other & ~ELF_ST_VISIBILITY (-1))
+ | info->start_stop_visibility);
if (was_dynamic)
bfd_elf_link_record_dynamic_symbol (info, h);
}
}
return NULL;
}
+
+/* Find dynamic relocs for H that apply to read-only sections. */
+
+asection *
+_bfd_elf_readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+ struct elf_dyn_relocs *p;
+
+ for (p = h->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *s = p->sec->output_section;
+
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ return p->sec;
+ }
+ return NULL;
+}
+
+/* Set DF_TEXTREL if we find any dynamic relocs that apply to
+ read-only sections. */
+
+bfd_boolean
+_bfd_elf_maybe_set_textrel (struct elf_link_hash_entry *h, void *inf)
+{
+ asection *sec;
+
+ if (h->root.type == bfd_link_hash_indirect)
+ return TRUE;
+
+ sec = _bfd_elf_readonly_dynrelocs (h);
+ if (sec != NULL)
+ {
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+ info->flags |= DF_TEXTREL;
+ /* xgettext:c-format */
+ info->callbacks->minfo (_("%pB: dynamic relocation against `%pT' "
+ "in read-only section `%pA'\n"),
+ sec->owner, h->root.root.string, sec);
+
+ if (bfd_link_textrel_check (info))
+ /* xgettext:c-format */
+ info->callbacks->einfo (_("%P: %pB: warning: relocation against `%s' "
+ "in read-only section `%pA'\n"),
+ sec->owner, h->root.root.string, sec);
+
+ /* Not an error, just cut short the traversal. */
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Add dynamic tags. */
+
+bfd_boolean
+_bfd_elf_add_dynamic_tags (bfd *output_bfd, struct bfd_link_info *info,
+ bfd_boolean need_dynamic_reloc)
+{
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ if (htab->dynamic_sections_created)
+ {
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in finish_dynamic_sections, but we must add
+ the entries now so that we get the correct size for the
+ .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
+#define add_dynamic_entry(TAG, VAL) \
+ _bfd_elf_add_dynamic_entry (info, TAG, VAL)
+
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (output_bfd);
+
+ if (bfd_link_executable (info))
+ {
+ if (!add_dynamic_entry (DT_DEBUG, 0))
+ return FALSE;
+ }
+
+ if (htab->dt_pltgot_required || htab->splt->size != 0)
+ {
+ /* DT_PLTGOT is used by prelink even if there is no PLT
+ relocation. */
+ if (!add_dynamic_entry (DT_PLTGOT, 0))
+ return FALSE;
+ }
+
+ if (htab->dt_jmprel_required || htab->srelplt->size != 0)
+ {
+ if (!add_dynamic_entry (DT_PLTRELSZ, 0)
+ || !add_dynamic_entry (DT_PLTREL,
+ (bed->rela_plts_and_copies_p
+ ? DT_RELA : DT_REL))
+ || !add_dynamic_entry (DT_JMPREL, 0))
+ return FALSE;
+ }
+
+ if (htab->tlsdesc_plt
+ && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
+ || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
+ return FALSE;
+
+ if (need_dynamic_reloc)
+ {
+ if (bed->rela_plts_and_copies_p)
+ {
+ if (!add_dynamic_entry (DT_RELA, 0)
+ || !add_dynamic_entry (DT_RELASZ, 0)
+ || !add_dynamic_entry (DT_RELAENT,
+ bed->s->sizeof_rela))
+ return FALSE;
+ }
+ else
+ {
+ if (!add_dynamic_entry (DT_REL, 0)
+ || !add_dynamic_entry (DT_RELSZ, 0)
+ || !add_dynamic_entry (DT_RELENT,
+ bed->s->sizeof_rel))
+ return FALSE;
+ }
+
+ /* If any dynamic relocs apply to a read-only section,
+ then we need a DT_TEXTREL entry. */
+ if ((info->flags & DF_TEXTREL) == 0)
+ elf_link_hash_traverse (htab, _bfd_elf_maybe_set_textrel,
+ info);
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (htab->ifunc_resolvers)
+ info->callbacks->einfo
+ (_("%P: warning: GNU indirect functions with DT_TEXTREL "
+ "may result in a segfault at runtime; recompile with %s\n"),
+ bfd_link_dll (info) ? "-fPIC" : "-fPIE");
+
+ if (!add_dynamic_entry (DT_TEXTREL, 0))
+ return FALSE;
+ }
+ }
+ }
+#undef add_dynamic_entry
+
+ return TRUE;
+}