/* ELF linking support for BFD.
- Copyright (C) 1995-2021 Free Software Foundation, Inc.
+ Copyright (C) 1995-2023 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
elf_section_data (s)->this_hdr.sh_entsize = 4;
}
+ if (info->enable_dt_relr)
+ {
+ s = bfd_make_section_anyway_with_flags (abfd, ".relr.dyn",
+ (bed->dynamic_sec_flags
+ | SEC_READONLY));
+ if (s == NULL
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
+ return false;
+ elf_hash_table (info)->srelrdyn = s;
+ }
+
/* Let the backend create the rest of the sections. This lets the
backend set the right flags. The backend will normally create
the .got and .plt sections. */
const struct elf_backend_data *bed;
char *new_version;
bool default_sym = *matched;
+ struct elf_link_hash_table *htab;
*skip = false;
*override = NULL;
symbols. */
bfd_elf_link_mark_dynamic_symbol (info, h, sym);
+ htab = elf_hash_table (info);
+
/* NEWDYN and OLDDYN indicate whether the new or old symbol,
respectively, is from a dynamic object. */
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)
+ /* Set non_ir_ref_dynamic only when not handling DT_NEEDED entries. */
+ if (!htab->handling_dt_needed
+ && oldbfd != NULL
+ && (oldbfd->flags & BFD_PLUGIN) != (abfd->flags & BFD_PLUGIN))
{
- h->root.non_ir_ref_dynamic = true;
- hi->root.non_ir_ref_dynamic = true;
+ if (newdyn != olddyn)
+ {
+ /* 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. */
+ h->root.non_ir_ref_dynamic = true;
+ hi->root.non_ir_ref_dynamic = true;
+ }
+ else if ((oldbfd->flags & BFD_PLUGIN) != 0
+ && hi->root.type == bfd_link_hash_indirect)
+ {
+ /* Change indirect symbol from IR to undefined. */
+ hi->root.type = bfd_link_hash_undefined;
+ hi->root.u.undef.abfd = oldbfd;
+ }
}
/* NEWDEF and OLDDEF indicate whether the new or old symbol,
return true;
}
\f
+/* Return true if GLIBC_ABI_DT_RELR is added to the list of version
+ dependencies successfully. GLIBC_ABI_DT_RELR will be put into the
+ .gnu.version_r section. */
+
+static bool
+elf_link_add_dt_relr_dependency (struct elf_find_verdep_info *rinfo)
+{
+ bfd *glibc_bfd = NULL;
+ Elf_Internal_Verneed *t;
+ Elf_Internal_Vernaux *a;
+ size_t amt;
+ const char *relr = "GLIBC_ABI_DT_RELR";
+
+ /* See if we already know about GLIBC_PRIVATE_DT_RELR. */
+ for (t = elf_tdata (rinfo->info->output_bfd)->verref;
+ t != NULL;
+ t = t->vn_nextref)
+ {
+ const char *soname = bfd_elf_get_dt_soname (t->vn_bfd);
+ /* Skip the shared library if it isn't libc.so. */
+ if (!soname || !startswith (soname, "libc.so."))
+ continue;
+
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ {
+ /* Return if GLIBC_PRIVATE_DT_RELR dependency has been
+ added. */
+ if (a->vna_nodename == relr
+ || strcmp (a->vna_nodename, relr) == 0)
+ return true;
+
+ /* Check if libc.so provides GLIBC_2.XX version. */
+ if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))
+ glibc_bfd = t->vn_bfd;
+ }
+
+ break;
+ }
+
+ /* Skip if it isn't linked against glibc. */
+ if (glibc_bfd == NULL)
+ return true;
+
+ /* This is a new version. Add it to tree we are building. */
+ if (t == NULL)
+ {
+ amt = sizeof *t;
+ t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->info->output_bfd,
+ amt);
+ if (t == NULL)
+ {
+ rinfo->failed = true;
+ return false;
+ }
+
+ t->vn_bfd = glibc_bfd;
+ t->vn_nextref = elf_tdata (rinfo->info->output_bfd)->verref;
+ elf_tdata (rinfo->info->output_bfd)->verref = t;
+ }
+
+ amt = sizeof *a;
+ a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->info->output_bfd, amt);
+ if (a == NULL)
+ {
+ rinfo->failed = true;
+ return false;
+ }
+
+ a->vna_nodename = relr;
+ a->vna_flags = 0;
+ a->vna_nextptr = t->vn_auxptr;
+ a->vna_other = rinfo->vers + 1;
+ ++rinfo->vers;
+
+ t->vn_auxptr = a;
+
+ return true;
+}
+
/* Look through the symbols which are defined in other shared
libraries and referenced here. Update the list of version
dependencies. This will be put into the .gnu.version_r section.
return false;
/* Read the relocations. */
- if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
+ if (bfd_read (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
return false;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
according to the KEEP_MEMORY argument. If O has two relocation
sections (both REL and RELA relocations), then the REL_HDR
relocations will appear first in INTERNAL_RELOCS, followed by the
- RELA_HDR relocations. */
+ RELA_HDR relocations. If INFO isn't NULL and KEEP_MEMORY is true,
+ update cache_size. */
Elf_Internal_Rela *
-_bfd_elf_link_read_relocs (bfd *abfd,
- asection *o,
- void *external_relocs,
- Elf_Internal_Rela *internal_relocs,
- bool keep_memory)
+_bfd_elf_link_info_read_relocs (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *o,
+ void *external_relocs,
+ Elf_Internal_Rela *internal_relocs,
+ bool keep_memory)
{
void *alloc1 = NULL;
Elf_Internal_Rela *alloc2 = NULL;
size = (bfd_size_type) o->reloc_count * sizeof (Elf_Internal_Rela);
if (keep_memory)
- internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
+ {
+ internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
+ if (info)
+ info->cache_size += size;
+ }
else
internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size);
if (internal_relocs == NULL)
return NULL;
}
+/* This is similar to _bfd_elf_link_info_read_relocs, except for that
+ NULL is passed to _bfd_elf_link_info_read_relocs for pointer to
+ struct bfd_link_info. */
+
+Elf_Internal_Rela *
+_bfd_elf_link_read_relocs (bfd *abfd,
+ asection *o,
+ void *external_relocs,
+ Elf_Internal_Rela *internal_relocs,
+ bool keep_memory)
+{
+ return _bfd_elf_link_info_read_relocs (abfd, NULL, o, external_relocs,
+ internal_relocs, keep_memory);
+
+}
+
/* Compute the size of, and allocate space for, REL_HDR which is the
section header for a section containing relocations for O. */
case STV_PROTECTED:
hash_table = elf_hash_table (info);
- if (!is_elf_hash_table (hash_table))
+ if (!is_elf_hash_table (&hash_table->root))
return false;
bed = get_elf_backend_data (hash_table->dynobj);
return false;
hash_table = elf_hash_table (info);
- if (!is_elf_hash_table (hash_table))
+ if (!is_elf_hash_table (&hash_table->root))
+ return true;
+
+ /* STV_PROTECTED symbols with indirect external access are local. */
+ if (info->indirect_extern_access > 0)
return true;
bed = get_elf_backend_data (hash_table->dynobj);
Elf_Internal_Sym *isymend;
bool result;
- abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+ abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset, NULL);
if (abfd == NULL)
return false;
abfd = abfd->plugin_dummy_bfd;
hdr = &elf_tdata (abfd)->symtab_hdr;
}
- else if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
- hdr = &elf_tdata (abfd)->symtab_hdr;
else
- hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ {
+ if (elf_use_dt_symtab_p (abfd))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
+ if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ else
+ hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ }
symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
Elf_Internal_Dyn dyn;
hash_table = elf_hash_table (info);
- if (! is_elf_hash_table (hash_table))
+ if (! is_elf_hash_table (&hash_table->root))
return false;
if (tag == DT_RELA || tag == DT_REL)
return true;
hash_table = elf_hash_table (info);
- if (!is_elf_hash_table (hash_table))
+ if (!is_elf_hash_table (&hash_table->root))
return false;
if (!hash_table->dynobj)
else
pp = &s->next;
- if (strip_zero_sized_plt)
+ if (strip_zero_sized_plt && sdynamic->size != 0)
for (extdyn = sdynamic->contents;
extdyn < sdynamic->contents + sdynamic->size;
extdyn = next)
{
/* Regenerate program headers. */
elf_seg_map (info->output_bfd) = NULL;
- return _bfd_elf_map_sections_to_segments (info->output_bfd, info);
+ return _bfd_elf_map_sections_to_segments (info->output_bfd, info,
+ NULL);
}
return true;
bed = get_elf_backend_data (hash_table->dynobj);
sdyn = bfd_get_linker_section (hash_table->dynobj, ".dynamic");
- if (sdyn != NULL)
+ if (sdyn != NULL && sdyn->size != 0)
for (extdyn = sdyn->contents;
extdyn < sdyn->contents + sdyn->size;
extdyn += bed->s->sizeof_dyn)
/* Update all .dynamic entries referencing .dynstr strings. */
for (extdyn = sdyn->contents;
- extdyn < sdyn->contents + sdyn->size;
+ extdyn < PTR_ADD (sdyn->contents, sdyn->size);
extdyn += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
}
-/* Check relocations an ELF object file. */
+/* Call ACTION on each relocation in an ELF object file. */
bool
-_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+_bfd_elf_link_iterate_on_relocs
+ (bfd *abfd, struct bfd_link_info *info,
+ bool (*action) (bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *))
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_link_hash_table *htab = elf_hash_table (info);
I have no idea how to handle linking PIC code into a file of a
different format. It probably can't be done. */
if ((abfd->flags & DYNAMIC) == 0
- && is_elf_hash_table (htab)
- && bed->check_relocs != NULL
+ && is_elf_hash_table (&htab->root)
&& elf_object_id (abfd) == elf_hash_table_id (htab)
&& (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
{
|| bfd_is_abs_section (o->output_section))
continue;
- internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
- info->keep_memory);
+ internal_relocs = _bfd_elf_link_info_read_relocs (abfd, info,
+ o, NULL,
+ NULL,
+ _bfd_link_keep_memory (info));
if (internal_relocs == NULL)
return false;
- ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
+ ok = action (abfd, info, o, internal_relocs);
if (elf_section_data (o)->relocs != internal_relocs)
free (internal_relocs);
return true;
}
+/* Check relocations in an ELF object file. This is called after
+ all input files have been opened. */
+
+bool
+_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ if (bed->check_relocs != NULL)
+ return _bfd_elf_link_iterate_on_relocs (abfd, info,
+ bed->check_relocs);
+ return true;
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static bool
htab = elf_hash_table (info);
bed = get_elf_backend_data (abfd);
+ if (elf_use_dt_symtab_p (abfd))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return false;
+ }
+
if ((abfd->flags & DYNAMIC) == 0)
dynamic = false;
else
hope of using a dynamic object which does not exactly match
the format of the output file. */
if (bfd_link_relocatable (info)
- || !is_elf_hash_table (htab)
+ || !is_elf_hash_table (&htab->root)
|| info->output_bfd->xvec != abfd->xvec)
{
if (bfd_link_relocatable (info))
|| (!bfd_link_relocatable (info)
&& info->nointerp
&& (info->export_dynamic || info->dynamic)))
- && is_elf_hash_table (htab)
+ && is_elf_hash_table (&htab->root)
&& info->output_bfd->xvec == abfd->xvec
&& !htab->dynamic_sections_created)
{
goto error_return;
}
}
- else if (!is_elf_hash_table (htab))
+ else if (!is_elf_hash_table (&htab->root))
goto error_return;
else
{
| DYN_NO_NEEDED)) == 0;
s = bfd_get_section_by_name (abfd, ".dynamic");
- if (s != NULL)
+ if (s != NULL && s->size != 0 && (s->flags & SEC_HAS_CONTENTS) != 0)
{
bfd_byte *dynbuf;
bfd_byte *extdyn;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
for (extdyn = dynbuf;
- extdyn <= dynbuf + s->size - bed->s->sizeof_dyn;
+ (size_t) (dynbuf + s->size - extdyn) >= bed->s->sizeof_dyn;
extdyn += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
unsigned int tagv = dyn.d_un.d_val;
audit = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
}
+ if (dyn.d_tag == DT_FLAGS_1)
+ elf_tdata (abfd)->is_pie = (dyn.d_un.d_val & DF_1_PIE) != 0;
}
free (dynbuf);
(_("%pB: plugin needed to handle lto object"), abfd);
}
- for (isym = isymbuf, isymend = isymbuf + extsymcount;
+ for (isym = isymbuf, isymend = PTR_ADD (isymbuf, extsymcount);
isym < isymend;
isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
{
old_bfd = NULL;
new_sec = sec;
- if (is_elf_hash_table (htab))
+ if (is_elf_hash_table (&htab->root))
{
Elf_Internal_Versym iver;
unsigned int vernum = 0;
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- if (elf_tdata (abfd)->verdef != NULL
+ if (h->versioned != unversioned
+ && elf_tdata (abfd)->verdef != NULL
&& vernum > 1
&& definition)
h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
/* Setting the index to -3 tells elf_link_output_extsym that
this symbol is defined in a discarded section. */
- if (discarded && is_elf_hash_table (htab))
+ if (discarded && is_elf_hash_table (&htab->root))
h->indx = -3;
new_weak = (flags & BSF_WEAK) != 0;
&& definition
&& new_weak
&& !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
- && is_elf_hash_table (htab)
+ && is_elf_hash_table (&htab->root)
&& h->u.alias == NULL)
{
/* Keep a list of all weak defined non function symbols from
h->root.u.c.p->alignment_power = old_alignment;
}
- if (is_elf_hash_table (htab))
+ if (is_elf_hash_table (&htab->root))
{
/* Set a flag in the hash table entry indicating the type of
reference or definition we just found. A dynamic symbol
else
_bfd_error_handler
/* xgettext:c-format */
- (_("warning: alignment %u of symbol `%s' in %pB"
- " is smaller than %u in %pB"),
+ (_("warning: alignment %u of normal symbol `%s' in %pB"
+ " is smaller than %u used by the common definition in %pB"),
1 << normal_align, name, normal_bfd,
1 << common_align, common_bfd);
+
+ /* PR 30499: make sure that users understand that this warning is serious. */
+ _bfd_error_handler
+ (_("warning: NOTE: alignment discrepancies can cause real problems. Investigation is advised."));
}
}
if (h->size != 0
&& h->size != isym->st_size
&& ! size_change_ok)
- _bfd_error_handler
- /* xgettext:c-format */
- (_("warning: size of symbol `%s' changed"
- " from %" PRIu64 " in %pB to %" PRIu64 " in %pB"),
- name, (uint64_t) h->size, old_bfd,
- (uint64_t) isym->st_size, abfd);
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("warning: size of symbol `%s' changed"
+ " from %" PRIu64 " in %pB to %" PRIu64 " in %pB"),
+ name, (uint64_t) h->size, old_bfd,
+ (uint64_t) isym->st_size, abfd);
+
+ /* PR 30499: make sure that users understand that this warning is serious. */
+ _bfd_error_handler
+ (_("warning: NOTE: size discrepancies can cause real problems. Investigation is advised."));
+ }
h->size = isym->st_size;
}
h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
}
- if (definition && !dynamic)
+ /* Don't add indirect symbols for .symver x, x@FOO aliases
+ in IR. Since all data or text symbols in IR have the
+ same type, value and section, we can't tell if a symbol
+ is an alias of another symbol by their types, values and
+ sections. */
+ if (definition
+ && !dynamic
+ && (abfd->flags & BFD_PLUGIN) == 0)
{
char *p = strchr (name, ELF_VER_CHR);
if (p != NULL && p[1] != ELF_VER_CHR)
&& (s->flags & SEC_DEBUGGING) != 0))
continue;
- internal_relocs = _bfd_elf_link_read_relocs (abfd, s, NULL,
- NULL,
- info->keep_memory);
+ internal_relocs = _bfd_elf_link_info_read_relocs (abfd, info,
+ s, NULL,
+ NULL,
+ _bfd_link_keep_memory (info));
if (internal_relocs == NULL)
goto error_free_vers;
of the .stab/.stabstr sections. */
if (! dynamic
&& ! info->traditional_format
- && is_elf_hash_table (htab)
+ && is_elf_hash_table (&htab->root)
&& (info->strip != strip_all && info->strip != strip_debugger))
{
asection *stabstr;
/* Return the linker hash table entry of a symbol that might be
satisfied by an archive symbol. Return -1 on error. */
-struct elf_link_hash_entry *
+struct bfd_link_hash_entry *
_bfd_elf_archive_symbol_lookup (bfd *abfd,
struct bfd_link_info *info,
const char *name)
{
- struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *h;
char *p, *copy;
size_t len, first;
- h = elf_link_hash_lookup (elf_hash_table (info), name, false, false, true);
+ h = bfd_link_hash_lookup (info->hash, name, false, false, true);
if (h != NULL)
return h;
len = strlen (name);
copy = (char *) bfd_alloc (abfd, len);
if (copy == NULL)
- return (struct elf_link_hash_entry *) -1;
+ return (struct bfd_link_hash_entry *) -1;
first = p - name + 1;
memcpy (copy, name, first);
memcpy (copy + first, name + first + 1, len - first);
- h = elf_link_hash_lookup (elf_hash_table (info), copy, false, false, true);
+ h = bfd_link_hash_lookup (info->hash, copy, false, false, true);
if (h == NULL)
{
/* We also need to check references to the symbol without the
version. */
copy[first - 1] = '\0';
- h = elf_link_hash_lookup (elf_hash_table (info), copy,
- false, false, true);
+ h = bfd_link_hash_lookup (info->hash, copy, false, false, true);
}
bfd_release (abfd, copy);
bool loop;
size_t amt;
const struct elf_backend_data *bed;
- struct elf_link_hash_entry * (*archive_symbol_lookup)
+ struct bfd_link_hash_entry * (*archive_symbol_lookup)
(bfd *, struct bfd_link_info *, const char *);
if (! bfd_has_map (abfd))
symdefend = symdef + c;
for (i = 0; symdef < symdefend; symdef++, i++)
{
- struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *h;
bfd *element;
struct bfd_link_hash_entry *undefs_tail;
symindex mark;
}
h = archive_symbol_lookup (abfd, info, symdef->name);
- if (h == (struct elf_link_hash_entry *) -1)
+ if (h == (struct bfd_link_hash_entry *) -1)
goto error_return;
if (h == NULL)
continue;
- if (h->root.type == bfd_link_hash_undefined)
+ if (h->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)
+ if (is_elf_hash_table (info->hash)
+ && ((struct elf_link_hash_entry *) h)->indx == -3)
continue;
}
- else if (h->root.type == bfd_link_hash_common)
+ else if (h->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
}
else
{
- if (h->root.type != bfd_link_hash_undefweak)
+ if (h->type != bfd_link_hash_undefweak)
/* Symbol must be defined. Don't check it again. */
included[i] = true;
continue;
}
/* We need to include this archive member. */
- element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+ element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset,
+ info);
if (element == NULL)
goto error_return;
size_t best_size = 0;
unsigned long int i;
- /* We have a problem here. The following code to optimize the table
- size requires an integer type with more the 32 bits. If
- BFD_HOST_U_64_BIT is set we know about such a type. */
-#ifdef BFD_HOST_U_64_BIT
if (info->optimize)
{
size_t minsize;
size_t maxsize;
- BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
+ uint64_t best_chlen = ~((uint64_t) 0);
bfd *dynobj = elf_hash_table (info)->dynobj;
size_t dynsymcount = elf_hash_table (info)->dynsymcount;
const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
for (i = minsize; i < maxsize; ++i)
{
/* Walk through the array of hashcodes and count the collisions. */
- BFD_HOST_U_64_BIT max;
+ uint64_t max;
unsigned long int j;
unsigned long int fact;
free (counts);
}
else
-#endif /* defined (BFD_HOST_U_64_BIT) */
{
- /* This is the fallback solution if no 64bit type is available or if we
- are not supposed to spend much time on optimizations. We select the
- bucket count using a fixed set of numbers. */
for (i = 0; elf_buckets[i] != 0; i++)
{
best_size = elf_buckets[i];
if (!is_elf_hash_table (info->hash))
return true;
+ /* Any syms created from now on start with -1 in
+ got.refcount/offset and plt.refcount/offset. */
+ elf_hash_table (info)->init_got_refcount
+ = elf_hash_table (info)->init_got_offset;
+ elf_hash_table (info)->init_plt_refcount
+ = elf_hash_table (info)->init_plt_offset;
+
+ bed = get_elf_backend_data (output_bfd);
+
+ /* The backend may have to create some sections regardless of whether
+ we're dynamic or not. */
+ if (bed->elf_backend_always_size_sections
+ && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
+ return false;
+
dynobj = elf_hash_table (info)->dynobj;
if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
}
}
- bed = get_elf_backend_data (output_bfd);
-
if (info->gc_sections && bed->can_gc_sections)
{
struct elf_gc_sweep_symbol_info sweep_info;
if (sinfo.failed)
return false;
+ if (info->enable_dt_relr)
+ {
+ elf_link_add_dt_relr_dependency (&sinfo);
+ if (sinfo.failed)
+ return false;
+ }
+
if (elf_tdata (output_bfd)->verref == NULL)
s->flags |= SEC_EXCLUDE;
else
}
}
- /* Any syms created from now on start with -1 in
- got.refcount/offset and plt.refcount/offset. */
- elf_hash_table (info)->init_got_refcount
- = elf_hash_table (info)->init_got_offset;
- elf_hash_table (info)->init_plt_refcount
- = elf_hash_table (info)->init_plt_offset;
-
if (bfd_link_relocatable (info)
&& !_bfd_elf_size_group_sections (info))
return false;
- /* The backend may have to create some sections regardless of whether
- we're dynamic or not. */
- if (bed->elf_backend_always_size_sections
- && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
- return false;
-
/* Determine any GNU_STACK segment requirements, after the backend
has had a chance to set a default segment size. */
if (info->execstack)
- elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
+ {
+ /* If the user has explicitly requested warnings, then generate one even
+ though the choice is the result of another command line option. */
+ if (info->warn_execstack == 1)
+ {
+ if (info->error_execstack)
+ {
+ _bfd_error_handler
+ (_("\
+error: creating an executable stack because of -z execstack command line option"));
+ return false;
+ }
+
+ _bfd_error_handler
+ (_("\
+warning: enabling an executable stack because of -z execstack command line option"));
+ }
+
+ elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
+ }
else if (info->noexecstack)
elf_stack_flags (output_bfd) = PF_R | PF_W;
else
{
bfd *inputobj;
asection *notesec = NULL;
+ bfd *noteobj = NULL;
+ bfd *emptyobj = NULL;
int exec = 0;
for (inputobj = info->input_bfds;
s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
if (s)
{
- if (s->flags & SEC_CODE)
- exec = PF_X;
notesec = s;
+ if (s->flags & SEC_CODE)
+ {
+ noteobj = inputobj;
+ exec = PF_X;
+ /* There is no point in scanning the remaining bfds. */
+ break;
+ }
+ }
+ else if (bed->default_execstack && info->default_execstack)
+ {
+ exec = PF_X;
+ emptyobj = inputobj;
}
- else if (bed->default_execstack)
- exec = PF_X;
}
+
if (notesec || info->stacksize > 0)
- elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
+ {
+ if (exec)
+ {
+ if (info->warn_execstack != 0)
+ {
+ /* PR 29072: Because an executable stack is a serious
+ security risk, make sure that the user knows that it is
+ being enabled despite the fact that it was not requested
+ on the command line. */
+ if (noteobj)
+ {
+ if (info->error_execstack)
+ {
+ _bfd_error_handler (_("\
+error: %s: is triggering the generation of an executable stack (because it has an executable .note.GNU-stack section)"),
+ bfd_get_filename (noteobj));
+ return false;
+ }
+
+ _bfd_error_handler (_("\
+warning: %s: requires executable stack (because the .note.GNU-stack section is executable)"),
+ bfd_get_filename (noteobj));
+ }
+ else if (emptyobj)
+ {
+ if (info->error_execstack)
+ {
+ _bfd_error_handler (_("\
+error: %s: is triggering the generation of an executable stack because it does not have a .note.GNU-stack section"),
+ bfd_get_filename (emptyobj));
+ return false;
+ }
+
+ _bfd_error_handler (_("\
+warning: %s: missing .note.GNU-stack section implies executable stack"),
+ bfd_get_filename (emptyobj));
+ _bfd_error_handler (_("\
+NOTE: This behaviour is deprecated and will be removed in a future version of the linker"));
+ }
+ }
+ }
+ elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
+ }
+
if (notesec && exec && bfd_link_relocatable (info)
&& notesec->output_section != bfd_abs_section_ptr)
notesec->output_section->flags |= SEC_CODE;
return true;
s = bfd_get_section_by_name (abfd, ".dynamic");
- if (s == NULL || s->size == 0)
+ if (s == NULL || s->size == 0 || (s->flags & SEC_HAS_CONTENTS) == 0)
return true;
if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
- extdyn = dynbuf;
- extdynend = extdyn + s->size;
- for (; extdyn < extdynend; extdyn += extdynsize)
+ for (extdyn = dynbuf, extdynend = dynbuf + s->size;
+ (size_t) (extdynend - extdyn) >= extdynsize;
+ extdyn += extdynsize)
{
Elf_Internal_Dyn dyn;
ssymhead->count++;
}
BFD_ASSERT ((size_t) (ssymhead - ssymbuf) == shndx_count
- && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf)
- == total_size));
+ && (uintptr_t) ssym - (uintptr_t) ssymbuf == total_size);
free (indbuf);
return ssymbuf;
return aval;
}
-#ifdef BFD_HOST_64_BIT
static bfd_vma
ext64l_r_offset (const void *p)
{
| (uint64_t) a->c[7]);
return aval;
}
-#endif
/* When performing a relocatable link, the input relocations are
preserved. But, if they reference global symbols, the indices
}
else
{
-#ifdef BFD_HOST_64_BIT
if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
ext_r_off = ext64l_r_offset;
else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
ext_r_off = ext64b_r_offset;
else
-#endif
abort ();
}
size_t sortlen = p - loc;
bfd_vma r_off2 = (*ext_r_off) (loc);
size_t runlen = elt_size;
+ bfd_vma r_off_runend = r_off;
+ bfd_vma r_off_runend_next;
size_t buf_size = 96 * 1024;
while (p + runlen < end
&& (sortlen <= buf_size
|| runlen + elt_size <= buf_size)
- && r_off2 > (*ext_r_off) (p + runlen))
- runlen += elt_size;
+ /* run must not break the ordering of base..loc+1 */
+ && r_off2 > (r_off_runend_next = (*ext_r_off) (p + runlen))
+ /* run must be already sorted */
+ && r_off_runend_next >= r_off_runend)
+ {
+ runlen += elt_size;
+ r_off_runend = r_off_runend_next;
+ }
if (buf == NULL)
{
buf = bfd_malloc (buf_size);
if (ELF_ST_BIND (elfsym->st_info) == STB_GNU_UNIQUE)
elf_tdata (flinfo->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_unique;
- if (name == NULL
- || *name == '\0'
- || (input_sec->flags & SEC_EXCLUDE))
+ if (name == NULL || *name == '\0')
elfsym->st_name = (unsigned long) -1;
else
{
&& ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
{
struct local_hash_entry *lh;
+ size_t count_len;
+ size_t base_len;
+ char buf[30];
switch (ELF_ST_TYPE (elfsym->st_info))
{
case STT_FILE:
(&flinfo->local_hash_table, name, true, false);
if (lh == NULL)
return 0;
- if (lh->count)
+ /* Always append ".COUNT" to local symbols to avoid
+ potential conflicts with local symbol "XXX.COUNT". */
+ sprintf (buf, "%lx", lh->count);
+ base_len = lh->size;
+ if (!base_len)
{
- /* 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);
+ 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;
}
hash_table = elf_hash_table (flinfo->info);
strtabsize = hash_table->strtabsize;
- if (strtabsize <= hash_table->strtabcount)
+ if (strtabsize <= flinfo->output_bfd->symcount)
{
strtabsize += strtabsize;
hash_table->strtabsize = strtabsize;
if (hash_table->strtab == NULL)
return 0;
}
- hash_table->strtab[hash_table->strtabcount].sym = *elfsym;
- hash_table->strtab[hash_table->strtabcount].dest_index
- = hash_table->strtabcount;
- hash_table->strtab[hash_table->strtabcount].destshndx_index
- = flinfo->symshndxbuf ? bfd_get_symcount (flinfo->output_bfd) : 0;
-
+ hash_table->strtab[flinfo->output_bfd->symcount].sym = *elfsym;
+ hash_table->strtab[flinfo->output_bfd->symcount].dest_index
+ = flinfo->output_bfd->symcount;
flinfo->output_bfd->symcount += 1;
- hash_table->strtabcount += 1;
return 1;
}
file_ptr pos;
bool ret;
- if (!hash_table->strtabcount)
+ if (flinfo->output_bfd->symcount == 0)
return true;
BFD_ASSERT (elf_onesymtab (flinfo->output_bfd));
bed = get_elf_backend_data (flinfo->output_bfd);
- amt = bed->s->sizeof_sym * hash_table->strtabcount;
+ amt = bed->s->sizeof_sym * flinfo->output_bfd->symcount;
symbuf = (bfd_byte *) bfd_malloc (amt);
if (symbuf == NULL)
return false;
}
/* Now swap out the symbols. */
- for (i = 0; i < hash_table->strtabcount; i++)
+ for (i = 0; i < flinfo->output_bfd->symcount; i++)
{
struct elf_sym_strtab *elfsym = &hash_table->strtab[i];
if (elfsym->sym.st_name == (unsigned long) -1)
((bfd_byte *) symbuf
+ (elfsym->dest_index
* bed->s->sizeof_sym)),
- (flinfo->symshndxbuf
- + elfsym->destshndx_index));
+ NPTR_ADD (flinfo->symshndxbuf,
+ elfsym->dest_index));
}
hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
pos = hdr->sh_offset + hdr->sh_size;
- amt = hash_table->strtabcount * bed->s->sizeof_sym;
+ amt = bed->s->sizeof_sym * flinfo->output_bfd->symcount;
if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) == 0
- && bfd_bwrite (symbuf, amt, flinfo->output_bfd) == amt)
+ && bfd_write (symbuf, amt, flinfo->output_bfd) == amt)
{
hdr->sh_size += amt;
ret = true;
case SEC_INFO_TYPE_STABS:
case SEC_INFO_TYPE_EH_FRAME:
case SEC_INFO_TYPE_EH_FRAME_ENTRY:
+ case SEC_INFO_TYPE_SFRAME:
return true;
default:
break;
unsigned int
_bfd_elf_default_action_discarded (asection *sec)
{
+ const struct elf_backend_data *bed;
+ bed = get_elf_backend_data (sec->owner);
+
if (sec->flags & SEC_DEBUGGING)
return PRETEND;
if (strcmp (".eh_frame", sec->name) == 0)
return 0;
+ if (bed->elf_backend_can_make_multiple_eh_frame
+ && strncmp (sec->name, ".eh_frame.", 10) == 0)
+ return 0;
+
+ if (strcmp (".sframe", sec->name) == 0)
+ return 0;
+
if (strcmp (".gcc_except_table", sec->name) == 0)
return 0;
/* Find local symbol sections and adjust values of symbols in
SEC_MERGE sections. Write out those local symbols we know are
going into the output file. */
- isymend = isymbuf + locsymcount;
+ isymend = PTR_ADD (isymbuf, locsymcount);
for (isym = isymbuf, pindex = flinfo->indices, ppsection = flinfo->sections;
isym < isymend;
isym++, pindex++, ppsection++)
/* 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,
- isec->output_section))
+ if (isym->st_shndx < SHN_LORESERVE
+ && (isec->output_section == NULL
+ || bfd_section_removed_from_list (output_bfd,
+ isec->output_section)))
continue;
/* Get the name of the symbol. */
contents = flinfo->contents;
}
}
+ else if (!(o->flags & SEC_RELOC)
+ && !bed->elf_backend_write_section
+ && o->sec_info_type == SEC_INFO_TYPE_MERGE)
+ /* A MERGE section that has no relocations doesn't need the
+ contents anymore, they have been recorded earlier. Except
+ if the backend has special provisions for writing sections. */
+ contents = NULL;
else
{
contents = flinfo->contents;
/* Get the swapped relocs. */
internal_relocs
- = _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs,
- flinfo->internal_relocs, false);
+ = _bfd_elf_link_info_read_relocs (input_bfd, flinfo->info, o,
+ flinfo->external_relocs,
+ flinfo->internal_relocs,
+ false);
if (internal_relocs == NULL
&& o->reloc_count > 0)
return false;
- /* We need to reverse-copy input .ctors/.dtors sections if
- they are placed in .init_array/.finit_array for output. */
- if (o->size > address_size
- && ((startswith (o->name, ".ctors")
- && strcmp (o->output_section->name,
- ".init_array") == 0)
- || (startswith (o->name, ".dtors")
- && strcmp (o->output_section->name,
- ".fini_array") == 0))
- && (o->name[6] == 0 || o->name[6] == '.'))
- {
- if (o->size * bed->s->int_rels_per_ext_rel
- != o->reloc_count * address_size)
- {
- _bfd_error_handler
- /* xgettext:c-format */
- (_("error: %pB: size of section %pA is not "
- "multiple of address size"),
- input_bfd, o);
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
- o->flags |= SEC_ELF_REVERSE_COPY;
- }
-
action_discarded = -1;
if (!elf_section_ignore_discarded_relocs (o))
action_discarded = (*bed->action_discarded) (o);
irela = internal_relocs;
irelaend = irela + o->reloc_count;
- rel_hash = esdo->rel.hashes + esdo->rel.count;
+ rel_hash = PTR_ADD (esdo->rel.hashes, esdo->rel.count);
/* We start processing the REL relocs, if any. When we reach
IRELAMID in the loop, we switch to the RELA relocs. */
irelamid = irela;
if (irela == irelamid)
{
- rel_hash = esdo->rela.hashes + esdo->rela.count;
+ rel_hash = PTR_ADD (esdo->rela.hashes, esdo->rela.count);
rela_hash_list = rel_hash;
rela_normal = bed->rela_normal;
}
return false;
}
break;
+ case SEC_INFO_TYPE_SFRAME:
+ {
+ /* Merge .sframe sections into the ctf frame encoder
+ context of the output_bfd's section. The final .sframe
+ output section will be written out later. */
+ if (!_bfd_elf_merge_section_sframe (output_bfd, flinfo->info,
+ o, contents))
+ return false;
+ }
+ break;
default:
{
if (! (o->flags & SEC_EXCLUDE))
offset *= bfd_octets_per_byte (output_bfd, o);
- if ((o->flags & SEC_ELF_REVERSE_COPY))
+ if ((o->flags & SEC_ELF_REVERSE_COPY)
+ && o->size > address_size)
{
/* Reverse-copy input section to output. */
+
+ if ((o->size & (address_size - 1)) != 0
+ || (o->reloc_count != 0
+ && (o->size * bed->s->int_rels_per_ext_rel
+ != o->reloc_count * address_size)))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("error: %pB: size of section %pA is not "
+ "multiple of address size"),
+ input_bfd, o);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
do
{
todo -= address_size;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_outext_info eoinfo;
bool merged;
- size_t relativecount = 0;
+ size_t relativecount;
+ size_t relr_entsize;
asection *reldyn = 0;
bfd_size_type amt;
asection *attr_section = NULL;
bool sections_removed;
bool ret;
- if (!is_elf_hash_table (htab))
+ if (!is_elf_hash_table (&htab->root))
return false;
if (bfd_link_pic (info))
&& elf_symtab_shndx_list (sec->owner) != NULL)
max_sym_shndx_count = sym_count;
- if (esdo->this_hdr.sh_type == SHT_REL
- || esdo->this_hdr.sh_type == SHT_RELA)
+ esdi = elf_section_data (sec);
+
+ if (esdi->this_hdr.sh_type == SHT_REL
+ || esdi->this_hdr.sh_type == SHT_RELA)
/* Some backends use reloc_count in relocation sections
to count particular types of relocs. Of course,
reloc sections themselves can't have relocations. */
else if (bed->elf_backend_count_relocs)
reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
- esdi = elf_section_data (sec);
-
if ((sec->flags & SEC_RELOC) != 0)
{
size_t ext_size = 0;
later. Use bfd_malloc since it will be freed by
bfd_compress_section_contents. */
unsigned char *contents = esdo->this_hdr.contents;
- if ((o->flags & SEC_ELF_COMPRESS) == 0 || contents != NULL)
+ if (contents != NULL)
abort ();
contents
= (unsigned char *) bfd_malloc (esdo->this_hdr.sh_size);
if (!_bfd_elf_fixup_eh_frame_hdr (info))
return false;
+ /* Finish relative relocations here after regular symbol processing
+ is finished if DT_RELR is enabled. */
+ if (info->enable_dt_relr
+ && bed->finish_relative_relocs
+ && !bed->finish_relative_relocs (info))
+ info->callbacks->einfo
+ (_("%F%P: %pB: failed to finish relative relocations\n"), abfd);
+
/* Since ELF permits relocations to be against local symbols, we
must have the local symbols available when we do the relocations.
Since we would rather only read the local symbols once, and we
/* 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
- && (info->strip != strip_all || emit_relocs))
+ if (bed->elf_backend_output_arch_local_syms)
{
if (! ((*bed->elf_backend_output_arch_local_syms)
(abfd, info, &flinfo, elf_link_output_symstrtab)))
off, true);
if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
- || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
+ || (bfd_write (flinfo.symshndxbuf, amt, abfd) != amt))
{
ret = false;
goto return_local_hash_table;
o->reloc_count = 0;
}
+ relativecount = 0;
if (dynamic && info->combreloc && dynobj != NULL)
relativecount = elf_link_sort_relocs (abfd, info, &reldyn);
+ relr_entsize = 0;
+ if (htab->srelrdyn != NULL
+ && htab->srelrdyn->output_section != NULL
+ && htab->srelrdyn->size != 0)
+ {
+ asection *s = htab->srelrdyn->output_section;
+ relr_entsize = elf_section_data (s)->this_hdr.sh_entsize;
+ if (relr_entsize == 0)
+ {
+ relr_entsize = bed->s->arch_size / 8;
+ elf_section_data (s)->this_hdr.sh_entsize = relr_entsize;
+ }
+ }
+
/* If we are linking against a dynamic object, or generating a
shared library, finish up the dynamic linking information. */
if (dynamic)
BFD_ASSERT (o != NULL);
dyncon = o->contents;
- dynconend = o->contents + o->size;
+ dynconend = PTR_ADD (o->contents, o->size);
for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
default:
continue;
case DT_NULL:
- if (relativecount > 0 && dyncon + bed->s->sizeof_dyn < dynconend)
+ if (relativecount != 0)
{
switch (elf_section_data (reldyn)->this_hdr.sh_type)
{
case SHT_REL: dyn.d_tag = DT_RELCOUNT; break;
case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break;
- default: continue;
}
- dyn.d_un.d_val = relativecount;
+ if (dyn.d_tag != DT_NULL
+ && dynconend - dyncon >= bed->s->sizeof_dyn)
+ {
+ dyn.d_un.d_val = relativecount;
+ relativecount = 0;
+ break;
+ }
relativecount = 0;
- break;
+ }
+ if (relr_entsize != 0)
+ {
+ if (dynconend - dyncon >= 3 * bed->s->sizeof_dyn)
+ {
+ asection *s = htab->srelrdyn;
+ dyn.d_tag = DT_RELR;
+ dyn.d_un.d_ptr
+ = s->output_section->vma + s->output_offset;
+ bed->s->swap_dyn_out (dynobj, &dyn, dyncon);
+ dyncon += bed->s->sizeof_dyn;
+
+ dyn.d_tag = DT_RELRSZ;
+ dyn.d_un.d_val = s->size;
+ bed->s->swap_dyn_out (dynobj, &dyn, dyncon);
+ dyncon += bed->s->sizeof_dyn;
+
+ dyn.d_tag = DT_RELRENT;
+ dyn.d_un.d_val = relr_entsize;
+ relr_entsize = 0;
+ break;
+ }
+ relr_entsize = 0;
}
continue;
/* Check for DT_TEXTREL (late, in case the backend removes it). */
if (bfd_link_textrel_check (info)
- && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
+ && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL
+ && o->size != 0)
{
bfd_byte *dyncon, *dynconend;
else if (bfd_link_dll (info))
info->callbacks->einfo
(_("%P: warning: creating DT_TEXTREL in a shared object\n"));
+ else if (bfd_link_pde (info))
+ info->callbacks->einfo
+ (_("%P: warning: creating DT_TEXTREL in a PDE\n"));
else
info->callbacks->einfo
(_("%P: warning: creating DT_TEXTREL in a PIE\n"));
if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
goto error_return;
+ if (! _bfd_elf_write_section_sframe (abfd, info))
+ goto error_return;
+
if (info->callbacks->emit_ctf)
info->callbacks->emit_ctf ();
info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
return false;
}
- if (info->keep_memory)
- symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+ if (_bfd_link_keep_memory (info) )
+ {
+ symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+ info->cache_size += (cookie->locsymcount
+ * sizeof (Elf_External_Sym_Shndx));
+ }
}
return true;
}
}
else
{
- cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
- info->keep_memory);
+ cookie->rels = _bfd_elf_link_info_read_relocs (abfd, info, sec,
+ NULL, NULL,
+ _bfd_link_keep_memory (info));
if (cookie->rels == NULL)
return false;
cookie->rel = cookie->rels;
/* Return the local debug definition section. */
asection *isec = bfd_section_from_elf_index (sec->owner,
sym->st_shndx);
- if ((isec->flags & SEC_DEBUGGING) != 0)
+ if (isec != NULL && (isec->flags & SEC_DEBUGGING) != 0)
return isec;
}
return true;
}
+struct link_info_ok
+{
+ struct bfd_link_info *info;
+ bool ok;
+};
+
static bool
-elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
+elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h,
+ void *ptr)
{
asection *sec;
bfd_vma hstart, hend;
Elf_Internal_Rela *relstart, *relend, *rel;
const struct elf_backend_data *bed;
unsigned int log_file_align;
+ struct link_info_ok *info = (struct link_info_ok *) ptr;
/* Take care of both those symbols that do not describe vtables as
well as those that are not loaded. */
hstart = h->root.u.def.value;
hend = hstart + h->size;
- relstart = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, true);
+ relstart = _bfd_elf_link_info_read_relocs (sec->owner, info->info,
+ sec, NULL, NULL, true);
if (!relstart)
- return *(bool *) okp = false;
+ return info->ok = false;
bed = get_elf_backend_data (sec->owner);
log_file_align = bed->s->log_file_align;
elf_gc_mark_hook_fn gc_mark_hook;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_link_hash_table *htab;
+ struct link_info_ok info_ok;
if (!bed->can_gc_sections
|| !is_elf_hash_table (info->hash))
return false;
/* Kill the vtable relocations that were not used. */
- elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok);
- if (!ok)
+ info_ok.info = info;
+ info_ok.ok = true;
+ elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &info_ok);
+ if (!info_ok.ok)
return false;
/* Mark dynamically referenced symbols. */
extsymcount -= elf_tdata (abfd)->symtab_hdr.sh_info;
sym_hashes = elf_sym_hashes (abfd);
- sym_hashes_end = sym_hashes + extsymcount;
+ sym_hashes_end = PTR_ADD (sym_hashes, extsymcount);
/* Hunt down the child symbol, which is in this section at the same
offset as the relocation. */
_bfd_elf_adjust_eh_frame_global_symbol, NULL);
}
+ o = bfd_get_section_by_name (output_bfd, ".sframe");
+ if (o != NULL)
+ {
+ asection *i;
+
+ for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+ {
+ if (i->size == 0)
+ continue;
+
+ abfd = i->owner;
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
+
+ if (!init_reloc_cookie_for_section (&cookie, info, i))
+ return -1;
+
+ if (_bfd_elf_parse_sframe (abfd, info, i, &cookie))
+ {
+ if (_bfd_elf_discard_section_sframe (i,
+ bfd_elf_reloc_symbol_deleted_p,
+ &cookie))
+ {
+ if (i->size != i->rawsize)
+ changed = 1;
+ }
+ }
+ fini_reloc_cookie_for_section (&cookie, i);
+ }
+ /* Update the reference to the output .sframe section. Used to
+ determine later if PT_GNU_SFRAME segment is to be generated. */
+ if (!_bfd_elf_set_section_sframe (output_bfd, info))
+ return -1;
+ }
+
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
{
const struct elf_backend_data *bed;
if (info->eh_frame_hdr_type
&& !bfd_link_relocatable (info)
- && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info))
+ && _bfd_elf_discard_section_eh_frame_hdr (info))
changed = 1;
return changed;