/* 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.
(bed->dynamic_sec_flags
| SEC_READONLY));
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
htab->srelgot = s;
s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (s == NULL
- || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
htab->sgot = s;
{
s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
if (s == NULL
- || !bfd_set_section_alignment (abfd, s,
- bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
htab->sgotplt = s;
}
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d",
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version",
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, 1))
+ || !bfd_set_section_alignment (s, 1))
return FALSE;
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_r",
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
s = bfd_make_section_anyway_with_flags (abfd, ".dynsym",
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
elf_hash_table (info)->dynsym = s;
s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", flags);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
/* The special symbol _DYNAMIC is always set to the start of the
s = bfd_make_section_anyway_with_flags (abfd, ".hash",
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
}
- if (info->emit_gnu_hash)
+ if (info->emit_gnu_hash && bed->record_xhash_symbol == NULL)
{
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash",
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
/* For 64-bit ELF, .gnu.hash is a non-uniform entity size section:
4 32-bit words followed by variable count of 64-bit words, then
s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
+ || !bfd_set_section_alignment (s, bed->plt_alignment))
return FALSE;
htab->splt = s;
? ".rela.plt" : ".rel.plt"),
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
htab->srelplt = s;
? ".rela.bss" : ".rel.bss"),
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
htab->srelbss = s;
? ".rela.data.rel.ro" : ".rel.data.rel.ro"),
flags | SEC_READONLY));
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- bed->s->log_file_align))
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
return FALSE;
htab->sreldynrelro = s;
}
SHT_PROGBITS/SHT_NOBITS. */
case SHT_NULL:
htab = elf_hash_table (info);
- if (p == htab->tls_sec)
- return FALSE;
-
if (htab->text_index_section != NULL)
return p != htab->text_index_section && p != htab->data_index_section;
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
{
bh = &hi->root;
if (bh->type == bfd_link_hash_defined
+ && bh->u.def.section->owner != NULL
&& (bh->u.def.section->owner->flags & BFD_PLUGIN) != 0)
{
/* Mark the previous definition from IR object as
/* 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
}
erela = (const bfd_byte *) external_relocs;
- erelaend = erela + shdr->sh_size;
+ /* Setting erelaend like this and comparing with <= handles case of
+ a fuzzed object with sh_size not a multiple of sh_entsize. */
+ erelaend = erela + shdr->sh_size - shdr->sh_entsize;
irela = internal_relocs;
- while (erela < erelaend)
+ while (erela <= erelaend)
{
bfd_vma r_symndx;
/* If the real definition is defined by a regular object file,
don't do anything special. See the longer description in
- _bfd_elf_adjust_dynamic_symbol, below. */
- if (def->def_regular)
+ _bfd_elf_adjust_dynamic_symbol, below. If the def is not
+ bfd_link_hash_defined as it was when put on the alias list
+ then it must have originally been a versioned symbol (for
+ which a non-versioned indirect symbol is created) and later
+ a definition for the non-versioned symbol is found. In that
+ case the indirection is flipped with the versioned symbol
+ becoming an indirect pointing at the non-versioned symbol.
+ Thus, not an alias any more. */
+ if (def->def_regular
+ || def->root.type != bfd_link_hash_defined)
{
h = def;
while ((h = h->u.alias) != def)
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak);
BFD_ASSERT (def->def_dynamic);
- BFD_ASSERT (def->root.type == bfd_link_hash_defined);
(*bed->elf_backend_copy_indirect_symbol) (eif->info, def, h);
}
}
know the symbol alignment requirement, we start with the
maximum alignment and check low bits of the symbol address
for the minimum alignment. */
- power_of_two = bfd_get_section_alignment (sec->owner, sec);
+ power_of_two = bfd_section_alignment (sec);
mask = ((bfd_vma) 1 << power_of_two) - 1;
while ((h->root.u.def.value & mask) != 0)
{
--power_of_two;
}
- if (power_of_two > bfd_get_section_alignment (dynbss->owner,
- dynbss))
+ if (power_of_two > bfd_section_alignment (dynbss))
{
/* Adjust the section alignment if needed. */
- if (! bfd_set_section_alignment (dynbss->owner, dynbss,
- power_of_two))
+ if (!bfd_set_section_alignment (dynbss, power_of_two))
return FALSE;
}
return FALSE;
}
-/* Sort symbol by value, section, and size. */
+/* Sort symbol by value, section, size, and type. */
static int
elf_sort_symbol (const void *arg1, const void *arg2)
{
const struct elf_link_hash_entry *h1;
const struct elf_link_hash_entry *h2;
bfd_signed_vma vdiff;
+ int sdiff;
+ const char *n1;
+ const char *n2;
h1 = *(const struct elf_link_hash_entry **) arg1;
h2 = *(const struct elf_link_hash_entry **) arg2;
vdiff = h1->root.u.def.value - h2->root.u.def.value;
if (vdiff != 0)
return vdiff > 0 ? 1 : -1;
- else
- {
- int sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id;
- if (sdiff != 0)
- return sdiff > 0 ? 1 : -1;
- }
+
+ sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id;
+ if (sdiff != 0)
+ return sdiff;
+
+ /* Sort so that sized symbols are selected over zero size symbols. */
vdiff = h1->size - h2->size;
- return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1;
+ if (vdiff != 0)
+ return vdiff > 0 ? 1 : -1;
+
+ /* Sort so that STT_OBJECT is selected over STT_NOTYPE. */
+ if (h1->type != h2->type)
+ return h1->type - h2->type;
+
+ /* If symbols are properly sized and typed, and multiple strong
+ aliases are not defined in a shared library by the user we
+ shouldn't get here. Unfortunately linker script symbols like
+ __bss_start sometimes match a user symbol defined at the start of
+ .bss without proper size and type. We'd like to preference the
+ user symbol over reserved system symbols. Sort on leading
+ underscores. */
+ n1 = h1->root.root.string;
+ n2 = h2->root.root.string;
+ while (*n1 == *n2)
+ {
+ if (*n1 == 0)
+ break;
+ ++n1;
+ ++n2;
+ }
+ if (*n1 == '_')
+ return -1;
+ if (*n2 == '_')
+ return 1;
+
+ /* Final sort on name selects user symbols like '_u' over reserved
+ system symbols like '_Z' and also will avoid qsort instability. */
+ return *n1 - *n2;
}
/* This function is used to adjust offsets into .dynstr for
struct elf_link_hash_entry **sym_hash;
bfd_boolean dynamic;
Elf_External_Versym *extversym = NULL;
+ Elf_External_Versym *extversym_end = NULL;
Elf_External_Versym *ever;
struct elf_link_hash_entry *weaks;
struct elf_link_hash_entry **nondeflt_vers = NULL;
{
const char *name;
- name = bfd_get_section_name (abfd, s);
+ name = bfd_section_name (s);
if (CONST_STRNEQ (name, ".gnu.warning."))
{
char *msg;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
for (extdyn = dynbuf;
- extdyn < dynbuf + s->size;
+ extdyn <= dynbuf + s->size - bed->s->sizeof_dyn;
extdyn += bed->s->sizeof_dyn)
{
Elf_Internal_Dyn dyn;
Elf_Internal_Shdr *versymhdr;
versymhdr = &elf_tdata (abfd)->dynversym_hdr;
- extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+ amt = versymhdr->sh_size;
+ extversym = (Elf_External_Versym *) bfd_malloc (amt);
if (extversym == NULL)
goto error_free_sym;
- amt = versymhdr->sh_size;
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));
}
}
}
weaks = NULL;
- ever = extversym != NULL ? extversym + extsymoff : NULL;
+ if (extversym == NULL)
+ ever = NULL;
+ else if (extversym + extsymoff < extversym_end)
+ ever = extversym + extsymoff;
+ else
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: invalid version offset %lx (max %lx)"),
+ abfd, (long) extsymoff,
+ (long) (extversym_end - extversym) / sizeof (* extversym));
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
+
+ if (!bfd_link_relocatable (info)
+ && abfd->lto_slim_object)
+ {
+ _bfd_error_handler
+ (_("%pB: plugin needed to handle lto object"), abfd);
+ }
+
for (isym = isymbuf, isymend = isymbuf + extsymcount;
isym < isymend;
isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
bfd_boolean common;
bfd_boolean discarded;
unsigned int old_alignment;
+ unsigned int shindex;
bfd *old_bfd;
bfd_boolean matched;
global symbols follow all local symbols, and that sh_info
point to the first global symbol. Unfortunately, Irix 5
screws this up. */
- continue;
+ if (elf_bad_symtab (abfd))
+ continue;
+
+ /* If we aren't prepared to handle locals within the globals
+ then we'll likely segfault on a NULL symbol hash if the
+ symbol is ever referenced in relocations. */
+ shindex = elf_elfheader (abfd)->e_shstrndx;
+ name = bfd_elf_string_from_elf_section (abfd, shindex, hdr->sh_name);
+ _bfd_error_handler (_("%pB: %s local symbol at index %lu"
+ " (>= sh_info of %lu)"),
+ abfd, name, (long) (isym - isymbuf + extsymoff),
+ (long) extsymoff);
+
+ /* Dynamic object relocations are not processed by ld, so
+ ld won't run into the problem mentioned above. */
+ if (dynamic)
+ continue;
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
case STB_GLOBAL:
if (isym->st_shndx != SHN_UNDEF && !common)
/* Sanity check that all possibilities were handled. */
if (sec == NULL)
- {
- bfd_set_error (bfd_error_bad_value);
- goto error_free_vers;
- }
+ abort ();
/* Silently discard TLS symbols from --just-syms. There's
no way to combine a static TLS block with a new TLS block
else
iver.vs_vers = 0;
}
+ else if (ever >= extversym_end)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: not enough version information"),
+ abfd);
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
else
_bfd_elf_swap_versym_in (abfd, ever, &iver);
(struct bfd_link_hash_entry **) sym_hash)))
goto error_free_vers;
- if ((abfd->flags & DYNAMIC) == 0
- && (bfd_get_flavour (info->output_bfd)
- == bfd_target_elf_flavour))
- {
- if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_gnu_symbols
- |= elf_gnu_symbol_ifunc;
- if ((flags & BSF_GNU_UNIQUE))
- elf_tdata (info->output_bfd)->has_gnu_symbols
- |= elf_gnu_symbol_unique;
- }
-
h = *sym_hash;
/* We need to make sure that indirect symbol dynamic flags are
updated. */
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 (struct elf_link_hash_entry *);
- sorted_sym_hash = (struct elf_link_hash_entry **) bfd_malloc (amt);
+ amt *= sizeof (*sorted_sym_hash);
+ sorted_sym_hash = bfd_malloc (amt);
if (sorted_sym_hash == NULL)
goto error_return;
sym_hash = sorted_sym_hash;
}
}
- qsort (sorted_sym_hash, sym_count,
- sizeof (struct elf_link_hash_entry *),
+ qsort (sorted_sym_hash, sym_count, sizeof (*sorted_sym_hash),
elf_sort_symbol);
while (weaks != NULL)
unsigned long int *counts;
bfd_vma *bitmask;
bfd_byte *contents;
+ bfd_size_type xlat;
long int min_dynindx;
unsigned long int bucketcount;
unsigned long int symindx;
}
/* This function will be called though elf_link_hash_traverse to do
- final dynaminc symbol renumbering. */
+ final dynamic symbol renumbering in case of .gnu.hash.
+ If using .MIPS.xhash, invoke record_xhash_symbol to add symbol index
+ to the translation table. */
static bfd_boolean
-elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
+elf_gnu_hash_process_symidx (struct elf_link_hash_entry *h, void *data)
{
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
unsigned long int bucket;
if (! (*s->bed->elf_hash_symbol) (h))
{
if (h->dynindx >= s->min_dynindx)
- h->dynindx = s->local_indx++;
+ {
+ if (s->bed->record_xhash_symbol != NULL)
+ {
+ (*s->bed->record_xhash_symbol) (h, 0);
+ s->local_indx++;
+ }
+ else
+ h->dynindx = s->local_indx++;
+ }
return TRUE;
}
bfd_put_32 (s->output_bfd, val,
s->contents + (s->indx[bucket] - s->symindx) * 4);
--s->counts[bucket];
- h->dynindx = s->indx[bucket]++;
+ if (s->bed->record_xhash_symbol != NULL)
+ {
+ bfd_vma xlat_loc = s->xlat + (s->indx[bucket]++ - s->symindx) * 4;
+
+ (*s->bed->record_xhash_symbol) (h, xlat_loc);
+ }
+ else
+ h->dynindx = s->indx[bucket]++;
return TRUE;
}
if ((info->emit_hash
&& !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0))
|| (info->emit_gnu_hash
- && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0))
+ && (bed->record_xhash_symbol == NULL
+ && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0)))
|| !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
_bfd_elf_init_1_index_section (bfd *output_bfd, struct bfd_link_info *info)
{
asection *s;
+ asection *found = NULL;
for (s = output_bfd->sections; s != NULL; s = s->next)
if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC
&& !_bfd_elf_omit_section_dynsym_default (output_bfd, info, s))
{
- elf_hash_table (info)->text_index_section = s;
- break;
+ found = s;
+ if ((s->flags & SEC_THREAD_LOCAL) == 0)
+ break;
}
+ elf_hash_table (info)->text_index_section = found;
}
/* Find two non-excluded output sections, one for code, one for data.
_bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info)
{
asection *s;
+ asection *found = NULL;
/* Data first, since setting text_index_section changes
_bfd_elf_omit_section_dynsym_default. */
for (s = output_bfd->sections; s != NULL; s = s->next)
- if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
+ if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC
+ && !(s->flags & SEC_READONLY)
&& !_bfd_elf_omit_section_dynsym_default (output_bfd, info, s))
{
- elf_hash_table (info)->data_index_section = s;
- break;
+ found = s;
+ if ((s->flags & SEC_THREAD_LOCAL) == 0)
+ break;
}
+ elf_hash_table (info)->data_index_section = found;
for (s = output_bfd->sections; s != NULL; s = s->next)
- if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY))
- == (SEC_ALLOC | SEC_READONLY))
+ if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC
+ && (s->flags & SEC_READONLY)
&& !_bfd_elf_omit_section_dynsym_default (output_bfd, info, s))
{
- elf_hash_table (info)->text_index_section = s;
+ found = s;
break;
}
-
- if (elf_hash_table (info)->text_index_section == NULL)
- elf_hash_table (info)->text_index_section
- = elf_hash_table (info)->data_index_section;
+ elf_hash_table (info)->text_index_section = found;
}
+#define GNU_HASH_SECTION_NAME(bed) \
+ (bed)->record_xhash_symbol != NULL ? ".MIPS.xhash" : ".gnu.hash"
+
bfd_boolean
bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
{
return FALSE;
}
- s = bfd_get_linker_section (dynobj, ".gnu.hash");
+ s = bfd_get_linker_section (dynobj, GNU_HASH_SECTION_NAME (bed));
BFD_ASSERT (s != NULL);
if (cinfo.nsyms == 0)
{
- /* Empty .gnu.hash section is special. */
+ /* Empty .gnu.hash or .MIPS.xhash section is special. */
BFD_ASSERT (cinfo.min_dynindx == -1);
free (cinfo.hashcodes);
s->size = 5 * 4 + bed->s->arch_size / 8;
s->size = (4 + bucketcount + cinfo.nsyms) * 4;
s->size += cinfo.maskbits / 8;
+ if (bed->record_xhash_symbol != NULL)
+ s->size += cinfo.nsyms * 4;
contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
if (contents == NULL)
{
cinfo.contents = contents;
- /* Renumber dynamic symbols, populate .gnu.hash section. */
+ cinfo.xlat = contents + cinfo.nsyms * 4 - s->contents;
+ /* Renumber dynamic symbols, if populating .gnu.hash section.
+ If using .MIPS.xhash, populate the translation table. */
elf_link_hash_traverse (elf_hash_table (info),
- elf_renumber_gnu_hash_syms, &cinfo);
+ elf_gnu_hash_process_symidx, &cinfo);
contents = s->contents + 16;
for (i = 0; i < maskwords; ++i)
{
Elf_Internal_Sym *isym;
struct elf_symbuf_symbol *ssym;
+ void *p;
} u;
const char *name;
};
const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
- return s1->st_shndx - s2->st_shndx;
+ if (s1->st_shndx != s2->st_shndx)
+ return s1->st_shndx > s2->st_shndx ? 1 : -1;
+ /* Final sort by the address of the sym in the symbuf ensures
+ a stable sort. */
+ if (s1 != s2)
+ return s1 > s2 ? 1 : -1;
+ return 0;
}
static int
{
const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
- return strcmp (s1->name, s2->name);
+ int ret = strcmp (s1->name, s2->name);
+ if (ret != 0)
+ return ret;
+ if (s1->u.p != s2->u.p)
+ return s1->u.p > s2->u.p ? 1 : -1;
+ return 0;
}
static struct elf_symbuf_head *
goto done;
if (!info->reduce_memory_overheads)
- elf_tdata (bfd1)->symbuf = ssymbuf1
- = elf_create_symbuf (symcount1, isymbuf1);
+ {
+ ssymbuf1 = elf_create_symbuf (symcount1, isymbuf1);
+ elf_tdata (bfd1)->symbuf = ssymbuf1;
+ }
}
if (ssymbuf1 == NULL || ssymbuf2 == NULL)
goto done;
if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
- elf_tdata (bfd2)->symbuf = ssymbuf2
- = elf_create_symbuf (symcount2, isymbuf2);
+ {
+ ssymbuf2 = elf_create_symbuf (symcount2, isymbuf2);
+ elf_tdata (bfd2)->symbuf = ssymbuf2;
+ }
}
if (ssymbuf1 != NULL && ssymbuf2 != NULL)
{
if (strncmp (".end", name + len, 4) == 0)
{
- *result = curr->vma + curr->size / bfd_octets_per_byte (abfd);
+ *result = (curr->vma
+ + curr->size / bfd_octets_per_byte (abfd, curr));
return TRUE;
}
bfd_reloc_status_type
bfd_elf_perform_complex_relocation (bfd *input_bfd,
- asection *input_section ATTRIBUTE_UNUSED,
+ asection *input_section,
bfd_byte *contents,
Elf_Internal_Rela *rel,
bfd_vma relocation)
bfd_vma shift, x, mask;
unsigned long start, oplen, len, wordsz, chunksz, lsb0_p, signed_p, trunc_p;
bfd_reloc_status_type r;
+ bfd_size_type octets;
/* Perform this reloc, since it is complex.
(this is not to say that it necessarily refers to a complex
else
shift = (8 * wordsz) - (start + len);
- x = get_value (wordsz, chunksz, input_bfd,
- contents + rel->r_offset * bfd_octets_per_byte (input_bfd));
+ octets = rel->r_offset * bfd_octets_per_byte (input_bfd, input_section);
+ x = get_value (wordsz, chunksz, input_bfd, contents + octets);
#ifdef DEBUG
printf ("Doing complex reloc: "
(unsigned long) relocation, (unsigned long) (mask << shift),
(unsigned long) ((relocation & mask) << shift), (unsigned long) x);
#endif
- put_value (wordsz, chunksz, input_bfd, x,
- contents + rel->r_offset * bfd_octets_per_byte (input_bfd));
+ put_value (wordsz, chunksz, input_bfd, x, contents + octets);
return r;
}
Elf_Internal_Rela rela[1];
};
+/* qsort stability here and for cmp2 is only an issue if multiple
+ dynamic relocations are emitted at the same address. But targets
+ that apply a series of dynamic relocations each operating on the
+ result of the prior relocation can't use -z combreloc as
+ implemented anyway. Such schemes tend to be broken by sorting on
+ symbol index. That leaves dynamic NONE relocs as the only other
+ case where ld might emit multiple relocs at the same address, and
+ those are only emitted due to target bugs. */
+
static int
elf_link_sort_cmp1 (const void *A, const void *B)
{
struct elf_link_sort_rela *sq;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
int i2e = bed->s->int_rels_per_ext_rel;
- unsigned int opb = bfd_octets_per_byte (abfd);
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *);
void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
struct bfd_link_order *lo;
return ret;
}
+ if (ELF_ST_TYPE (elfsym->st_info) == STT_GNU_IFUNC)
+ elf_tdata (flinfo->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_ifunc;
+ 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))
hash_table->strtab[hash_table->strtabcount].destshndx_index
= flinfo->symshndxbuf ? bfd_get_symcount (flinfo->output_bfd) : 0;
- bfd_get_symcount (flinfo->output_bfd) += 1;
+ flinfo->output_bfd->symcount += 1;
hash_table->strtabcount += 1;
return 1;
+ 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;
/* If we are reporting errors for this situation then do so now. */
if (!ignore_undef
- && h->ref_dynamic
+ && h->ref_dynamic_nonweak
&& (!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)
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)
{
/* Don't attempt to output symbols with st_shnx in the
reserved range other than SHN_ABS and SHN_COMMON. */
- *ppsection = NULL;
- continue;
+ isec = bfd_und_section_ptr;
}
else if (isec->sec_info_type == SEC_INFO_TYPE_MERGE
&& ELF_ST_TYPE (isym->st_info) != STT_SECTION)
file_ptr offset = (file_ptr) o->output_offset;
bfd_size_type todo = o->size;
- offset *= bfd_octets_per_byte (output_bfd);
+ offset *= bfd_octets_per_byte (output_bfd, o);
if ((o->flags & SEC_ELF_REVERSE_COPY))
{
bfd_byte *buf;
bfd_boolean ok;
const char *sym_name;
+ bfd_size_type octets;
size = (bfd_size_type) bfd_get_reloc_size (howto);
buf = (bfd_byte *) bfd_zmalloc (size);
case bfd_reloc_overflow:
if (link_order->type == bfd_section_reloc_link_order)
- sym_name = bfd_section_name (output_bfd,
- link_order->u.reloc.p->u.section);
+ sym_name = bfd_section_name (link_order->u.reloc.p->u.section);
else
sym_name = link_order->u.reloc.p->u.name;
(*info->callbacks->reloc_overflow) (info, NULL, sym_name,
break;
}
+ octets = link_order->offset * bfd_octets_per_byte (output_bfd,
+ output_section);
ok = bfd_set_section_contents (output_bfd, output_section, buf,
- link_order->offset
- * bfd_octets_per_byte (output_bfd),
- size);
+ octets, size);
free (buf);
if (! ok)
return FALSE;
}
-/* Get the output vma of the section pointed to by the sh_link field. */
-
-static bfd_vma
-elf_get_linked_section_vma (struct bfd_link_order *p)
-{
- Elf_Internal_Shdr **elf_shdrp;
- asection *s;
- int elfsec;
-
- s = p->u.indirect.section;
- elf_shdrp = elf_elfsections (s->owner);
- elfsec = _bfd_elf_section_from_bfd_section (s->owner, s);
- elfsec = elf_shdrp[elfsec]->sh_link;
- /* PR 290:
- The Intel C compiler generates SHT_IA_64_UNWIND with
- SHF_LINK_ORDER. But it doesn't set the sh_link or
- sh_info fields. Hence we could get the situation
- where elfsec is 0. */
- if (elfsec == 0)
- {
- const struct elf_backend_data *bed
- = get_elf_backend_data (s->owner);
- if (bed->link_order_error_handler)
- bed->link_order_error_handler
- /* xgettext:c-format */
- (_("%pB: warning: sh_link not set for section `%pA'"), s->owner, s);
- return 0;
- }
- else
- {
- s = elf_shdrp[elfsec]->bfd_section;
- return s->output_section->vma + s->output_offset;
- }
-}
-
-
/* Compare two sections based on the locations of the sections they are
linked to. Used by elf_fixup_link_order. */
static int
-compare_link_order (const void * a, const void * b)
+compare_link_order (const void *a, const void *b)
{
- bfd_vma apos;
- bfd_vma bpos;
+ const struct bfd_link_order *alo = *(const struct bfd_link_order **) a;
+ const struct bfd_link_order *blo = *(const struct bfd_link_order **) b;
+ asection *asec = elf_linked_to_section (alo->u.indirect.section);
+ asection *bsec = elf_linked_to_section (blo->u.indirect.section);
+ bfd_vma apos = asec->output_section->lma + asec->output_offset;
+ bfd_vma bpos = bsec->output_section->lma + bsec->output_offset;
+
+ if (apos < bpos)
+ return -1;
+ if (apos > bpos)
+ return 1;
+
+ /* The only way we should get matching LMAs is when the first of two
+ sections has zero size. */
+ if (asec->size < bsec->size)
+ return -1;
+ if (asec->size > bsec->size)
+ return 1;
- apos = elf_get_linked_section_vma (*(struct bfd_link_order **)a);
- bpos = elf_get_linked_section_vma (*(struct bfd_link_order **)b);
+ /* If they are both zero size then they almost certainly have the same
+ VMA and thus are not ordered with respect to each other. Test VMA
+ anyway, and fall back to id to make the result reproducible across
+ qsort implementations. */
+ apos = asec->output_section->vma + asec->output_offset;
+ bpos = bsec->output_section->vma + bsec->output_offset;
if (apos < bpos)
return -1;
- return apos > bpos;
+ if (apos > bpos)
+ return 1;
+
+ return asec->id - bsec->id;
}
static bfd_boolean
elf_fixup_link_order (bfd *abfd, asection *o)
{
- int seen_linkorder;
- int seen_other;
- int n;
+ size_t seen_linkorder;
+ size_t seen_other;
+ size_t n;
struct bfd_link_order *p;
bfd *sub;
- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- unsigned elfsec;
struct bfd_link_order **sections;
asection *s, *other_sec, *linkorder_sec;
bfd_vma offset;
{
s = p->u.indirect.section;
sub = s->owner;
- if (bfd_get_flavour (sub) == bfd_target_elf_flavour
- && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass
- && (elfsec = _bfd_elf_section_from_bfd_section (sub, s))
- && elfsec < elf_numsections (sub)
- && elf_elfsections (sub)[elfsec]->sh_flags & SHF_LINK_ORDER
- && elf_elfsections (sub)[elfsec]->sh_link < elf_numsections (sub))
+ if ((s->flags & SEC_LINKER_CREATED) == 0
+ && bfd_get_flavour (sub) == bfd_target_elf_flavour
+ && elf_section_data (s) != NULL
+ && elf_linked_to_section (s) != NULL)
{
seen_linkorder++;
linkorder_sec = s;
if (!seen_linkorder)
return TRUE;
- sections = (struct bfd_link_order **)
- bfd_malloc (seen_linkorder * sizeof (struct bfd_link_order *));
+ sections = bfd_malloc (seen_linkorder * sizeof (*sections));
if (sections == NULL)
return FALSE;
- seen_linkorder = 0;
+ seen_linkorder = 0;
for (p = o->map_head.link_order; p != NULL; p = p->next)
- {
- sections[seen_linkorder++] = p;
- }
+ sections[seen_linkorder++] = p;
+
/* Sort the input sections in the order of their linked section. */
- qsort (sections, seen_linkorder, sizeof (struct bfd_link_order *),
- compare_link_order);
+ qsort (sections, seen_linkorder, sizeof (*sections), compare_link_order);
/* Change the offsets of the sections. */
offset = 0;
for (n = 0; n < seen_linkorder; n++)
{
+ bfd_vma mask;
s = sections[n]->u.indirect.section;
- offset &= ~(bfd_vma) 0 << s->alignment_power;
- s->output_offset = offset / bfd_octets_per_byte (abfd);
+ mask = ~(bfd_vma) 0 << s->alignment_power;
+ offset = (offset + ~mask) & mask;
+ s->output_offset = offset / bfd_octets_per_byte (abfd, s);
sections[n]->offset = offset;
offset += sections[n]->size;
}
return FALSE;
/* Read in the symbol table. */
- sympp = (asymbol **) xmalloc (symsize);
+ sympp = (asymbol **) bfd_malloc (symsize);
+ if (sympp == NULL)
+ return FALSE;
+
symcount = bfd_canonicalize_symtab (abfd, sympp);
if (symcount < 0)
goto free_sym_buf;
/* Make symbols absolute. */
osymbuf = (elf_symbol_type *) bfd_alloc2 (implib_bfd, symcount,
sizeof (*osymbuf));
+ if (osymbuf == NULL)
+ goto free_sym_buf;
+
for (src_count = 0; src_count < symcount; src_count++)
{
memcpy (&osymbuf[src_count], (elf_symbol_type *) sympp[src_count],
free (flinfo->indices);
if (flinfo->sections != NULL)
free (flinfo->sections);
- if (flinfo->symshndxbuf != NULL)
+ if (flinfo->symshndxbuf != NULL
+ && flinfo->symshndxbuf != (Elf_External_Sym_Shndx *) -1)
free (flinfo->symshndxbuf);
for (o = obfd->sections; o != NULL; o = o->next)
{
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
- secton. */
+ section. */
+ sections_removed = FALSE;
std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section;
for (o = abfd->sections; o != NULL; o = o->next)
{
}
attr_size = bfd_elf_obj_attr_size (abfd);
- bfd_set_section_size (abfd, o, attr_size);
+ bfd_set_section_size (o, attr_size);
/* Skip this section later on. */
o->map_head.link_order = NULL;
if (attr_size)
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
/* Figure out the file positions for everything but the symbol table
and the relocs. We set symcount to force assign_section_numbers
to create a symbol table. */
- bfd_get_symcount (abfd) = info->strip != strip_all || emit_relocs;
+ abfd->symcount = info->strip != strip_all || emit_relocs;
BFD_ASSERT (! abfd->output_has_begun);
if (! _bfd_elf_compute_section_file_positions (abfd, info))
goto error_return;
goto error_return;
}
+ /* _bfd_elf_compute_section_file_positions makes temporary use
+ of target_index. Reset it. */
+ o->target_index = 0;
+
/* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
to count upwards while actually outputting the relocations. */
esdo->rel.count = 0;
esdo->rela.count = 0;
- if (esdo->this_hdr.sh_offset == (file_ptr) -1)
+ if ((esdo->this_hdr.sh_offset == (file_ptr) -1)
+ && !bfd_section_is_ctf (o))
{
/* Cache the section contents so that they can be compressed
later. Use bfd_malloc since it will be freed by
}
}
- /* We have now assigned file positions for all the sections except
- .symtab, .strtab, and non-loaded reloc sections. We start the
- .symtab section at the current file position, and write directly
- to it. We build the .strtab section in memory. */
- bfd_get_symcount (abfd) = 0;
+ /* We have now assigned file positions for all the sections except .symtab,
+ .strtab, and non-loaded reloc and compressed debugging sections. We start
+ the .symtab section at the current file position, and write directly to it.
+ We build the .strtab section in memory. */
+ abfd->symcount = 0;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
/* sh_name is set in prep_headers. */
symtab_hdr->sh_type = SHT_SYMTAB;
continue;
if (strcmp (o->name, ".dynstr") != 0)
{
- if (! bfd_set_section_contents (abfd, o->output_section,
- o->contents,
- (file_ptr) o->output_offset
- * bfd_octets_per_byte (abfd),
- o->size))
+ bfd_size_type octets = ((file_ptr) o->output_offset
+ * bfd_octets_per_byte (abfd, o));
+ if (!bfd_set_section_contents (abfd, o->output_section,
+ o->contents, octets, o->size))
goto error_return;
}
else
if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
goto error_return;
- elf_final_link_free (abfd, &flinfo);
+ if (info->callbacks->emit_ctf)
+ info->callbacks->emit_ctf ();
- elf_linker (abfd) = TRUE;
+ elf_final_link_free (abfd, &flinfo);
if (attr_section)
{
for (sec = ibfd->sections; sec; sec = sec->next)
{
- if (CONST_STRNEQ (bfd_section_name (ibfd, sec), ".eh_frame_entry")
+ if (CONST_STRNEQ (bfd_section_name (sec), ".eh_frame_entry")
&& init_reloc_cookie_rels (&cookie, info, ibfd, sec))
{
_bfd_elf_parse_eh_frame_entry (info, sec, &cookie);
/* Called from check_relocs to record the existence of a VTENTRY reloc. */
bfd_boolean
-bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec ATTRIBUTE_UNUSED,
+bfd_elf_gc_record_vtentry (bfd *abfd, asection *sec,
struct elf_link_hash_entry *h,
bfd_vma addend)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
unsigned int log_file_align = bed->s->log_file_align;
+ if (!h)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: section '%pA': corrupt VTENTRY entry"),
+ abfd, sec);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
if (!h->u2.vtable)
{
h->u2.vtable = ((struct elf_link_virtual_table_entry *)
bfd_boolean is_rela)
{
char *name;
- const char *old_name = bfd_get_section_name (NULL, sec);
+ const char *old_name = bfd_section_name (sec);
const char *prefix = is_rela ? ".rela" : ".rel";
if (old_name == NULL)
section named "auto" we'll get ".relauto" which is
seen to be a .rela section. */
elf_section_type (reloc_sec) = is_rela ? SHT_RELA : SHT_REL;
- if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment))
+ if (!bfd_set_section_alignment (reloc_sec, alignment))
reloc_sec = NULL;
}
}