bfd_boolean newweak, oldweak, newfunc, oldfunc;
const struct elf_backend_data *bed;
char *new_version;
+ bfd_boolean default_sym = *matched;
*skip = FALSE;
*override = FALSE;
if (pold_weak)
*pold_weak = oldweak;
- /* This code is for coping with dynamic objects, and is only useful
- if we are doing an ELF link. */
- if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
- return TRUE;
-
/* We have to check it for every instance since the first few may be
references and not all compilers emit symbol type for undefined
symbols. */
olddyn = (oldsec->symbol->flags & BSF_DYNAMIC) != 0;
}
+ /* Handle a case where plugin_notice won't be called and thus won't
+ set the non_ir_ref flags on the first pass over symbols. */
+ if (oldbfd != NULL
+ && (oldbfd->flags & BFD_PLUGIN) != (abfd->flags & BFD_PLUGIN)
+ && newdyn != olddyn)
+ {
+ h->root.non_ir_ref_dynamic = TRUE;
+ hi->root.non_ir_ref_dynamic = TRUE;
+ }
+
/* NEWDEF and OLDDEF indicate whether the new or old symbol,
respectively, appear to be a definition rather than reference. */
sec = *psec;
}
+ /* There are multiple definitions of a normal symbol.
+ Skip the default symbol as well. */
+ if (olddef && !olddyn && !oldweak && newdef && !newdyn && !newweak
+ && !default_sym && h->def_regular)
+ {
+ /* Handle a multiple definition. */
+ (*info->callbacks->multiple_definition) (info, &h->root,
+ abfd, sec, *pvalue);
+ *skip = TRUE;
+ return TRUE;
+ }
+
/* If both the old and the new symbols look like common symbols in a
dynamic object, set the size of the symbol to the larger of the
two. */
_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
{
struct elf_info_failed *eif = (struct elf_info_failed *) data;
- bfd *dynobj;
+ struct elf_link_hash_table *htab;
const struct elf_backend_data *bed;
if (! is_elf_hash_table (eif->info->hash))
if (! _bfd_elf_fix_symbol_flags (h, eif))
return FALSE;
+ htab = elf_hash_table (eif->info);
+ bed = get_elf_backend_data (htab->dynobj);
+
if (h->root.type == bfd_link_hash_undefweak)
{
if (eif->info->dynamic_undefined_weak == 0)
- _bfd_elf_link_hash_hide_symbol (eif->info, h, TRUE);
+ (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE);
else if (eif->info->dynamic_undefined_weak > 0
&& h->ref_regular
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
(_("warning: type and size of dynamic symbol `%s' are not defined"),
h->root.root.string);
- dynobj = elf_hash_table (eif->info)->dynobj;
- bed = get_elf_backend_data (dynobj);
-
if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h))
{
eif->failed = TRUE;
sec = NULL;
value = isym->st_value;
common = bed->common_definition (isym);
+ if (common && info->inhibit_common_definition)
+ {
+ /* Treat common symbol as undefined for --no-define-common. */
+ isym->st_shndx = SHN_UNDEF;
+ common = FALSE;
+ }
discarded = FALSE;
bind = ELF_ST_BIND (isym->st_info);
&& !(*bed->check_directives) (abfd, info))
return FALSE;
- if (!info->check_relocs_after_open_input
- && !_bfd_elf_link_check_relocs (abfd, info))
- return FALSE;
-
/* If this is a non-traditional link, try to optimize the handling
of the .stab/.stabstr sections. */
if (! dynamic
struct elf_info_failed asvinfo;
struct bfd_elf_version_tree *t;
struct bfd_elf_version_expr *d;
- struct elf_info_failed eif;
- bfd_boolean all_defined;
asection *s;
size_t soname_indx;
- eif.info = info;
- eif.failed = FALSE;
-
/* If we are supposed to export all symbols into the dynamic symbol
table (this is not the normal case), then do so. */
if (info->export_dynamic
|| (bfd_link_executable (info) && info->dynamic))
{
+ struct elf_info_failed eif;
+
+ eif.info = info;
+ eif.failed = FALSE;
elf_link_hash_traverse (elf_hash_table (info),
_bfd_elf_export_symbol,
&eif);
if (!info->allow_undefined_version)
{
/* Check if all global versions have a definition. */
- all_defined = TRUE;
+ bfd_boolean all_defined = TRUE;
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)
elf_tdata (output_bfd)->cverdefs = cdefs;
}
+ }
+
+ bed = get_elf_backend_data (output_bfd);
+
+ if (info->gc_sections && bed->can_gc_sections)
+ {
+ struct elf_gc_sweep_symbol_info sweep_info;
+
+ /* Remove the symbols that were in the swept sections from the
+ dynamic symbol table. */
+ sweep_info.info = info;
+ sweep_info.hide_symbol = bed->elf_backend_hide_symbol;
+ elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol,
+ &sweep_info);
+ }
+
+ if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
+ {
+ asection *s;
+ struct elf_find_verdep_info sinfo;
/* Work out the size of the version reference section. */
s = bfd_get_linker_section (dynobj, ".gnu.version_r");
BFD_ASSERT (s != NULL);
- {
- struct elf_find_verdep_info sinfo;
-
- sinfo.info = info;
- sinfo.vers = elf_tdata (output_bfd)->cverdefs;
- if (sinfo.vers == 0)
- sinfo.vers = 1;
- sinfo.failed = FALSE;
- elf_link_hash_traverse (elf_hash_table (info),
- _bfd_elf_link_find_version_dependencies,
- &sinfo);
- if (sinfo.failed)
- return FALSE;
+ sinfo.info = info;
+ sinfo.vers = elf_tdata (output_bfd)->cverdefs;
+ if (sinfo.vers == 0)
+ sinfo.vers = 1;
+ sinfo.failed = FALSE;
- if (elf_tdata (output_bfd)->verref == NULL)
- s->flags |= SEC_EXCLUDE;
- else
- {
- Elf_Internal_Verneed *vn;
- unsigned int size;
- unsigned int crefs;
- bfd_byte *p;
-
- /* Build the version dependency section. */
- size = 0;
- crefs = 0;
- for (vn = elf_tdata (output_bfd)->verref;
- vn != NULL;
- vn = vn->vn_nextref)
- {
- Elf_Internal_Vernaux *a;
+ elf_link_hash_traverse (elf_hash_table (info),
+ _bfd_elf_link_find_version_dependencies,
+ &sinfo);
+ if (sinfo.failed)
+ return FALSE;
- size += sizeof (Elf_External_Verneed);
- ++crefs;
- for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
- size += sizeof (Elf_External_Vernaux);
- }
+ if (elf_tdata (output_bfd)->verref == NULL)
+ s->flags |= SEC_EXCLUDE;
+ else
+ {
+ Elf_Internal_Verneed *vn;
+ unsigned int size;
+ unsigned int crefs;
+ bfd_byte *p;
- s->size = size;
- s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
- if (s->contents == NULL)
- return FALSE;
+ /* Build the version dependency section. */
+ size = 0;
+ crefs = 0;
+ for (vn = elf_tdata (output_bfd)->verref;
+ vn != NULL;
+ vn = vn->vn_nextref)
+ {
+ Elf_Internal_Vernaux *a;
- p = s->contents;
- for (vn = elf_tdata (output_bfd)->verref;
- vn != NULL;
- vn = vn->vn_nextref)
- {
- unsigned int caux;
- Elf_Internal_Vernaux *a;
- size_t indx;
-
- caux = 0;
- for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
- ++caux;
-
- vn->vn_version = VER_NEED_CURRENT;
- vn->vn_cnt = caux;
- 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),
- FALSE);
- if (indx == (size_t) -1)
- return FALSE;
- vn->vn_file = indx;
- vn->vn_aux = sizeof (Elf_External_Verneed);
- if (vn->vn_nextref == NULL)
- vn->vn_next = 0;
- else
- vn->vn_next = (sizeof (Elf_External_Verneed)
- + caux * sizeof (Elf_External_Vernaux));
+ size += sizeof (Elf_External_Verneed);
+ ++crefs;
+ for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ size += sizeof (Elf_External_Vernaux);
+ }
- _bfd_elf_swap_verneed_out (output_bfd, vn,
- (Elf_External_Verneed *) p);
- p += sizeof (Elf_External_Verneed);
+ s->size = size;
+ s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size);
+ if (s->contents == NULL)
+ return FALSE;
- for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
- {
- a->vna_hash = bfd_elf_hash (a->vna_nodename);
- indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
- a->vna_nodename, FALSE);
- if (indx == (size_t) -1)
- return FALSE;
- a->vna_name = indx;
- if (a->vna_nextptr == NULL)
- a->vna_next = 0;
- else
- a->vna_next = sizeof (Elf_External_Vernaux);
+ p = s->contents;
+ for (vn = elf_tdata (output_bfd)->verref;
+ vn != NULL;
+ vn = vn->vn_nextref)
+ {
+ unsigned int caux;
+ Elf_Internal_Vernaux *a;
+ size_t indx;
- _bfd_elf_swap_vernaux_out (output_bfd, a,
- (Elf_External_Vernaux *) p);
- p += sizeof (Elf_External_Vernaux);
- }
- }
+ caux = 0;
+ for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ ++caux;
- elf_tdata (output_bfd)->cverrefs = crefs;
- }
- }
- }
+ vn->vn_version = VER_NEED_CURRENT;
+ vn->vn_cnt = caux;
+ 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),
+ FALSE);
+ if (indx == (size_t) -1)
+ return FALSE;
+ vn->vn_file = indx;
+ vn->vn_aux = sizeof (Elf_External_Verneed);
+ if (vn->vn_nextref == NULL)
+ vn->vn_next = 0;
+ else
+ vn->vn_next = (sizeof (Elf_External_Verneed)
+ + caux * sizeof (Elf_External_Vernaux));
- bed = get_elf_backend_data (output_bfd);
+ _bfd_elf_swap_verneed_out (output_bfd, vn,
+ (Elf_External_Verneed *) p);
+ p += sizeof (Elf_External_Verneed);
- if (info->gc_sections && bed->can_gc_sections)
- {
- struct elf_gc_sweep_symbol_info sweep_info;
- unsigned long section_sym_count;
+ for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ {
+ a->vna_hash = bfd_elf_hash (a->vna_nodename);
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+ a->vna_nodename, FALSE);
+ if (indx == (size_t) -1)
+ return FALSE;
+ a->vna_name = indx;
+ if (a->vna_nextptr == NULL)
+ a->vna_next = 0;
+ else
+ a->vna_next = sizeof (Elf_External_Vernaux);
- /* Remove the symbols that were in the swept sections from the
- dynamic symbol table. GCFIXME: Anyone know how to get them
- out of the static symbol table as well? */
- sweep_info.info = info;
- sweep_info.hide_symbol = bed->elf_backend_hide_symbol;
- elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol,
- &sweep_info);
+ _bfd_elf_swap_vernaux_out (output_bfd, a,
+ (Elf_External_Vernaux *) p);
+ p += sizeof (Elf_External_Vernaux);
+ }
+ }
- /* We need to reassign dynsym indices now that symbols may have
- been removed. See the call in `bfd_elf_size_dynsym_hash_dynstr'
- for the details of the conditions used here. */
- if (elf_hash_table (info)->dynamic_sections_created
- || bed->always_renumber_dynsyms)
- _bfd_elf_link_renumber_dynsyms (output_bfd, info, §ion_sym_count);
+ elf_tdata (output_bfd)->cverrefs = crefs;
+ }
}
/* Any syms created from now on start with -1 in
if ((elf_tdata (output_bfd)->cverrefs == 0
&& elf_tdata (output_bfd)->cverdefs == 0)
|| _bfd_elf_link_renumber_dynsyms (output_bfd, info,
- §ion_sym_count) == 0)
+ §ion_sym_count) <= 1)
{
asection *s;
{
const struct elf_backend_data *bed;
unsigned long section_sym_count;
- bfd_size_type dynsymcount;
+ bfd_size_type dynsymcount = 0;
if (!is_elf_hash_table (info->hash))
return TRUE;
relocatable output or when needed for --emit-relocs. */
else if (input_sec == bfd_und_section_ptr
&& h->indx != -2
+ /* PR 22319 Do not strip global undefined symbols marked as being needed. */
+ && (h->mark != 1 || ELF_ST_BIND (sym.st_info) != STB_GLOBAL)
&& !bfd_link_relocatable (flinfo->info))
return TRUE;
+
/* Also strip others that we couldn't earlier due to dynamic symbol
processing. */
if (strip)
(_("error: %B: size of section %A is not "
"multiple of address size"),
input_bfd, o);
- bfd_set_error (bfd_error_on_input);
+ bfd_set_error (bfd_error_bad_value);
return FALSE;
}
o->flags |= SEC_ELF_REVERSE_COPY;
get_vma:
o = bfd_get_linker_section (dynobj, name);
do_vma:
- if (o == NULL)
+ if (o == NULL || bfd_is_abs_section (o->output_section))
{
_bfd_error_handler
(_("could not find section %s"), name);
return TRUE;
}
-/* The sweep phase of garbage collection. Remove all garbage sections. */
-
-typedef bfd_boolean (*gc_sweep_hook_fn)
- (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
-
static bfd_boolean
elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
{
bfd *sub;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- gc_sweep_hook_fn gc_sweep_hook = bed->gc_sweep_hook;
for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *o;
if (bfd_get_flavour (sub) != bfd_target_elf_flavour
+ || elf_object_id (sub) != elf_hash_table_id (elf_hash_table (info))
|| !(*bed->relocs_compatible) (sub->xvec, abfd->xvec))
continue;
o = sub->sections;
/* xgettext:c-format */
_bfd_error_handler (_("Removing unused section '%A' in file '%B'"),
o, sub);
-
- /* But we also have to update some of the relocation
- info we collected before. */
- if (gc_sweep_hook
- && (o->flags & SEC_RELOC) != 0
- && o->reloc_count != 0
- && !((info->strip == strip_all || info->strip == strip_debugger)
- && (o->flags & SEC_DEBUGGING) != 0)
- && !bfd_is_abs_section (o->output_section))
- {
- Elf_Internal_Rela *internal_relocs;
- bfd_boolean r;
-
- internal_relocs
- = _bfd_elf_link_read_relocs (o->owner, o, NULL, NULL,
- info->keep_memory);
- if (internal_relocs == NULL)
- return FALSE;
-
- r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs);
-
- if (elf_section_data (o)->relocs != internal_relocs)
- free (internal_relocs);
-
- if (!r)
- return FALSE;
- }
}
}
asection *o;
if (bfd_get_flavour (sub) != bfd_target_elf_flavour
+ || elf_object_id (sub) != elf_hash_table_id (htab)
|| !(*bed->relocs_compatible) (sub->xvec, abfd->xvec))
continue;
{
asection *i;
int eh_changed = 0;
+ unsigned int eh_alignment;
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;
+ /* 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 (i->size == 0)
+ i->flags |= SEC_EXCLUDE;
+ else if (i->size > 4)
+ break;
+ /* The last non-empty eh_frame section doesn't need padding. */
+ if (i != NULL)
+ i = i->map_tail.s;
+ /* Any prior sections must pad the last FDE out to the output
+ section alignment. Otherwise we might have zero padding
+ between sections, which would be seen as a terminator. */
+ for (; i != NULL; i = i->map_tail.s)
+ if (i->size == 4)
+ /* All but the last zero terminator should have been removed. */
+ BFD_FAIL ();
+ else
+ {
+ bfd_size_type size
+ = (i->size + eh_alignment - 1) & -eh_alignment;
+ if (i->size != size)
+ {
+ i->size = size;
+ changed = 1;
+ eh_changed = 1;
+ }
+ }
if (eh_changed)
elf_link_hash_traverse (elf_hash_table (info),
_bfd_elf_adjust_eh_frame_global_symbol, NULL);
bfd_elf_define_start_stop (struct bfd_link_info *info,
const char *symbol, asection *sec)
{
- struct bfd_link_hash_entry *h;
+ struct elf_link_hash_entry *h;
- h = bfd_generic_define_start_stop (info, symbol, sec);
- if (h != NULL)
+ h = elf_link_hash_lookup (elf_hash_table (info), symbol,
+ FALSE, FALSE, TRUE);
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak
+ || (h->ref_regular && !h->def_regular)))
{
- struct elf_link_hash_entry *eh = (struct elf_link_hash_entry *) h;
- eh->start_stop = 1;
- eh->u2.start_stop_section = sec;
- _bfd_elf_link_hash_hide_symbol (info, eh, TRUE);
- if (ELF_ST_VISIBILITY (eh->other) != STV_INTERNAL)
- eh->other = ((eh->other & ~ELF_ST_VISIBILITY (-1))
- | STV_HIDDEN);
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = sec;
+ h->root.u.def.value = 0;
+ h->def_regular = 1;
+ h->def_dynamic = 0;
+ h->start_stop = 1;
+ h->u2.start_stop_section = sec;
+ if (symbol[0] == '.')
+ {
+ /* .startof. and .sizeof. symbols are local. */
+ const struct elf_backend_data *bed;
+ bed = get_elf_backend_data (info->output_bfd);
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ }
+ else if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+ h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_PROTECTED;
+ return &h->root;
}
- return h;
+ return NULL;
}