/* ELF linking support for BFD.
- Copyright (C) 1995-2019 Free Software Foundation, Inc.
+ Copyright (C) 1995-2020 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
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;
if (skip)
goto nondefault;
- if (hi->def_regular)
+ if (hi->def_regular || ELF_COMMON_DEF_P (hi))
{
/* If the undecorated symbol will have a version added by a
script different to H, then don't indirect to/from the
/* 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)
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. */
/* We only need version numbers for symbols defined in regular
objects. */
- if (!h->def_regular)
+ if (!h->def_regular && !ELF_COMMON_DEF_P (h))
{
/* Hide symbols defined in discarded input sections. */
if ((h->root.type == bfd_link_hash_defined
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,
+/* 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;
}
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)
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);
}
}
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++)
{
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)
&& !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);
}
}
}
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 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;
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;
_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)
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;
result = TRUE;
-done:
+ done:
if (symtable1)
free (symtable1);
if (symtable2)
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;
}
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;
}
Elf_Internal_Versym iversym;
Elf_External_Versym *eversym;
- if (!h->def_regular)
+ if (!h->def_regular && !ELF_COMMON_DEF_P (h))
{
if (h->verinfo.verdef == NULL
|| (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd)
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;
}
bfd_vma attr_size = 0;
const char *std_attrs_section;
struct elf_link_hash_table *htab = elf_hash_table (info);
+ bfd_boolean sections_removed;
if (!is_elf_hash_table (htab))
return FALSE;
/* The object attributes have been merged. Remove the input
sections from the link, and set the contents of the output
section. */
+ sections_removed = FALSE;
std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section;
for (o = abfd->sections; o != NULL; o = o->next)
{
o->flags |= SEC_EXCLUDE;
bfd_section_list_remove (abfd, o);
abfd->section_count--;
+ sections_removed = TRUE;
}
}
+ if (sections_removed)
+ _bfd_fix_excluded_sec_syms (abfd, info);
/* Count up the number of relocations we will output for each output
section, so that we know the sizes of the reloc sections. We
bfd_boolean *start_stop)
{
unsigned long r_symndx;
- struct elf_link_hash_entry *h;
+ struct elf_link_hash_entry *h, *hw;
r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
if (r_symndx == STN_UNDEF)
|| 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->is_weakalias)
- weakdef (h)->mark = 1;
+ /* Keep all aliases of the symbol too. If an object symbol
+ needs to be copied into .dynbss then all of its aliases
+ should be present as dynamic symbols, not just the one used
+ on the copy relocation. */
+ hw = h;
+ while (hw->is_weakalias)
+ {
+ hw = hw->u.alias;
+ hw->mark = 1;
+ }
if (start_stop != NULL)
{
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;