blob: 9fe031da963a0207a90e5d451464608b769d841e [file] [log] [blame]
/* ELF executable support for BFD.
Copyright (C) 1993-2024 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
SECTION
ELF backends
BFD support for ELF formats is being worked on.
Currently, the best supported back ends are for sparc and i386
(running svr4 or Solaris 2).
Documentation of the internals of the support code still needs
to be written. The code is changing quickly enough that we
haven't bothered yet. */
/* For sparc64-cross-sparc32. */
#define _SYSCALL32
#include "sysdep.h"
#include <limits.h>
#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#define ARCH_SIZE 0
#include "elf-bfd.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "elf-linux-core.h"
#ifdef CORE_HEADER
#include CORE_HEADER
#endif
static int elf_sort_sections (const void *, const void *);
static bool assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
static bool swap_out_syms (bfd *, struct elf_strtab_hash **, int,
struct bfd_link_info *);
static bool elf_parse_notes (bfd *abfd, char *buf, size_t size,
file_ptr offset, size_t align);
/* Swap version information in and out. The version information is
currently size independent. If that ever changes, this code will
need to move into elfcode.h. */
/* Swap in a Verdef structure. */
void
_bfd_elf_swap_verdef_in (bfd *abfd,
const Elf_External_Verdef *src,
Elf_Internal_Verdef *dst)
{
dst->vd_version = H_GET_16 (abfd, src->vd_version);
dst->vd_flags = H_GET_16 (abfd, src->vd_flags);
dst->vd_ndx = H_GET_16 (abfd, src->vd_ndx);
dst->vd_cnt = H_GET_16 (abfd, src->vd_cnt);
dst->vd_hash = H_GET_32 (abfd, src->vd_hash);
dst->vd_aux = H_GET_32 (abfd, src->vd_aux);
dst->vd_next = H_GET_32 (abfd, src->vd_next);
}
/* Swap out a Verdef structure. */
void
_bfd_elf_swap_verdef_out (bfd *abfd,
const Elf_Internal_Verdef *src,
Elf_External_Verdef *dst)
{
H_PUT_16 (abfd, src->vd_version, dst->vd_version);
H_PUT_16 (abfd, src->vd_flags, dst->vd_flags);
H_PUT_16 (abfd, src->vd_ndx, dst->vd_ndx);
H_PUT_16 (abfd, src->vd_cnt, dst->vd_cnt);
H_PUT_32 (abfd, src->vd_hash, dst->vd_hash);
H_PUT_32 (abfd, src->vd_aux, dst->vd_aux);
H_PUT_32 (abfd, src->vd_next, dst->vd_next);
}
/* Swap in a Verdaux structure. */
void
_bfd_elf_swap_verdaux_in (bfd *abfd,
const Elf_External_Verdaux *src,
Elf_Internal_Verdaux *dst)
{
dst->vda_name = H_GET_32 (abfd, src->vda_name);
dst->vda_next = H_GET_32 (abfd, src->vda_next);
}
/* Swap out a Verdaux structure. */
void
_bfd_elf_swap_verdaux_out (bfd *abfd,
const Elf_Internal_Verdaux *src,
Elf_External_Verdaux *dst)
{
H_PUT_32 (abfd, src->vda_name, dst->vda_name);
H_PUT_32 (abfd, src->vda_next, dst->vda_next);
}
/* Swap in a Verneed structure. */
void
_bfd_elf_swap_verneed_in (bfd *abfd,
const Elf_External_Verneed *src,
Elf_Internal_Verneed *dst)
{
dst->vn_version = H_GET_16 (abfd, src->vn_version);
dst->vn_cnt = H_GET_16 (abfd, src->vn_cnt);
dst->vn_file = H_GET_32 (abfd, src->vn_file);
dst->vn_aux = H_GET_32 (abfd, src->vn_aux);
dst->vn_next = H_GET_32 (abfd, src->vn_next);
}
/* Swap out a Verneed structure. */
void
_bfd_elf_swap_verneed_out (bfd *abfd,
const Elf_Internal_Verneed *src,
Elf_External_Verneed *dst)
{
H_PUT_16 (abfd, src->vn_version, dst->vn_version);
H_PUT_16 (abfd, src->vn_cnt, dst->vn_cnt);
H_PUT_32 (abfd, src->vn_file, dst->vn_file);
H_PUT_32 (abfd, src->vn_aux, dst->vn_aux);
H_PUT_32 (abfd, src->vn_next, dst->vn_next);
}
/* Swap in a Vernaux structure. */
void
_bfd_elf_swap_vernaux_in (bfd *abfd,
const Elf_External_Vernaux *src,
Elf_Internal_Vernaux *dst)
{
dst->vna_hash = H_GET_32 (abfd, src->vna_hash);
dst->vna_flags = H_GET_16 (abfd, src->vna_flags);
dst->vna_other = H_GET_16 (abfd, src->vna_other);
dst->vna_name = H_GET_32 (abfd, src->vna_name);
dst->vna_next = H_GET_32 (abfd, src->vna_next);
}
/* Swap out a Vernaux structure. */
void
_bfd_elf_swap_vernaux_out (bfd *abfd,
const Elf_Internal_Vernaux *src,
Elf_External_Vernaux *dst)
{
H_PUT_32 (abfd, src->vna_hash, dst->vna_hash);
H_PUT_16 (abfd, src->vna_flags, dst->vna_flags);
H_PUT_16 (abfd, src->vna_other, dst->vna_other);
H_PUT_32 (abfd, src->vna_name, dst->vna_name);
H_PUT_32 (abfd, src->vna_next, dst->vna_next);
}
/* Swap in a Versym structure. */
void
_bfd_elf_swap_versym_in (bfd *abfd,
const Elf_External_Versym *src,
Elf_Internal_Versym *dst)
{
dst->vs_vers = H_GET_16 (abfd, src->vs_vers);
}
/* Swap out a Versym structure. */
void
_bfd_elf_swap_versym_out (bfd *abfd,
const Elf_Internal_Versym *src,
Elf_External_Versym *dst)
{
H_PUT_16 (abfd, src->vs_vers, dst->vs_vers);
}
/* Standard ELF hash function. Do not change this function; you will
cause invalid hash tables to be generated. */
unsigned long
bfd_elf_hash (const char *namearg)
{
uint32_t h = 0;
for (const unsigned char *name = (const unsigned char *) namearg;
*name; name++)
{
h = (h << 4) + *name;
h ^= (h >> 24) & 0xf0;
}
return h & 0x0fffffff;
}
/* DT_GNU_HASH hash function. Do not change this function; you will
cause invalid hash tables to be generated. */
unsigned long
bfd_elf_gnu_hash (const char *namearg)
{
uint32_t h = 5381;
for (const unsigned char *name = (const unsigned char *) namearg;
*name; name++)
h = (h << 5) + h + *name;
return h;
}
/* Create a tdata field OBJECT_SIZE bytes in length, zeroed out and with
the object_id field of an elf_obj_tdata field set to OBJECT_ID. */
bool
bfd_elf_allocate_object (bfd *abfd,
size_t object_size,
enum elf_target_id object_id)
{
BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata));
abfd->tdata.any = bfd_zalloc (abfd, object_size);
if (abfd->tdata.any == NULL)
return false;
elf_object_id (abfd) = object_id;
if (abfd->direction != read_direction)
{
struct output_elf_obj_tdata *o = bfd_zalloc (abfd, sizeof *o);
if (o == NULL)
return false;
elf_tdata (abfd)->o = o;
elf_program_header_size (abfd) = (bfd_size_type) -1;
}
return true;
}
bool
bfd_elf_make_object (bfd *abfd)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
bed->target_id);
}
bool
bfd_elf_mkcorefile (bfd *abfd)
{
/* I think this can be done just like an object file. */
if (!abfd->xvec->_bfd_set_format[(int) bfd_object] (abfd))
return false;
elf_tdata (abfd)->core = bfd_zalloc (abfd, sizeof (*elf_tdata (abfd)->core));
return elf_tdata (abfd)->core != NULL;
}
char *
bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
{
Elf_Internal_Shdr **i_shdrp;
bfd_byte *shstrtab = NULL;
file_ptr offset;
bfd_size_type shstrtabsize;
i_shdrp = elf_elfsections (abfd);
if (i_shdrp == 0
|| shindex >= elf_numsections (abfd)
|| i_shdrp[shindex] == 0)
return NULL;
shstrtab = i_shdrp[shindex]->contents;
if (shstrtab == NULL)
{
/* No cached one, attempt to read, and cache what we read. */
offset = i_shdrp[shindex]->sh_offset;
shstrtabsize = i_shdrp[shindex]->sh_size;
if (shstrtabsize == 0
|| bfd_seek (abfd, offset, SEEK_SET) != 0
|| (shstrtab
= _bfd_mmap_readonly_persistent (abfd, shstrtabsize)) == NULL)
{
/* Once we've failed to read it, make sure we don't keep
trying. Otherwise, we'll keep allocating space for
the string table over and over. */
i_shdrp[shindex]->sh_size = 0;
}
else if (shstrtab[shstrtabsize - 1] != 0)
{
/* It is an error if a string table isn't terminated. */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: string table [%u] is corrupt"), abfd, shindex);
shstrtab[shstrtabsize - 1] = 0;
}
i_shdrp[shindex]->contents = shstrtab;
}
return (char *) shstrtab;
}
char *
bfd_elf_string_from_elf_section (bfd *abfd,
unsigned int shindex,
unsigned int strindex)
{
Elf_Internal_Shdr *hdr;
if (strindex == 0)
return "";
if (elf_elfsections (abfd) == NULL || shindex >= elf_numsections (abfd))
return NULL;
hdr = elf_elfsections (abfd)[shindex];
if (hdr->contents == NULL)
{
if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS)
{
/* PR 17512: file: f057ec89. */
/* xgettext:c-format */
_bfd_error_handler (_("%pB: attempt to load strings from"
" a non-string section (number %d)"),
abfd, shindex);
return NULL;
}
if (bfd_elf_get_str_section (abfd, shindex) == NULL)
return NULL;
}
else
{
/* PR 24273: The string section's contents may have already
been loaded elsewhere, eg because a corrupt file has the
string section index in the ELF header pointing at a group
section. So be paranoid, and test that the last byte of
the section is zero. */
if (hdr->sh_size == 0 || hdr->contents[hdr->sh_size - 1] != 0)
return NULL;
}
if (strindex >= hdr->sh_size)
{
unsigned int shstrndx = elf_elfheader(abfd)->e_shstrndx;
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: invalid string offset %u >= %" PRIu64 " for section `%s'"),
abfd, strindex, (uint64_t) hdr->sh_size,
(shindex == shstrndx && strindex == hdr->sh_name
? ".shstrtab"
: bfd_elf_string_from_elf_section (abfd, shstrndx, hdr->sh_name)));
return NULL;
}
return ((char *) hdr->contents) + strindex;
}
/* Read and convert symbols to internal format.
SYMCOUNT specifies the number of symbols to read, starting from
symbol SYMOFFSET. If any of INTSYM_BUF, EXTSYM_BUF or EXTSHNDX_BUF
are non-NULL, they are used to store the internal symbols, external
symbols, and symbol section index extensions, respectively.
Returns a pointer to the internal symbol buffer (malloced if necessary)
or NULL if there were no symbols or some kind of problem. */
Elf_Internal_Sym *
bfd_elf_get_elf_syms (bfd *ibfd,
Elf_Internal_Shdr *symtab_hdr,
size_t symcount,
size_t symoffset,
Elf_Internal_Sym *intsym_buf,
void *extsym_buf,
Elf_External_Sym_Shndx *extshndx_buf)
{
Elf_Internal_Shdr *shndx_hdr;
void *alloc_ext;
const bfd_byte *esym;
Elf_External_Sym_Shndx *alloc_extshndx;
Elf_External_Sym_Shndx *shndx;
Elf_Internal_Sym *alloc_intsym;
Elf_Internal_Sym *isym;
Elf_Internal_Sym *isymend;
const struct elf_backend_data *bed;
size_t extsym_size;
size_t amt;
file_ptr pos;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
abort ();
if (symcount == 0)
return intsym_buf;
if (elf_use_dt_symtab_p (ibfd))
{
/* Use dynamic symbol table. */
if (elf_tdata (ibfd)->dt_symtab_count != symcount + symoffset)
{
bfd_set_error (bfd_error_invalid_operation);
return NULL;
}
return elf_tdata (ibfd)->dt_symtab + symoffset;
}
/* Normal syms might have section extension entries. */
shndx_hdr = NULL;
if (elf_symtab_shndx_list (ibfd) != NULL)
{
elf_section_list * entry;
Elf_Internal_Shdr **sections = elf_elfsections (ibfd);
/* Find an index section that is linked to this symtab section. */
for (entry = elf_symtab_shndx_list (ibfd); entry != NULL; entry = entry->next)
{
/* PR 20063. */
if (entry->hdr.sh_link >= elf_numsections (ibfd))
continue;
if (sections[entry->hdr.sh_link] == symtab_hdr)
{
shndx_hdr = & entry->hdr;
break;
};
}
if (shndx_hdr == NULL)
{
if (symtab_hdr == &elf_symtab_hdr (ibfd))
/* Not really accurate, but this was how the old code used
to work. */
shndx_hdr = &elf_symtab_shndx_list (ibfd)->hdr;
/* Otherwise we do nothing. The assumption is that
the index table will not be needed. */
}
}
/* Read the symbols. */
alloc_ext = NULL;
alloc_extshndx = NULL;
alloc_intsym = NULL;
bed = get_elf_backend_data (ibfd);
extsym_size = bed->s->sizeof_sym;
if (_bfd_mul_overflow (symcount, extsym_size, &amt))
{
bfd_set_error (bfd_error_file_too_big);
return NULL;
}
pos = symtab_hdr->sh_offset + symoffset * extsym_size;
size_t alloc_ext_size = amt;
if (bfd_seek (ibfd, pos, SEEK_SET) != 0
|| !_bfd_mmap_read_temporary (&extsym_buf, &alloc_ext_size,
&alloc_ext, ibfd, false))
{
intsym_buf = NULL;
goto out2;
}
size_t alloc_extshndx_size = 0;
if (shndx_hdr == NULL || shndx_hdr->sh_size == 0)
extshndx_buf = NULL;
else
{
if (_bfd_mul_overflow (symcount, sizeof (Elf_External_Sym_Shndx), &amt))
{
bfd_set_error (bfd_error_file_too_big);
intsym_buf = NULL;
goto out1;
}
alloc_extshndx_size = amt;
pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
if (bfd_seek (ibfd, pos, SEEK_SET) != 0
|| !_bfd_mmap_read_temporary ((void **) &extshndx_buf,
&alloc_extshndx_size,
(void **) &alloc_extshndx,
ibfd, false))
{
intsym_buf = NULL;
goto out1;
}
}
if (intsym_buf == NULL)
{
if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt))
{
bfd_set_error (bfd_error_file_too_big);
goto out1;
}
alloc_intsym = (Elf_Internal_Sym *) bfd_malloc (amt);
intsym_buf = alloc_intsym;
if (intsym_buf == NULL)
goto out1;
}
/* Convert the symbols to internal form. */
isymend = intsym_buf + symcount;
for (esym = (const bfd_byte *) extsym_buf, isym = intsym_buf,
shndx = extshndx_buf;
isym < isymend;
esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL)
if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym))
{
symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size;
/* xgettext:c-format */
_bfd_error_handler (_("%pB symbol number %lu references"
" nonexistent SHT_SYMTAB_SHNDX section"),
ibfd, (unsigned long) symoffset);
free (alloc_intsym);
intsym_buf = NULL;
goto out1;
}
out1:
_bfd_munmap_readonly_temporary (alloc_extshndx, alloc_extshndx_size);
out2:
_bfd_munmap_readonly_temporary (alloc_ext, alloc_ext_size);
return intsym_buf;
}
/* Look up a symbol name. */
const char *
bfd_elf_sym_name (bfd *abfd,
Elf_Internal_Shdr *symtab_hdr,
Elf_Internal_Sym *isym,
asection *sym_sec)
{
const char *name;
unsigned int iname = isym->st_name;
unsigned int shindex = symtab_hdr->sh_link;
if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION
/* Check for a bogus st_shndx to avoid crashing. */
&& isym->st_shndx < elf_numsections (abfd))
{
iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name;
shindex = elf_elfheader (abfd)->e_shstrndx;
}
name = bfd_elf_string_from_elf_section (abfd, shindex, iname);
if (name == NULL)
name = "(null)";
else if (sym_sec && *name == '\0')
name = bfd_section_name (sym_sec);
return name;
}
/* Return the name of the group signature symbol. Why isn't the
signature just a string? */
static const char *
group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr)
{
Elf_Internal_Shdr *hdr;
unsigned char esym[sizeof (Elf64_External_Sym)];
Elf_External_Sym_Shndx eshndx;
Elf_Internal_Sym isym;
/* First we need to ensure the symbol table is available. Make sure
that it is a symbol table section. */
if (ghdr->sh_link >= elf_numsections (abfd))
return NULL;
hdr = elf_elfsections (abfd) [ghdr->sh_link];
if (hdr->sh_type != SHT_SYMTAB
|| ! bfd_section_from_shdr (abfd, ghdr->sh_link))
return NULL;
/* Go read the symbol. */
hdr = &elf_tdata (abfd)->symtab_hdr;
if (bfd_elf_get_elf_syms (abfd, hdr, 1, ghdr->sh_info,
&isym, esym, &eshndx) == NULL)
return NULL;
return bfd_elf_sym_name (abfd, hdr, &isym, NULL);
}
static bool
is_valid_group_section_header (Elf_Internal_Shdr *shdr, size_t minsize)
{
return (shdr->sh_size >= minsize
&& shdr->sh_entsize == GRP_ENTRY_SIZE
&& shdr->sh_size % GRP_ENTRY_SIZE == 0
&& shdr->bfd_section != NULL);
}
/* Set next_in_group, sec_group list pointers, and group names. */
static bool
process_sht_group_entries (bfd *abfd,
Elf_Internal_Shdr *ghdr, unsigned int gidx)
{
unsigned char *contents;
/* Read the raw contents. */
if (!bfd_malloc_and_get_section (abfd, ghdr->bfd_section, &contents))
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: could not read contents of group [%u]"), abfd, gidx);
return false;
}
asection *last_elt = NULL;
const char *gname = NULL;
unsigned char *p = contents + ghdr->sh_size;
while (1)
{
unsigned int idx;
Elf_Internal_Shdr *shdr;
asection *elt;
p -= 4;
idx = H_GET_32 (abfd, p);
if (p == contents)
{
if ((idx & GRP_COMDAT) != 0)
ghdr->bfd_section->flags
|= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
break;
}
if (idx == 0
|| idx >= elf_numsections (abfd)
|| (shdr = elf_elfsections (abfd)[idx])->sh_type == SHT_GROUP
|| ((elt = shdr->bfd_section) != NULL
&& elf_sec_group (elt) != NULL
&& elf_sec_group (elt) != ghdr->bfd_section))
{
_bfd_error_handler
(_("%pB: invalid entry (%#x) in group [%u]"),
abfd, idx, gidx);
continue;
}
/* PR binutils/23199: According to the ELF gABI all sections in
a group must be marked with SHF_GROUP, but some tools
generate broken objects. Fix them up here. */
shdr->sh_flags |= SHF_GROUP;
if (elt == NULL)
{
if (shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL)
{
const char *name = bfd_elf_string_from_elf_section
(abfd, elf_elfheader (abfd)->e_shstrndx, shdr->sh_name);
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: unexpected type (%#x) section `%s' in group [%u]"),
abfd, shdr->sh_type, name, gidx);
}
continue;
}
/* Don't try to add a section to elf_next_in_group list twice. */
if (elf_sec_group (elt) != NULL)
continue;
if (last_elt == NULL)
{
/* Start a circular list with one element.
It will be in reverse order to match what gas does. */
elf_next_in_group (elt) = elt;
/* Point the group section to it. */
elf_next_in_group (ghdr->bfd_section) = elt;
gname = group_signature (abfd, ghdr);
if (gname == NULL)
{
free (contents);
return false;
}
}
else
{
elf_next_in_group (elt) = elf_next_in_group (last_elt);
elf_next_in_group (last_elt) = elt;
}
last_elt = elt;
elf_group_name (elt) = gname;
elf_sec_group (elt) = ghdr->bfd_section;
}
free (contents);
return true;
}
bool
_bfd_elf_setup_sections (bfd *abfd)
{
bool result = true;
/* Process SHF_LINK_ORDER. */
for (asection *s = abfd->sections; s != NULL; s = s->next)
{
Elf_Internal_Shdr *this_hdr = &elf_section_data (s)->this_hdr;
if ((this_hdr->sh_flags & SHF_LINK_ORDER) != 0)
{
unsigned int elfsec = this_hdr->sh_link;
/* An sh_link value of 0 is now allowed. It indicates that linked
to section has already been discarded, but that the current
section has been retained for some other reason. This linking
section is still a candidate for later garbage collection
however. */
if (elfsec == 0)
{
elf_linked_to_section (s) = NULL;
}
else
{
asection *linksec = NULL;
if (elfsec < elf_numsections (abfd))
{
this_hdr = elf_elfsections (abfd)[elfsec];
linksec = this_hdr->bfd_section;
}
/* PR 1991, 2008:
Some strip/objcopy may leave an incorrect value in
sh_link. We don't want to proceed. */
if (linksec == NULL)
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: sh_link [%d] in section `%pA' is incorrect"),
s->owner, elfsec, s);
result = false;
}
elf_linked_to_section (s) = linksec;
}
}
}
/* Process section groups. */
for (unsigned int i = 1; i < elf_numsections (abfd); i++)
{
Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
if (shdr && shdr->sh_type == SHT_GROUP)
{
if (is_valid_group_section_header (shdr, GRP_ENTRY_SIZE))
{
if (shdr->sh_size >= 2 * GRP_ENTRY_SIZE
&& !process_sht_group_entries (abfd, shdr, i))
result = false;
}
else
{
/* PR binutils/18758: Beware of corrupt binaries with
invalid group data. */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: section group entry number %u is corrupt"), abfd, i);
result = false;
}
}
}
return result;
}
bool
bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
{
return elf_next_in_group (sec) != NULL;
}
const char *
bfd_elf_group_name (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
{
if (elf_sec_group (sec) != NULL)
return elf_group_name (sec);
return NULL;
}
/* Make a BFD section from an ELF section. We store a pointer to the
BFD section in the bfd_section field of the header. */
bool
_bfd_elf_make_section_from_shdr (bfd *abfd,
Elf_Internal_Shdr *hdr,
const char *name,
int shindex)
{
asection *newsect;
flagword flags;
const struct elf_backend_data *bed;
unsigned int opb = bfd_octets_per_byte (abfd, NULL);
if (hdr->bfd_section != NULL)
return true;
newsect = bfd_make_section_anyway (abfd, name);
if (newsect == NULL)
return false;
hdr->bfd_section = newsect;
elf_section_data (newsect)->this_hdr = *hdr;
elf_section_data (newsect)->this_idx = shindex;
/* Always use the real type/flags. */
elf_section_type (newsect) = hdr->sh_type;
elf_section_flags (newsect) = hdr->sh_flags;
newsect->filepos = hdr->sh_offset;
flags = SEC_NO_FLAGS;
if (hdr->sh_type != SHT_NOBITS)
flags |= SEC_HAS_CONTENTS;
if (hdr->sh_type == SHT_GROUP)
flags |= SEC_GROUP;
if ((hdr->sh_flags & SHF_ALLOC) != 0)
{
flags |= SEC_ALLOC;
if (hdr->sh_type != SHT_NOBITS)
flags |= SEC_LOAD;
}
if ((hdr->sh_flags & SHF_WRITE) == 0)
flags |= SEC_READONLY;
if ((hdr->sh_flags & SHF_EXECINSTR) != 0)
flags |= SEC_CODE;
else if ((flags & SEC_LOAD) != 0)
flags |= SEC_DATA;
if ((hdr->sh_flags & SHF_MERGE) != 0)
{
flags |= SEC_MERGE;
newsect->entsize = hdr->sh_entsize;
}
if ((hdr->sh_flags & SHF_STRINGS) != 0)
flags |= SEC_STRINGS;
if ((hdr->sh_flags & SHF_TLS) != 0)
flags |= SEC_THREAD_LOCAL;
if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
flags |= SEC_EXCLUDE;
switch (elf_elfheader (abfd)->e_ident[EI_OSABI])
{
/* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE,
but binutils as of 2019-07-23 did not set the EI_OSABI header
byte. */
case ELFOSABI_GNU:
case ELFOSABI_FREEBSD:
if ((hdr->sh_flags & SHF_GNU_RETAIN) != 0)
elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_retain;
/* Fall through */
case ELFOSABI_NONE:
if ((hdr->sh_flags & SHF_GNU_MBIND) != 0)
elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind;
break;
}
if ((flags & SEC_ALLOC) == 0)
{
/* The debugging sections appear to be recognized only by name,
not any sort of flag. Their SEC_ALLOC bits are cleared. */
if (name [0] == '.')
{
if (startswith (name, ".debug")
|| startswith (name, ".gnu.debuglto_.debug_")
|| startswith (name, ".gnu.linkonce.wi.")
|| startswith (name, ".zdebug"))
flags |= SEC_DEBUGGING | SEC_ELF_OCTETS;
else if (startswith (name, GNU_BUILD_ATTRS_SECTION_NAME)
|| startswith (name, ".note.gnu"))
{
flags |= SEC_ELF_OCTETS;
opb = 1;
}
else if (startswith (name, ".line")
|| startswith (name, ".stab")
|| strcmp (name, ".gdb_index") == 0)
flags |= SEC_DEBUGGING;
}
}
if (!bfd_set_section_vma (newsect, hdr->sh_addr / opb)
|| !bfd_set_section_size (newsect, hdr->sh_size)
|| !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign
& -hdr->sh_addralign)))
return false;
/* As a GNU extension, if the name begins with .gnu.linkonce, we
only link a single copy of the section. This is used to support
g++. g++ will emit each template expansion in its own section.
The symbols will be defined as weak, so that multiple definitions
are permitted. The GNU linker extension is to actually discard
all but one of the sections. */
if (startswith (name, ".gnu.linkonce")
&& elf_next_in_group (newsect) == NULL)
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
if (!bfd_set_section_flags (newsect, flags))
return false;
bed = get_elf_backend_data (abfd);
if (bed->elf_backend_section_flags)
if (!bed->elf_backend_section_flags (hdr))
return false;
/* We do not parse the PT_NOTE segments as we are interested even in the
separate debug info files which may have the segments offsets corrupted.
PT_NOTEs from the core files are currently not parsed using BFD. */
if (hdr->sh_type == SHT_NOTE && hdr->sh_size != 0)
{
bfd_byte *contents;
if (!_bfd_elf_mmap_section_contents (abfd, newsect, &contents))
return false;
elf_parse_notes (abfd, (char *) contents, hdr->sh_size,
hdr->sh_offset, hdr->sh_addralign);
_bfd_elf_munmap_section_contents (newsect, contents);
}
if ((newsect->flags & SEC_ALLOC) != 0)
{
Elf_Internal_Phdr *phdr;
unsigned int i, nload;
/* Some ELF linkers produce binaries with all the program header
p_paddr fields zero. If we have such a binary with more than
one PT_LOAD header, then leave the section lma equal to vma
so that we don't create sections with overlapping lma. */
phdr = elf_tdata (abfd)->phdr;
for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
if (phdr->p_paddr != 0)
break;
else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0)
++nload;
if (i >= elf_elfheader (abfd)->e_phnum && nload > 1)
return true;
phdr = elf_tdata (abfd)->phdr;
for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
{
if (((phdr->p_type == PT_LOAD
&& (hdr->sh_flags & SHF_TLS) == 0)
|| phdr->p_type == PT_TLS)
&& ELF_SECTION_IN_SEGMENT (hdr, phdr))
{
if ((newsect->flags & SEC_LOAD) == 0)
newsect->lma = (phdr->p_paddr
+ hdr->sh_addr - phdr->p_vaddr) / opb;
else
/* We used to use the same adjustment for SEC_LOAD
sections, but that doesn't work if the segment
is packed with code from multiple VMAs.
Instead we calculate the section LMA based on
the segment LMA. It is assumed that the
segment will contain sections with contiguous
LMAs, even if the VMAs are not. */
newsect->lma = (phdr->p_paddr
+ hdr->sh_offset - phdr->p_offset) / opb;
/* With contiguous segments, we can't tell from file
offsets whether a section with zero size should
be placed at the end of one segment or the
beginning of the next. Decide based on vaddr. */
if (hdr->sh_addr >= phdr->p_vaddr
&& (hdr->sh_addr + hdr->sh_size
<= phdr->p_vaddr + phdr->p_memsz))
break;
}
}
}
/* Compress/decompress DWARF debug sections with names: .debug_*,
.zdebug_*, .gnu.debuglto_.debug_, after the section flags is set. */
if ((newsect->flags & SEC_DEBUGGING) != 0
&& (newsect->flags & SEC_HAS_CONTENTS) != 0
&& (newsect->flags & SEC_ELF_OCTETS) != 0)
{
enum { nothing, compress, decompress } action = nothing;
int compression_header_size;
bfd_size_type uncompressed_size;
unsigned int uncompressed_align_power;
enum compression_type ch_type = ch_none;
bool compressed
= bfd_is_section_compressed_info (abfd, newsect,
&compression_header_size,
&uncompressed_size,
&uncompressed_align_power,
&ch_type);
/* Should we decompress? */
if ((abfd->flags & BFD_DECOMPRESS) != 0 && compressed)
action = decompress;
/* Should we compress? Or convert to a different compression? */
else if ((abfd->flags & BFD_COMPRESS) != 0
&& newsect->size != 0
&& compression_header_size >= 0
&& uncompressed_size > 0)
{
if (!compressed)
action = compress;
else
{
enum compression_type new_ch_type = ch_none;
if ((abfd->flags & BFD_COMPRESS_GABI) != 0)
new_ch_type = ((abfd->flags & BFD_COMPRESS_ZSTD) != 0
? ch_compress_zstd : ch_compress_zlib);
if (new_ch_type != ch_type)
action = compress;
}
}
if (action == compress)
{
if (!bfd_init_section_compress_status (abfd, newsect))
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: unable to compress section %s"), abfd, name);
return false;
}
}
else if (action == decompress)
{
if (!bfd_init_section_decompress_status (abfd, newsect))
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: unable to decompress section %s"), abfd, name);
return false;
}
#ifndef HAVE_ZSTD
if (newsect->compress_status == DECOMPRESS_SECTION_ZSTD)
{
_bfd_error_handler
/* xgettext:c-format */
(_ ("%pB: section %s is compressed with zstd, but BFD "
"is not built with zstd support"),
abfd, name);
newsect->compress_status = COMPRESS_SECTION_NONE;
return false;
}
#endif
if (abfd->is_linker_input
&& name[1] == 'z')
{
/* Rename section from .zdebug_* to .debug_* so that ld
scripts will see this section as a debug section. */
char *new_name = bfd_zdebug_name_to_debug (abfd, name);
if (new_name == NULL)
return false;
bfd_rename_section (newsect, new_name);
}
}
}
return true;
}
const char *const bfd_elf_section_type_names[] =
{
"SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
"SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
"SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
};
/* ELF relocs are against symbols. If we are producing relocatable
output, and the reloc is against an external symbol, and nothing
has given us any additional addend, the resulting reloc will also
be against the same symbol. In such a case, we don't want to
change anything about the way the reloc is handled, since it will
all be done at final link time. Rather than put special case code
into bfd_perform_relocation, all the reloc types use this howto
function, or should call this function for relocatable output. */
bfd_reloc_status_type
bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED,
arelent *reloc_entry,
asymbol *symbol,
void *data ATTRIBUTE_UNUSED,
asection *input_section,
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
if (output_bfd != NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
&& (! reloc_entry->howto->partial_inplace
|| reloc_entry->addend == 0))
{
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
/* In some cases the relocation should be treated as output section
relative, as when linking ELF DWARF into PE COFF. Many ELF
targets lack section relative relocations and instead use
ordinary absolute relocations for references between DWARF
sections. That is arguably a bug in those targets but it happens
to work for the usual case of linking to non-loaded ELF debug
sections with VMAs forced to zero. PE COFF on the other hand
doesn't allow a section VMA of zero. */
if (output_bfd == NULL
&& !reloc_entry->howto->pc_relative
&& (symbol->section->flags & SEC_DEBUGGING) != 0
&& (input_section->flags & SEC_DEBUGGING) != 0)
reloc_entry->addend -= symbol->section->output_section->vma;
return bfd_reloc_continue;
}
/* Returns TRUE if section A matches section B.
Names, addresses and links may be different, but everything else
should be the same. */
static bool
section_match (const Elf_Internal_Shdr * a,
const Elf_Internal_Shdr * b)
{
if (a->sh_type != b->sh_type
|| ((a->sh_flags ^ b->sh_flags) & ~SHF_INFO_LINK) != 0
|| a->sh_addralign != b->sh_addralign
|| a->sh_entsize != b->sh_entsize)
return false;
if (a->sh_type == SHT_SYMTAB
|| a->sh_type == SHT_STRTAB)
return true;
return a->sh_size == b->sh_size;
}
/* Find a section in OBFD that has the same characteristics
as IHEADER. Return the index of this section or SHN_UNDEF if
none can be found. Check's section HINT first, as this is likely
to be the correct section. */
static unsigned int
find_link (const bfd *obfd, const Elf_Internal_Shdr *iheader,
const unsigned int hint)
{
Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd);
unsigned int i;
BFD_ASSERT (iheader != NULL);
/* See PR 20922 for a reproducer of the NULL test. */
if (hint < elf_numsections (obfd)
&& oheaders[hint] != NULL
&& section_match (oheaders[hint], iheader))
return hint;
for (i = 1; i < elf_numsections (obfd); i++)
{
Elf_Internal_Shdr * oheader = oheaders[i];
if (oheader == NULL)
continue;
if (section_match (oheader, iheader))
/* FIXME: Do we care if there is a potential for
multiple matches ? */
return i;
}
return SHN_UNDEF;
}
/* PR 19938: Attempt to set the ELF section header fields of an OS or
Processor specific section, based upon a matching input section.
Returns TRUE upon success, FALSE otherwise. */
static bool
copy_special_section_fields (const bfd *ibfd,
bfd *obfd,
const Elf_Internal_Shdr *iheader,
Elf_Internal_Shdr *oheader,
const unsigned int secnum)
{
const struct elf_backend_data *bed = get_elf_backend_data (obfd);
const Elf_Internal_Shdr **iheaders
= (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
bool changed = false;
unsigned int sh_link;
if (oheader->sh_type == SHT_NOBITS)
{
/* This is a feature for objcopy --only-keep-debug:
When a section's type is changed to NOBITS, we preserve
the sh_link and sh_info fields so that they can be
matched up with the original.
Note: Strictly speaking these assignments are wrong.
The sh_link and sh_info fields should point to the
relevent sections in the output BFD, which may not be in
the same location as they were in the input BFD. But
the whole point of this action is to preserve the
original values of the sh_link and sh_info fields, so
that they can be matched up with the section headers in
the original file. So strictly speaking we may be
creating an invalid ELF file, but it is only for a file
that just contains debug info and only for sections
without any contents. */
if (oheader->sh_link == 0)
oheader->sh_link = iheader->sh_link;
if (oheader->sh_info == 0)
oheader->sh_info = iheader->sh_info;
return true;
}
/* Allow the target a chance to decide how these fields should be set. */
if (bed->elf_backend_copy_special_section_fields (ibfd, obfd,
iheader, oheader))
return true;
/* We have an iheader which might match oheader, and which has non-zero
sh_info and/or sh_link fields. Attempt to follow those links and find
the section in the output bfd which corresponds to the linked section
in the input bfd. */
if (iheader->sh_link != SHN_UNDEF)
{
/* See PR 20931 for a reproducer. */
if (iheader->sh_link >= elf_numsections (ibfd))
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: invalid sh_link field (%d) in section number %d"),
ibfd, iheader->sh_link, secnum);
return false;
}
sh_link = find_link (obfd, iheaders[iheader->sh_link], iheader->sh_link);
if (sh_link != SHN_UNDEF)
{
oheader->sh_link = sh_link;
changed = true;
}
else
/* FIXME: Should we install iheader->sh_link
if we could not find a match ? */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: failed to find link section for section %d"), obfd, secnum);
}
if (iheader->sh_info)
{
/* The sh_info field can hold arbitrary information, but if the
SHF_LINK_INFO flag is set then it should be interpreted as a
section index. */
if (iheader->sh_flags & SHF_INFO_LINK)
{
sh_link = find_link (obfd, iheaders[iheader->sh_info],
iheader->sh_info);
if (sh_link != SHN_UNDEF)
oheader->sh_flags |= SHF_INFO_LINK;
}
else
/* No idea what it means - just copy it. */
sh_link = iheader->sh_info;
if (sh_link != SHN_UNDEF)
{
oheader->sh_info = sh_link;
changed = true;
}
else
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: failed to find info section for section %d"), obfd, secnum);
}
return changed;
}
/* Copy the program header and other data from one object module to
another. */
bool
_bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
{
const Elf_Internal_Shdr **iheaders
= (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
Elf_Internal_Shdr **oheaders = elf_elfsections (obfd);
const struct elf_backend_data *bed;
unsigned int i;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return true;
if (!elf_flags_init (obfd))
{
elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
elf_flags_init (obfd) = true;
}
elf_gp (obfd) = elf_gp (ibfd);
/* Also copy the EI_OSABI field. */
elf_elfheader (obfd)->e_ident[EI_OSABI] =
elf_elfheader (ibfd)->e_ident[EI_OSABI];
/* If set, copy the EI_ABIVERSION field. */
if (elf_elfheader (ibfd)->e_ident[EI_ABIVERSION])
elf_elfheader (obfd)->e_ident[EI_ABIVERSION]
= elf_elfheader (ibfd)->e_ident[EI_ABIVERSION];
/* Copy object attributes. */
_bfd_elf_copy_obj_attributes (ibfd, obfd);
if (iheaders == NULL || oheaders == NULL)
return true;
bed = get_elf_backend_data (obfd);
/* Possibly copy other fields in the section header. */
for (i = 1; i < elf_numsections (obfd); i++)
{
unsigned int j;
Elf_Internal_Shdr * oheader = oheaders[i];
/* Ignore ordinary sections. SHT_NOBITS sections are considered however
because of a special case need for generating separate debug info
files. See below for more details. */
if (oheader == NULL
|| (oheader->sh_type != SHT_NOBITS
&& oheader->sh_type < SHT_LOOS))
continue;
/* Ignore empty sections, and sections whose
fields have already been initialised. */
if (oheader->sh_size == 0
|| (oheader->sh_info != 0 && oheader->sh_link != 0))
continue;
/* Scan for the matching section in the input bfd.
First we try for a direct mapping between the input and
output sections. */
for (j = 1; j < elf_numsections (ibfd); j++)
{
const Elf_Internal_Shdr * iheader = iheaders[j];
if (iheader == NULL)
continue;
if (oheader->bfd_section != NULL
&& iheader->bfd_section != NULL
&& iheader->bfd_section->output_section != NULL
&& iheader->bfd_section->output_section == oheader->bfd_section)
{
/* We have found a connection from the input section to
the output section. Attempt to copy the header fields.
If this fails then do not try any further sections -
there should only be a one-to-one mapping between
input and output. */
if (!copy_special_section_fields (ibfd, obfd,
iheader, oheader, i))
j = elf_numsections (ibfd);
break;
}
}
if (j < elf_numsections (ibfd))
continue;
/* That failed. So try to deduce the corresponding input section.
Unfortunately we cannot compare names as the output string table
is empty, so instead we check size, address and type. */
for (j = 1; j < elf_numsections (ibfd); j++)
{
const Elf_Internal_Shdr * iheader = iheaders[j];
if (iheader == NULL)
continue;
/* Try matching fields in the input section's header.
Since --only-keep-debug turns all non-debug sections into
SHT_NOBITS sections, the output SHT_NOBITS type matches any
input type. */
if ((oheader->sh_type == SHT_NOBITS
|| iheader->sh_type == oheader->sh_type)
&& (iheader->sh_flags & ~ SHF_INFO_LINK)
== (oheader->sh_flags & ~ SHF_INFO_LINK)
&& iheader->sh_addralign == oheader->sh_addralign
&& iheader->sh_entsize == oheader->sh_entsize
&& iheader->sh_size == oheader->sh_size
&& iheader->sh_addr == oheader->sh_addr
&& (iheader->sh_info != oheader->sh_info
|| iheader->sh_link != oheader->sh_link))
{
if (copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
break;
}
}
if (j == elf_numsections (ibfd) && oheader->sh_type >= SHT_LOOS)
{
/* Final attempt. Call the backend copy function
with a NULL input section. */
(void) bed->elf_backend_copy_special_section_fields (ibfd, obfd,
NULL, oheader);
}
}
return true;
}
static const char *
get_segment_type (unsigned int p_type)
{
const char *pt;
switch (p_type)
{
case PT_NULL: pt = "NULL"; break;
case PT_LOAD: pt = "LOAD"; break;
case PT_DYNAMIC: pt = "DYNAMIC"; break;
case PT_INTERP: pt = "INTERP"; break;
case PT_NOTE: pt = "NOTE"; break;
case PT_SHLIB: pt = "SHLIB"; break;
case PT_PHDR: pt = "PHDR"; break;
case PT_TLS: pt = "TLS"; break;
case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
case PT_GNU_STACK: pt = "STACK"; break;
case PT_GNU_RELRO: pt = "RELRO"; break;
case PT_GNU_SFRAME: pt = "SFRAME"; break;
default: pt = NULL; break;
}
return pt;
}
/* Print out the program headers. */
bool
_bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
{
FILE *f = (FILE *) farg;
Elf_Internal_Phdr *p;
asection *s;
bfd_byte *dynbuf = NULL;
p = elf_tdata (abfd)->phdr;
if (p != NULL)
{
unsigned int i, c;
fprintf (f, _("\nProgram Header:\n"));
c = elf_elfheader (abfd)->e_phnum;
for (i = 0; i < c; i++, p++)
{
const char *pt = get_segment_type (p->p_type);
char buf[20];
if (pt == NULL)
{
sprintf (buf, "0x%lx", p->p_type);
pt = buf;
}
fprintf (f, "%8s off 0x", pt);
bfd_fprintf_vma (abfd, f, p->p_offset);
fprintf (f, " vaddr 0x");
bfd_fprintf_vma (abfd, f, p->p_vaddr);
fprintf (f, " paddr 0x");
bfd_fprintf_vma (abfd, f, p->p_paddr);
fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align));
fprintf (f, " filesz 0x");
bfd_fprintf_vma (abfd, f, p->p_filesz);
fprintf (f, " memsz 0x");
bfd_fprintf_vma (abfd, f, p->p_memsz);
fprintf (f, " flags %c%c%c",
(p->p_flags & PF_R) != 0 ? 'r' : '-',
(p->p_flags & PF_W) != 0 ? 'w' : '-',
(p->p_flags & PF_X) != 0 ? 'x' : '-');
if ((p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)) != 0)
fprintf (f, " %lx", p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X));
fprintf (f, "\n");
}
}
s = bfd_get_section_by_name (abfd, ".dynamic");
if (s != NULL && (s->flags & SEC_HAS_CONTENTS) != 0)
{
unsigned int elfsec;
unsigned long shlink;
bfd_byte *extdyn, *extdynend;
size_t extdynsize;
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
fprintf (f, _("\nDynamic Section:\n"));
if (!_bfd_elf_mmap_section_contents (abfd, s, &dynbuf))
goto error_return;
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
if (elfsec == SHN_BAD)
goto error_return;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
for (extdyn = dynbuf, extdynend = dynbuf + s->size;
(size_t) (extdynend - extdyn) >= extdynsize;
extdyn += extdynsize)
{
Elf_Internal_Dyn dyn;
const char *name = "";
char ab[20];
bool stringp;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
(*swap_dyn_in) (abfd, extdyn, &dyn);
if (dyn.d_tag == DT_NULL)
break;
stringp = false;
switch (dyn.d_tag)
{
default:
if (bed->elf_backend_get_target_dtag)
name = (*bed->elf_backend_get_target_dtag) (dyn.d_tag);
if (!strcmp (name, ""))
{
sprintf (ab, "%#" PRIx64, (uint64_t) dyn.d_tag);
name = ab;
}
break;
case DT_NEEDED: name = "NEEDED"; stringp = true; break;
case DT_PLTRELSZ: name = "PLTRELSZ"; break;
case DT_PLTGOT: name = "PLTGOT"; break;
case DT_HASH: name = "HASH"; break;
case DT_STRTAB: name = "STRTAB"; break;
case DT_SYMTAB: name = "SYMTAB"; break;
case DT_RELA: name = "RELA"; break;
case DT_RELASZ: name = "RELASZ"; break;
case DT_RELAENT: name = "RELAENT"; break;
case DT_STRSZ: name = "STRSZ"; break;
case DT_SYMENT: name = "SYMENT"; break;
case DT_INIT: name = "INIT"; break;
case DT_FINI: name = "FINI"; break;
case DT_SONAME: name = "SONAME"; stringp = true; break;
case DT_RPATH: name = "RPATH"; stringp = true; break;
case DT_SYMBOLIC: name = "SYMBOLIC"; break;
case DT_REL: name = "REL"; break;
case DT_RELSZ: name = "RELSZ"; break;
case DT_RELENT: name = "RELENT"; break;
case DT_RELR: name = "RELR"; break;
case DT_RELRSZ: name = "RELRSZ"; break;
case DT_RELRENT: name = "RELRENT"; break;
case DT_PLTREL: name = "PLTREL"; break;
case DT_DEBUG: name = "DEBUG"; break;
case DT_TEXTREL: name = "TEXTREL"; break;
case DT_JMPREL: name = "JMPREL"; break;
case DT_BIND_NOW: name = "BIND_NOW"; break;
case DT_INIT_ARRAY: name = "INIT_ARRAY"; break;
case DT_FINI_ARRAY: name = "FINI_ARRAY"; break;
case DT_INIT_ARRAYSZ: name = "INIT_ARRAYSZ"; break;
case DT_FINI_ARRAYSZ: name = "FINI_ARRAYSZ"; break;
case DT_RUNPATH: name = "RUNPATH"; stringp = true; break;
case DT_FLAGS: name = "FLAGS"; break;
case DT_PREINIT_ARRAY: name = "PREINIT_ARRAY"; break;
case DT_PREINIT_ARRAYSZ: name = "PREINIT_ARRAYSZ"; break;
case DT_CHECKSUM: name = "CHECKSUM"; break;
case DT_PLTPADSZ: name = "PLTPADSZ"; break;
case DT_MOVEENT: name = "MOVEENT"; break;
case DT_MOVESZ: name = "MOVESZ"; break;
case DT_FEATURE: name = "FEATURE"; break;
case DT_POSFLAG_1: name = "POSFLAG_1"; break;
case DT_SYMINSZ: name = "SYMINSZ"; break;
case DT_SYMINENT: name = "SYMINENT"; break;
case DT_CONFIG: name = "CONFIG"; stringp = true; break;
case DT_DEPAUDIT: name = "DEPAUDIT"; stringp = true; break;
case DT_AUDIT: name = "AUDIT"; stringp = true; break;
case DT_PLTPAD: name = "PLTPAD"; break;
case DT_MOVETAB: name = "MOVETAB"; break;
case DT_SYMINFO: name = "SYMINFO"; break;
case DT_RELACOUNT: name = "RELACOUNT"; break;
case DT_RELCOUNT: name = "RELCOUNT"; break;
case DT_FLAGS_1: name = "FLAGS_1"; break;
case DT_VERSYM: name = "VERSYM"; break;
case DT_VERDEF: name = "VERDEF"; break;
case DT_VERDEFNUM: name = "VERDEFNUM"; break;
case DT_VERNEED: name = "VERNEED"; break;
case DT_VERNEEDNUM: name = "VERNEEDNUM"; break;
case DT_AUXILIARY: name = "AUXILIARY"; stringp = true; break;
case DT_USED: name = "USED"; break;
case DT_FILTER: name = "FILTER"; stringp = true; break;
case DT_GNU_HASH: name = "GNU_HASH"; break;
}
fprintf (f, " %-20s ", name);
if (! stringp)
{
fprintf (f, "0x");
bfd_fprintf_vma (abfd, f, dyn.d_un.d_val);
}
else
{
const char *string;
unsigned int tagv = dyn.d_un.d_val;
string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (string == NULL)
goto error_return;
fprintf (f, "%s", string);
}
fprintf (f, "\n");
}
_bfd_elf_munmap_section_contents (s, dynbuf);
dynbuf = NULL;
}
if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL)
|| (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL))
{
if (! _bfd_elf_slurp_version_tables (abfd, false))
return false;
}
if (elf_dynverdef (abfd) != 0)
{
Elf_Internal_Verdef *t;
fprintf (f, _("\nVersion definitions:\n"));
for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef)
{
fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx,
t->vd_flags, t->vd_hash,
t->vd_nodename ? t->vd_nodename : "<corrupt>");
if (t->vd_auxptr != NULL && t->vd_auxptr->vda_nextptr != NULL)
{
Elf_Internal_Verdaux *a;
fprintf (f, "\t");
for (a = t->vd_auxptr->vda_nextptr;
a != NULL;
a = a->vda_nextptr)
fprintf (f, "%s ",
a->vda_nodename ? a->vda_nodename : "<corrupt>");
fprintf (f, "\n");
}
}
}
if (elf_dynverref (abfd) != 0)
{
Elf_Internal_Verneed *t;
fprintf (f, _("\nVersion References:\n"));
for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref)
{
Elf_Internal_Vernaux *a;
fprintf (f, _(" required from %s:\n"),
t->vn_filename ? t->vn_filename : "<corrupt>");
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
fprintf (f, " 0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash,
a->vna_flags, a->vna_other,
a->vna_nodename ? a->vna_nodename : "<corrupt>");
}
}
return true;
error_return:
_bfd_elf_munmap_section_contents (s, dynbuf);
return false;
}
/* Find the file offset corresponding to VMA by using the program
headers. */
static file_ptr
offset_from_vma (Elf_Internal_Phdr *phdrs, size_t phnum, bfd_vma vma,
size_t size, size_t *max_size_p)
{
Elf_Internal_Phdr *seg;
size_t i;
for (seg = phdrs, i = 0; i < phnum; ++seg, ++i)
if (seg->p_type == PT_LOAD
&& vma >= (seg->p_vaddr & -seg->p_align)
&& vma + size <= seg->p_vaddr + seg->p_filesz)
{
if (max_size_p)
*max_size_p = seg->p_vaddr + seg->p_filesz - vma;
return vma - seg->p_vaddr + seg->p_offset;
}
if (max_size_p)
*max_size_p = 0;
bfd_set_error (bfd_error_invalid_operation);
return (file_ptr) -1;
}
/* Convert hash table to internal form. */
static bfd_vma *
get_hash_table_data (bfd *abfd, bfd_size_type number,
unsigned int ent_size, bfd_size_type filesize)
{
unsigned char *e_data = NULL;
bfd_vma *i_data = NULL;
bfd_size_type size;
void *e_data_addr;
size_t e_data_size ATTRIBUTE_UNUSED;
if (ent_size != 4 && ent_size != 8)
return NULL;
if ((size_t) number != number)
{
bfd_set_error (bfd_error_file_too_big);
return NULL;
}
size = ent_size * number;
/* Be kind to memory checkers (eg valgrind, address sanitizer) by not
attempting to allocate memory when the read is bound to fail. */
if (size > filesize
|| number >= ~(size_t) 0 / ent_size
|| number >= ~(size_t) 0 / sizeof (*i_data))
{
bfd_set_error (bfd_error_file_too_big);
return NULL;
}
e_data = _bfd_mmap_readonly_temporary (abfd, size, &e_data_addr,
&e_data_size);
if (e_data == NULL)
return NULL;
i_data = (bfd_vma *) bfd_malloc (number * sizeof (*i_data));
if (i_data == NULL)
{
free (e_data);
return NULL;
}
if (ent_size == 4)
while (number--)
i_data[number] = bfd_get_32 (abfd, e_data + number * ent_size);
else
while (number--)
i_data[number] = bfd_get_64 (abfd, e_data + number * ent_size);
_bfd_munmap_readonly_temporary (e_data_addr, e_data_size);
return i_data;
}
/* Address of .MIPS.xhash section. FIXME: What is the best way to
support DT_MIPS_XHASH? */
#define DT_MIPS_XHASH 0x70000036
/* Reconstruct dynamic symbol table from PT_DYNAMIC segment. */
bool
_bfd_elf_get_dynamic_symbols (bfd *abfd, Elf_Internal_Phdr *phdr,
Elf_Internal_Phdr *phdrs, size_t phnum,
bfd_size_type filesize)
{
bfd_byte *extdyn, *extdynend;
size_t extdynsize;
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
bool (*swap_symbol_in) (bfd *, const void *, const void *,
Elf_Internal_Sym *);
Elf_Internal_Dyn dyn;
bfd_vma dt_hash = 0;
bfd_vma dt_gnu_hash = 0;
bfd_vma dt_mips_xhash = 0;
bfd_vma dt_strtab = 0;
bfd_vma dt_symtab = 0;
size_t dt_strsz = 0;
bfd_vma dt_versym = 0;
bfd_vma dt_verdef = 0;
bfd_vma dt_verneed = 0;
bfd_byte *dynbuf = NULL;
char *strbuf = NULL;
bfd_vma *gnubuckets = NULL;
bfd_vma *gnuchains = NULL;
bfd_vma *mipsxlat = NULL;
file_ptr saved_filepos, filepos;
bool res = false;
size_t amt;
bfd_byte *esymbuf = NULL, *esym;
bfd_size_type symcount;
Elf_Internal_Sym *isymbuf = NULL;
Elf_Internal_Sym *isym, *isymend;
bfd_byte *versym = NULL;
bfd_byte *verdef = NULL;
bfd_byte *verneed = NULL;
size_t verdef_size = 0;
size_t verneed_size = 0;
size_t extsym_size;
const struct elf_backend_data *bed;
void *dynbuf_addr = NULL;
void *esymbuf_addr = NULL;
size_t dynbuf_size = 0;
size_t esymbuf_size = 0;
/* Return TRUE if symbol table is bad. */
if (elf_bad_symtab (abfd))
return true;
/* Return TRUE if DT_HASH/DT_GNU_HASH have bee processed before. */
if (elf_tdata (abfd)->dt_strtab != NULL)
return true;
bed = get_elf_backend_data (abfd);
/* Save file position for elf_object_p. */
saved_filepos = bfd_tell (abfd);
if (bfd_seek (abfd, phdr->p_offset, SEEK_SET) != 0)
goto error_return;
dynbuf_size = phdr->p_filesz;
dynbuf = _bfd_mmap_readonly_temporary (abfd, dynbuf_size,
&dynbuf_addr, &dynbuf_size);
if (dynbuf == NULL)
goto error_return;
extsym_size = bed->s->sizeof_sym;
extdynsize = bed->s->sizeof_dyn;
swap_dyn_in = bed->s->swap_dyn_in;
extdyn = dynbuf;
if (phdr->p_filesz < extdynsize)
goto error_return;
extdynend = extdyn + phdr->p_filesz;
for (; extdyn <= (extdynend - extdynsize); extdyn += extdynsize)
{
swap_dyn_in (abfd, extdyn, &dyn);
if (dyn.d_tag == DT_NULL)
break;
switch (dyn.d_tag)
{
case DT_HASH:
dt_hash = dyn.d_un.d_val;
break;
case DT_GNU_HASH:
if (bed->elf_machine_code != EM_MIPS
&& bed->elf_machine_code != EM_MIPS_RS3_LE)
dt_gnu_hash = dyn.d_un.d_val;
break;
case DT_STRTAB:
dt_strtab = dyn.d_un.d_val;
break;
case DT_SYMTAB:
dt_symtab = dyn.d_un.d_val;
break;
case DT_STRSZ:
dt_strsz = dyn.d_un.d_val;
break;
case DT_SYMENT:
if (dyn.d_un.d_val != extsym_size)
goto error_return;
break;
case DT_VERSYM:
dt_versym = dyn.d_un.d_val;
break;
case DT_VERDEF:
dt_verdef = dyn.d_un.d_val;
break;
case DT_VERNEED:
dt_verneed = dyn.d_un.d_val;
break;
default:
if (dyn.d_tag == DT_MIPS_XHASH
&& (bed->elf_machine_code == EM_MIPS
|| bed->elf_machine_code == EM_MIPS_RS3_LE))
{
dt_gnu_hash = dyn.d_un.d_val;
dt_mips_xhash = dyn.d_un.d_val;
}
break;
}
}
/* Check if we can reconstruct dynamic symbol table from PT_DYNAMIC
segment. */
if ((!dt_hash && !dt_gnu_hash)
|| !dt_strtab
|| !dt_symtab
|| !dt_strsz)
goto error_return;
/* Get dynamic string table. */
filepos = offset_from_vma (phdrs, phnum, dt_strtab, dt_strsz, NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
/* Dynamic string table must be valid until ABFD is closed. */
strbuf = (char *) _bfd_mmap_readonly_persistent (abfd, dt_strsz);
if (strbuf == NULL)
goto error_return;
if (strbuf[dt_strsz - 1] != 0)
{
/* It is an error if a string table is't terminated. */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: DT_STRTAB table is corrupt"), abfd);
strbuf[dt_strsz - 1] = 0;
}
/* Get the real symbol count from DT_HASH or DT_GNU_HASH. Prefer
DT_HASH since it is simpler than DT_GNU_HASH. */
if (dt_hash)
{
unsigned char nb[16];
unsigned int hash_ent_size;
switch (bed->elf_machine_code)
{
case EM_ALPHA:
case EM_S390:
case EM_S390_OLD:
if (bed->s->elfclass == ELFCLASS64)
{
hash_ent_size = 8;
break;
}
/* FALLTHROUGH */
default:
hash_ent_size = 4;
break;
}
filepos = offset_from_vma (phdrs, phnum, dt_hash, sizeof (nb),
NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0
|| bfd_read (nb, 2 * hash_ent_size, abfd) != 2 * hash_ent_size)
goto error_return;
/* The number of dynamic symbol table entries equals the number
of chains. */
if (hash_ent_size == 8)
symcount = bfd_get_64 (abfd, nb + hash_ent_size);
else
symcount = bfd_get_32 (abfd, nb + hash_ent_size);
}
else
{
/* For DT_GNU_HASH, only defined symbols with non-STB_LOCAL
bindings are in hash table. Since in dynamic symbol table,
all symbols with STB_LOCAL binding are placed before symbols
with other bindings and all undefined symbols are placed
before defined ones, the highest symbol index in DT_GNU_HASH
is the highest dynamic symbol table index. */
unsigned char nb[16];
bfd_vma ngnubuckets;
bfd_vma gnusymidx;
size_t i, ngnuchains;
bfd_vma maxchain = 0xffffffff, bitmaskwords;
bfd_vma buckets_vma;
filepos = offset_from_vma (phdrs, phnum, dt_gnu_hash,
sizeof (nb), NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0
|| bfd_read (nb, sizeof (nb), abfd) != sizeof (nb))
goto error_return;
ngnubuckets = bfd_get_32 (abfd, nb);
gnusymidx = bfd_get_32 (abfd, nb + 4);
bitmaskwords = bfd_get_32 (abfd, nb + 8);
buckets_vma = dt_gnu_hash + 16;
if (bed->s->elfclass == ELFCLASS32)
buckets_vma += bitmaskwords * 4;
else
buckets_vma += bitmaskwords * 8;
filepos = offset_from_vma (phdrs, phnum, buckets_vma, 4, NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
gnubuckets = get_hash_table_data (abfd, ngnubuckets, 4, filesize);
if (gnubuckets == NULL)
goto error_return;
for (i = 0; i < ngnubuckets; i++)
if (gnubuckets[i] != 0)
{
if (gnubuckets[i] < gnusymidx)
goto error_return;
if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
maxchain = gnubuckets[i];
}
if (maxchain == 0xffffffff)
{
symcount = 0;
goto empty_gnu_hash;
}
maxchain -= gnusymidx;
filepos = offset_from_vma (phdrs, phnum,
(buckets_vma +
4 * (ngnubuckets + maxchain)),
4, NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
do
{
if (bfd_read (nb, 4, abfd) != 4)
goto error_return;
++maxchain;
if (maxchain == 0)
goto error_return;
}
while ((bfd_get_32 (abfd, nb) & 1) == 0);
filepos = offset_from_vma (phdrs, phnum,
(buckets_vma + 4 * ngnubuckets),
4, NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
gnuchains = get_hash_table_data (abfd, maxchain, 4, filesize);
if (gnuchains == NULL)
goto error_return;
ngnuchains = maxchain;
if (dt_mips_xhash)
{
filepos = offset_from_vma (phdrs, phnum,
(buckets_vma
+ 4 * (ngnubuckets + maxchain)),
4, NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
mipsxlat = get_hash_table_data (abfd, maxchain, 4, filesize);
if (mipsxlat == NULL)
goto error_return;
}
symcount = 0;
for (i = 0; i < ngnubuckets; ++i)
if (gnubuckets[i] != 0)
{
bfd_vma si = gnubuckets[i];
bfd_vma off = si - gnusymidx;
do
{
if (mipsxlat)
{
if (mipsxlat[off] >= symcount)
symcount = mipsxlat[off] + 1;
}
else
{
if (si >= symcount)
symcount = si + 1;
}
si++;
}
while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
}
}
/* Swap in dynamic symbol table. */
if (_bfd_mul_overflow (symcount, extsym_size, &amt))
{
bfd_set_error (bfd_error_file_too_big);
goto error_return;
}
filepos = offset_from_vma (phdrs, phnum, dt_symtab, amt, NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
esymbuf_size = amt;
esymbuf = _bfd_mmap_readonly_temporary (abfd, esymbuf_size,
&esymbuf_addr,
&esymbuf_size);
if (esymbuf == NULL)
goto error_return;
if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt))
{
bfd_set_error (bfd_error_file_too_big);
goto error_return;
}
/* Dynamic symbol table must be valid until ABFD is closed. */
isymbuf = (Elf_Internal_Sym *) bfd_alloc (abfd, amt);
if (isymbuf == NULL)
goto error_return;
swap_symbol_in = bed->s->swap_symbol_in;
/* Convert the symbols to internal form. */
isymend = isymbuf + symcount;
for (esym = esymbuf, isym = isymbuf;
isym < isymend;
esym += extsym_size, isym++)
if (!swap_symbol_in (abfd, esym, NULL, isym)
|| isym->st_name >= dt_strsz)
{
bfd_set_error (bfd_error_invalid_operation);
goto error_return;
}
if (dt_versym)
{
/* Swap in DT_VERSYM. */
if (_bfd_mul_overflow (symcount, 2, &amt))
{
bfd_set_error (bfd_error_file_too_big);
goto error_return;
}
filepos = offset_from_vma (phdrs, phnum, dt_versym, amt, NULL);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
/* DT_VERSYM info must be valid until ABFD is closed. */
versym = _bfd_mmap_readonly_persistent (abfd, amt);
if (dt_verdef)
{
/* Read in DT_VERDEF. */
filepos = offset_from_vma (phdrs, phnum, dt_verdef,
0, &verdef_size);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
/* DT_VERDEF info must be valid until ABFD is closed. */
verdef = _bfd_mmap_readonly_persistent (abfd, verdef_size);
}
if (dt_verneed)
{
/* Read in DT_VERNEED. */
filepos = offset_from_vma (phdrs, phnum, dt_verneed,
0, &verneed_size);
if (filepos == (file_ptr) -1
|| bfd_seek (abfd, filepos, SEEK_SET) != 0)
goto error_return;
/* DT_VERNEED info must be valid until ABFD is closed. */
verneed = _bfd_mmap_readonly_persistent (abfd, verneed_size);
}
}
empty_gnu_hash:
elf_tdata (abfd)->dt_strtab = strbuf;
elf_tdata (abfd)->dt_strsz = dt_strsz;
elf_tdata (abfd)->dt_symtab = isymbuf;
elf_tdata (abfd)->dt_symtab_count = symcount;
elf_tdata (abfd)->dt_versym = versym;
elf_tdata (abfd)->dt_verdef = verdef;
elf_tdata (abfd)->dt_verneed = verneed;
elf_tdata (abfd)->dt_verdef_count
= verdef_size / sizeof (Elf_External_Verdef);
elf_tdata (abfd)->dt_verneed_count
= verneed_size / sizeof (Elf_External_Verneed);
res = true;
error_return:
/* Restore file position for elf_object_p. */
if (bfd_seek (abfd, saved_filepos, SEEK_SET) != 0)
res = false;
_bfd_munmap_readonly_temporary (dynbuf_addr, dynbuf_size);
_bfd_munmap_readonly_temporary (esymbuf_addr, esymbuf_size);
free (gnubuckets);
free (gnuchains);
free (mipsxlat);
return res;
}
/* Reconstruct section from dynamic symbol. */
asection *
_bfd_elf_get_section_from_dynamic_symbol (bfd *abfd,
Elf_Internal_Sym *isym)
{
asection *sec;
flagword flags;
if (!elf_use_dt_symtab_p (abfd))
return NULL;
flags = SEC_ALLOC | SEC_LOAD;
switch (ELF_ST_TYPE (isym->st_info))
{
case STT_FUNC:
case STT_GNU_IFUNC:
sec = bfd_get_section_by_name (abfd, ".text");
if (sec == NULL)
sec = bfd_make_section_with_flags (abfd,
".text",
flags | SEC_CODE);
break;
case STT_COMMON:
sec = bfd_com_section_ptr;
break;
case STT_OBJECT:
sec = bfd_get_section_by_name (abfd, ".data");
if (sec == NULL)
sec = bfd_make_section_with_flags (abfd,
".data",
flags | SEC_DATA);
break;
case STT_TLS:
sec = bfd_get_section_by_name (abfd, ".tdata");
if (sec == NULL)
sec = bfd_make_section_with_flags (abfd,
".tdata",
(flags
| SEC_DATA
| SEC_THREAD_LOCAL));
break;
default:
sec = bfd_abs_section_ptr;
break;
}
return sec;
}
/* Get version name. If BASE_P is TRUE, return "Base" for VER_FLG_BASE
and return symbol version for symbol version itself. */
const char *
_bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol,
bool base_p,
bool *hidden)
{
const char *version_string = NULL;
if ((elf_dynversym (abfd) != 0
&& (elf_dynverdef (abfd) != 0 || elf_dynverref (abfd) != 0))
|| (elf_tdata (abfd)->dt_versym != NULL
&& (elf_tdata (abfd)->dt_verdef != NULL
|| elf_tdata (abfd)->dt_verneed != NULL)))
{
unsigned int vernum = ((elf_symbol_type *) symbol)->version;
*hidden = (vernum & VERSYM_HIDDEN) != 0;
vernum &= VERSYM_VERSION;
if (vernum == 0)
version_string = "";
else if (vernum == 1
&& (vernum > elf_tdata (abfd)->cverdefs
|| (elf_tdata (abfd)->verdef[0].vd_flags
== VER_FLG_BASE)))
version_string = base_p ? "Base" : "";
else if (vernum <= elf_tdata (abfd)->cverdefs)
{
const char *nodename
= elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
version_string = "";
if (base_p
|| nodename == NULL
|| symbol->name == NULL
|| strcmp (symbol->name, nodename) != 0)
version_string = nodename;
}
else
{
Elf_Internal_Verneed *t;
version_string = _("<corrupt>");
for (t = elf_tdata (abfd)->verref;
t != NULL;
t = t->vn_nextref)
{
Elf_Internal_Vernaux *a;
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
{
if (a->vna_other == vernum)
{
*hidden = true;
version_string = a->vna_nodename;
break;
}
}
}
}
}
return version_string;
}
/* Display ELF-specific fields of a symbol. */
void
bfd_elf_print_symbol (bfd *abfd,
void *filep,
asymbol *symbol,
bfd_print_symbol_type how)
{
FILE *file = (FILE *) filep;
switch (how)
{
case bfd_print_symbol_name:
fprintf (file, "%s", symbol->name);
break;
case bfd_print_symbol_more:
fprintf (file, "elf ");
bfd_fprintf_vma (abfd, file, symbol->value);
fprintf (file, " %x", symbol->flags);
break;
case bfd_print_symbol_all:
{
const char *section_name;
const char *name = NULL;
const struct elf_backend_data *bed;
unsigned char st_other;
bfd_vma val;
const char *version_string;
bool hidden;
section_name = symbol->section ? symbol->section->name : "(*none*)";
bed = get_elf_backend_data (abfd);
if (bed->elf_backend_print_symbol_all)
name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol);
if (name == NULL)
{
name = symbol->name;
bfd_print_symbol_vandf (abfd, file, symbol);
}
fprintf (file, " %s\t", section_name);
/* Print the "other" value for a symbol. For common symbols,
we've already printed the size; now print the alignment.
For other symbols, we have no specified alignment, and
we've printed the address; now print the size. */
if (symbol->section && bfd_is_com_section (symbol->section))
val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
else
val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size;
bfd_fprintf_vma (abfd, file, val);
/* If we have version information, print it. */
version_string = _bfd_elf_get_symbol_version_string (abfd,
symbol,
true,
&hidden);
if (version_string)
{
if (!hidden)
fprintf (file, " %-11s", version_string);
else
{
int i;
fprintf (file, " (%s)", version_string);
for (i = 10 - strlen (version_string); i > 0; --i)
putc (' ', file);
}
}
/* If the st_other field is not zero, print it. */
st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other;
switch (st_other)
{
case 0: break;
case STV_INTERNAL: fprintf (file, " .internal"); break;
case STV_HIDDEN: fprintf (file, " .hidden"); break;
case STV_PROTECTED: fprintf (file, " .protected"); break;
default:
/* Some other non-defined flags are also present, so print
everything hex. */
fprintf (file, " 0x%02x", (unsigned int) st_other);
}
fprintf (file, " %s", name);
}
break;
}
}
/* ELF .o/exec file reading */
/* Create a new bfd section from an ELF section header. */
bool
bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
{
Elf_Internal_Shdr *hdr;
Elf_Internal_Ehdr *ehdr;
const struct elf_backend_data *bed;
const char *name;
bool ret = true;
if (shindex >= elf_numsections (abfd))
return false;
/* PR17512: A corrupt ELF binary might contain a loop of sections via
sh_link or sh_info. Detect this here, by refusing to load a
section that we are already in the process of loading. */
if (elf_tdata (abfd)->being_created[shindex])
{
_bfd_error_handler
(_("%pB: warning: loop in section dependencies detected"), abfd);
return false;
}
elf_tdata (abfd)->being_created[shindex] = true;
hdr = elf_elfsections (abfd)[shindex];
ehdr = elf_elfheader (abfd);
name = bfd_elf_string_from_elf_section (abfd, ehdr->e_shstrndx,
hdr->sh_name);
if (name == NULL)
goto fail;
bed = get_elf_backend_data (abfd);
switch (hdr->sh_type)
{
case SHT_NULL:
/* Inactive section. Throw it away. */
goto success;
case SHT_PROGBITS: /* Normal section with contents. */
case SHT_NOBITS: /* .bss section. */
case SHT_HASH: /* .hash section. */
case SHT_NOTE: /* .note section. */
case SHT_INIT_ARRAY: /* .init_array section. */
case SHT_FINI_ARRAY: /* .fini_array section. */
case SHT_PREINIT_ARRAY: /* .preinit_array section. */
case SHT_GNU_LIBLIST: /* .gnu.liblist section. */
case SHT_GNU_HASH: /* .gnu.hash section. */
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
case SHT_DYNAMIC: /* Dynamic linking information. */
if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
goto fail;
if (hdr->sh_link > elf_numsections (abfd))
{
/* PR 10478: Accept Solaris binaries with a sh_link field
set to SHN_BEFORE (LORESERVE) or SHN_AFTER (LORESERVE+1). */
switch (bfd_get_arch (abfd))
{
case bfd_arch_i386:
case bfd_arch_sparc:
if (hdr->sh_link == (SHN_LORESERVE & 0xffff)
|| hdr->sh_link == ((SHN_LORESERVE + 1) & 0xffff))
break;
/* Otherwise fall through. */
default:
goto fail;
}
}
else if (elf_elfsections (abfd)[hdr->sh_link] == NULL)
goto fail;
else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB)
{
Elf_Internal_Shdr *dynsymhdr;
/* The shared libraries distributed with hpux11 have a bogus
sh_link field for the ".dynamic" section. Find the
string table for the ".dynsym" section instead. */
if (elf_dynsymtab (abfd) != 0)
{
dynsymhdr = elf_elfsections (abfd)[elf_dynsymtab (abfd)];
hdr->sh_link = dynsymhdr->sh_link;
}
else
{
unsigned int i, num_sec;
num_sec = elf_numsections (abfd);
for (i = 1; i < num_sec; i++)
{
dynsymhdr = elf_elfsections (abfd)[i];
if (dynsymhdr->sh_type == SHT_DYNSYM)
{
hdr->sh_link = dynsymhdr->sh_link;
break;
}
}
}
}
goto success;
case SHT_SYMTAB: /* A symbol table. */
if (elf_onesymtab (abfd) == shindex)
goto success;
if (hdr->sh_entsize != bed->s->sizeof_sym)
goto fail;
if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
{
if (hdr->sh_size != 0)
goto fail;
/* Some assemblers erroneously set sh_info to one with a
zero sh_size. ld sees this as a global symbol count
of (unsigned) -1. Fix it here. */
hdr->sh_info = 0;
goto success;
}
/* PR 18854: A binary might contain more than one symbol table.
Unusual, but possible. Warn, but continue. */
if (elf_onesymtab (abfd) != 0)
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: warning: multiple symbol tables detected"
" - ignoring the table in section %u"),
abfd, shindex);
goto success;
}
elf_onesymtab (abfd) = shindex;
elf_symtab_hdr (abfd) = *hdr;
elf_elfsections (abfd)[shindex] = hdr = & elf_symtab_hdr (abfd);
abfd->flags |= HAS_SYMS;
/* Sometimes a shared object will map in the symbol table. If
SHF_ALLOC is set, and this is a shared object, then we also
treat this section as a BFD section. We can not base the
decision purely on SHF_ALLOC, because that flag is sometimes
set in a relocatable object file, which would confuse the
linker. */
if ((hdr->sh_flags & SHF_ALLOC) != 0
&& (abfd->flags & DYNAMIC) != 0
&& ! _bfd_elf_make_section_from_shdr (abfd, hdr, name,
shindex))
goto fail;
/* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we
can't read symbols without that section loaded as well. It
is most likely specified by the next section header. */
{
elf_section_list * entry;
unsigned int i, num_sec;
for (entry = elf_symtab_shndx_list (abfd); entry; entry = entry->next)
if (entry->hdr.sh_link == shindex)
goto success;
num_sec = elf_numsections (abfd);
for (i = shindex + 1; i < num_sec; i++)
{
Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
if (hdr2->sh_type == SHT_SYMTAB_SHNDX
&& hdr2->sh_link == shindex)
break;
}
if (i == num_sec)
for (i = 1; i < shindex; i++)
{
Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
if (hdr2->sh_type == SHT_SYMTAB_SHNDX
&& hdr2->sh_link == shindex)
break;
}
if (i != shindex)
ret = bfd_section_from_shdr (abfd, i);
/* else FIXME: we have failed to find the symbol table.
Should we issue an error? */
goto success;
}
case SHT_DYNSYM: /* A dynamic symbol table. */
if (elf_dynsymtab (abfd) == shindex)
goto success;
if (hdr->sh_entsize != bed->s->sizeof_sym)
goto fail;
if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
{
if (hdr->sh_size != 0)
goto fail;
/* Some linkers erroneously set sh_info to one with a
zero sh_size. ld sees this as a global symbol count
of (unsigned) -1. Fix it here. */
hdr->sh_info = 0;
goto success;
}
/* PR 18854: A binary might contain more than one dynamic symbol table.
Unusual, but possible. Warn, but continue. */
if (elf_dynsymtab (abfd) != 0)
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: warning: multiple dynamic symbol tables detected"
" - ignoring the table in section %u"),
abfd, shindex);
goto success;
}
elf_dynsymtab (abfd) = shindex;
elf_tdata (abfd)->dynsymtab_hdr = *hdr;
elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr;
abfd->flags |= HAS_SYMS;
/* Besides being a symbol table, we also treat this as a regular
section, so that objcopy can handle it. */
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections. */
{
elf_section_list * entry;
for (entry = elf_symtab_shndx_list (abfd); entry; entry = entry->next)
if (entry->ndx == shindex)
goto success;
entry = bfd_alloc (abfd, sizeof (*entry));
if (entry == NULL)
goto fail;
entry->ndx = shindex;
entry->hdr = * hdr;
entry->next = elf_symtab_shndx_list (abfd);
elf_symtab_shndx_list (abfd) = entry;
elf_elfsections (abfd)[shindex] = & entry->hdr;
goto success;
}
case SHT_STRTAB: /* A string table. */
if (hdr->bfd_section != NULL)
goto success;
if (ehdr->e_shstrndx == shindex)
{
elf_tdata (abfd)->shstrtab_hdr = *hdr;
elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr;
goto success;
}
if (elf_elfsections (abfd)[elf_onesymtab (abfd)]->sh_link == shindex)
{
symtab_strtab:
elf_tdata (abfd)->strtab_hdr = *hdr;
elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr;
goto success;
}
if (elf_elfsections (abfd)[elf_dynsymtab (abfd)]->sh_link == shindex)
{
dynsymtab_strtab:
elf_tdata (abfd)->dynstrtab_hdr = *hdr;
hdr = &elf_tdata (abfd)->dynstrtab_hdr;
elf_elfsections (abfd)[shindex] = hdr;
/* We also treat this as a regular section, so that objcopy
can handle it. */
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name,
shindex);
goto success;
}
/* If the string table isn't one of the above, then treat it as a
regular section. We need to scan all the headers to be sure,
just in case this strtab section appeared before the above. */
if (elf_onesymtab (abfd) == 0 || elf_dynsymtab (abfd) == 0)
{
unsigned int i, num_sec;
num_sec = elf_numsections (abfd);
for (i = 1; i < num_sec; i++)
{
Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
if (hdr2->sh_link == shindex)
{
/* Prevent endless recursion on broken objects. */
if (i == shindex)
goto fail;
if (! bfd_section_from_shdr (abfd, i))
goto fail;
if (elf_onesymtab (abfd) == i)
goto symtab_strtab;
if (elf_dynsymtab (abfd) == i)
goto dynsymtab_strtab;
}
}
}
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
case SHT_REL:
case SHT_RELA:
case SHT_RELR:
/* *These* do a lot of work -- but build no sections! */
{
asection *target_sect;
Elf_Internal_Shdr *hdr2, **p_hdr;
unsigned int num_sec = elf_numsections (abfd);
struct bfd_elf_section_data *esdt;
bfd_size_type size;
if (hdr->sh_type == SHT_REL)
size = bed->s->sizeof_rel;
else if (hdr->sh_type == SHT_RELA)
size = bed->s->sizeof_rela;
else
size = bed->s->arch_size / 8;
if (hdr->sh_entsize != size)
goto fail;
/* Check for a bogus link to avoid crashing. */
if (hdr->sh_link >= num_sec)
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: invalid link %u for reloc section %s (index %u)"),
abfd, hdr->sh_link, name, shindex);
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
}
/* Get the symbol table. */
if ((elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB
|| elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_DYNSYM)
&& ! bfd_section_from_shdr (abfd, hdr->sh_link))
goto fail;
/* If this is an alloc section in an executable or shared
library, or the reloc section does not use the main symbol
table we don't treat it as a reloc section. BFD can't
adequately represent such a section, so at least for now,
we don't try. We just present it as a normal section. We
also can't use it as a reloc section if it points to the
null section, an invalid section, another reloc section, or
its sh_link points to the null section. */
if (((abfd->flags & (DYNAMIC | EXEC_P)) != 0
&& (hdr->sh_flags & SHF_ALLOC) != 0)
|| (hdr->sh_flags & SHF_COMPRESSED) != 0
|| hdr->sh_type == SHT_RELR
|| hdr->sh_link == SHN_UNDEF
|| hdr->sh_link != elf_onesymtab (abfd)
|| hdr->sh_info == SHN_UNDEF
|| hdr->sh_info >= num_sec
|| elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
|| elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA)
{
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
}
if (! bfd_section_from_shdr (abfd, hdr->sh_info))
goto fail;
target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
if (target_sect == NULL)
goto fail;
esdt = elf_section_data (target_sect);
if (hdr->sh_type == SHT_RELA)
p_hdr = &esdt->rela.hdr;
else
p_hdr = &esdt->rel.hdr;
/* PR 17512: file: 0b4f81b7.
Also see PR 24456, for a file which deliberately has two reloc
sections. */
if (*p_hdr != NULL)
{
if (!bed->init_secondary_reloc_section (abfd, hdr, name, shindex))
{
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: warning: secondary relocation section '%s' "
"for section %pA found - ignoring"),
abfd, name, target_sect);
}
else
esdt->has_secondary_relocs = true;
goto success;
}
hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
if (hdr2 == NULL)
goto fail;
*hdr2 = *hdr;
*p_hdr = hdr2;
elf_elfsections (abfd)[shindex] = hdr2;
target_sect->reloc_count += (NUM_SHDR_ENTRIES (hdr)
* bed->s->int_rels_per_ext_rel);
target_sect->flags |= SEC_RELOC;
target_sect->relocation = NULL;
target_sect->rel_filepos = hdr->sh_offset;
/* In the section to which the relocations apply, mark whether
its relocations are of the REL or RELA variety. */
if (hdr->sh_size != 0)
{
if (hdr->sh_type == SHT_RELA)
target_sect->use_rela_p = 1;
}
abfd->flags |= HAS_RELOC;
goto success;
}
case SHT_GNU_verdef:
if (hdr->sh_info != 0)
elf_dynverdef (abfd) = shindex;
elf_tdata (abfd)->dynverdef_hdr = *hdr;
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
case SHT_GNU_versym:
if (hdr->sh_entsize != sizeof (Elf_External_Versym))
goto fail;
elf_dynversym (abfd) = shindex;
elf_tdata (abfd)->dynversym_hdr = *hdr;
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
case SHT_GNU_verneed:
if (hdr->sh_info != 0)
elf_dynverref (abfd) = shindex;
elf_tdata (abfd)->dynverref_hdr = *hdr;
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
case SHT_SHLIB:
goto success;
case SHT_GROUP:
if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
goto fail;
goto success;
default:
/* Possibly an attributes section. */
if (hdr->sh_type == SHT_GNU_ATTRIBUTES
|| hdr->sh_type == bed->obj_attrs_section_type)
{
if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
goto fail;
_bfd_elf_parse_attributes (abfd, hdr);
goto success;
}
/* Check for any processor-specific section types. */
if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex))
goto success;
if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER)
{
if ((hdr->sh_flags & SHF_ALLOC) != 0)
/* FIXME: How to properly handle allocated section reserved
for applications? */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: unknown type [%#x] section `%s'"),
abfd, hdr->sh_type, name);
else
{
/* Allow sections reserved for applications. */
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
}
}
else if (hdr->sh_type >= SHT_LOPROC
&& hdr->sh_type <= SHT_HIPROC)
/* FIXME: We should handle this section. */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: unknown type [%#x] section `%s'"),
abfd, hdr->sh_type, name);
else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS)
{
/* Unrecognised OS-specific sections. */
if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0)
/* SHF_OS_NONCONFORMING indicates that special knowledge is
required to correctly process the section and the file should
be rejected with an error message. */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: unknown type [%#x] section `%s'"),
abfd, hdr->sh_type, name);
else
{
/* Otherwise it should be processed. */
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
goto success;
}
}
else
/* FIXME: We should handle this section. */
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: unknown type [%#x] section `%s'"),
abfd, hdr->sh_type, name);
goto fail;
}
fail:
ret = false;
success:
elf_tdata (abfd)->being_created[shindex] = false;
return ret;
}
/* Return the local symbol specified by ABFD, R_SYMNDX. */
Elf_Internal_Sym *
bfd_sym_from_r_symndx (struct sym_cache *cache,
bfd *abfd,
unsigned long r_symndx)
{
unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
if (cache->abfd != abfd || cache->indx[ent] != r_symndx)
{
Elf_Internal_Shdr *symtab_hdr;
unsigned char esym[sizeof (Elf64_External_Sym)];
Elf_External_Sym_Shndx eshndx;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
&cache->sym[ent], esym, &eshndx) == NULL)
return NULL;
if (cache->abfd != abfd)
{
memset (cache->indx, -1, sizeof (cache->indx));
cache->abfd = abfd;
}
cache->indx[ent] = r_symndx;
}
return &cache->sym[ent];