2019-11-12 10:19:53 +00:00

1268 lines
30 KiB
C++

/*
* Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* @file
*
* @ingroup rtems-ld
*
* @brief RTEMS Linker ELF module manages the ELF format images.
*
*/
#include <string.h>
#include <rld.h>
namespace rld
{
namespace elf
{
/**
* Throw an ELF error.
*
* @param where Where the error is raised.
*/
void libelf_error (const std::string& where)
{
throw rld::error (::elf_errmsg (-1), "libelf:" + where);
}
/**
* We record the first class, machine and .. type of object file we get the
* header of and all header must match. We cannot mix object module types.
*/
static unsigned int elf_object_class = ELFCLASSNONE;
static unsigned int elf_object_machinetype = EM_NONE;
static unsigned int elf_object_datatype = ELFDATANONE;
/**
* A single place to initialise the libelf library. This must be called
* before any libelf API calls are made.
*/
static void
libelf_initialise ()
{
static bool libelf_initialised = false;
if (!libelf_initialised)
{
if (::elf_version (EV_CURRENT) == EV_NONE)
libelf_error ("initialisation");
libelf_initialised = true;
}
}
relocation::relocation (const symbols::symbol& sym,
elf_addr offset,
elf_xword info,
elf_sxword addend)
: sym (&sym),
offset_ (offset),
info_ (info),
addend_ (addend)
{
}
relocation::relocation ()
: sym (0),
offset_ (0),
info_ (0),
addend_ (0)
{
}
elf_addr
relocation::offset () const
{
return offset_;
}
uint32_t
relocation::type () const
{
return GELF_R_TYPE (info_);
}
elf_xword
relocation::info () const
{
return info_;
}
elf_sxword
relocation::addend () const
{
return addend_;
}
const symbols::symbol&
relocation::symbol () const
{
if (sym)
return *sym;
throw rld::error ("no symbol", "elf:relocation");
}
section::section (file& file_,
int index_,
const std::string& name_,
elf_word type,
elf_xword alignment,
elf_xword flags,
elf_addr addr,
elf_off offset,
elf_xword size,
elf_word link,
elf_word info,
elf_xword entry_size)
: file_ (&file_),
index_ (index_),
name_ (name_),
scn (0),
data_ (0),
rela (false)
{
if (!file_.is_writable ())
throw rld::error ("not writable",
"elf:section" + file_.name () + " (" + name_ + ')');
scn = ::elf_newscn (file_.get_elf ());
if (!scn)
libelf_error ("elf_newscn: " + name_ + " (" + file_.name () + ')');
if (::gelf_getshdr(scn, &shdr) == 0)
libelf_error ("gelf_getshdr: " + name_ + " (" + file_.name () + ')');
shdr.sh_name = 0;
shdr.sh_type = type;
shdr.sh_flags = flags;
shdr.sh_addr = addr;
shdr.sh_offset = offset;
shdr.sh_size = size;
shdr.sh_link = link;
shdr.sh_info = info;
shdr.sh_addralign = alignment;
shdr.sh_entsize = entry_size;
if (type == SHT_NOBITS)
add_data (ELF_T_BYTE, alignment, size);
if (!gelf_update_shdr (scn, &shdr))
libelf_error ("gelf_update_shdr: " + name_ + " (" + file_.name () + ')');
}
section::section (file& file_, int index_)
: file_ (&file_),
index_ (index_),
scn (0),
data_ (0),
rela (false)
{
memset (&shdr, 0, sizeof (shdr));
scn = ::elf_getscn (file_.get_elf (), index_);
if (!scn)
libelf_error ("elf_getscn: " + file_.name ());
if (!::gelf_getshdr (scn, &shdr))
libelf_error ("gelf_getshdr: " + file_.name ());
if (shdr.sh_type != SHT_NULL)
{
name_ = file_.get_string (shdr.sh_name);
data_ = ::elf_getdata (scn, 0);
if (!data_)
{
data_ = ::elf_rawdata (scn, 0);
if (!data_)
libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')');
}
}
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf::section: index=" << index ()
<< " name='" << name () << "'"
<< " size=" << size ()
<< " align=" << alignment ()
<< " flags=0x" << std::hex << flags () << std::dec
<< std::endl;
}
section::section (const section& orig)
: file_ (orig.file_),
index_ (orig.index_),
name_ (orig.name_),
scn (orig.scn),
shdr (orig.shdr),
data_ (orig.data_),
rela (orig.rela),
relocs (orig.relocs)
{
}
section::section ()
: file_ (0),
index_ (-1),
scn (0),
data_ (0),
rela (false)
{
memset (&shdr, 0, sizeof (shdr));
}
void
section::add_data (elf_type type,
elf_xword alignment,
elf_xword size,
void* buffer,
elf_off offset)
{
check_writable ("add_data");
data_ = ::elf_newdata(scn);
if (!data_)
libelf_error ("elf_newdata: " + name_ + " (" + file_->name () + ')');
data_->d_type = type;
data_->d_off = offset;
data_->d_size = size;
data_->d_align = alignment;
data_->d_version = EV_CURRENT;
data_->d_buf = buffer;
if (!gelf_update_shdr (scn, &shdr))
libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')');
}
int
section::index () const
{
check ("index");
return index_;
}
const std::string&
section::name () const
{
check ("name");
return name_;
}
elf_data*
section::data ()
{
check ("data");
return data_;
}
elf_word
section::type () const
{
check ("type");
return shdr.sh_type;
}
elf_xword
section::flags () const
{
check ("flags");
return shdr.sh_flags;
}
elf_addr
section::address () const
{
check ("address");
return shdr.sh_addr;
}
elf_xword
section::alignment () const
{
check ("alignment");
return shdr.sh_addralign;
}
elf_off
section::offset () const
{
check ("offset");
return shdr.sh_offset;
}
elf_word
section::link () const
{
check ("link");
return shdr.sh_link;
}
elf_word
section::info () const
{
check ("info");
return shdr.sh_info;
}
elf_xword
section::size () const
{
check ("size");
return shdr.sh_size;
}
elf_xword
section::entry_size () const
{
check ("entry_size");
return shdr.sh_entsize;
}
int
section::entries () const
{
return size () / entry_size ();
}
bool
section::get_reloc_type () const
{
return rela;
}
void
section::set_name (unsigned int index)
{
check_writable ("set_name");
shdr.sh_name = index;
if (!gelf_update_shdr (scn, &shdr))
libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')');
}
void
section::set_reloc_type (bool rela_)
{
rela = rela_;
}
void
section::add (const relocation& reloc)
{
relocs.push_back (reloc);
}
const relocations&
section::get_relocations () const
{
return relocs;
}
void
section::check (const char* where) const
{
if (!file_ || (index_ < 0) || !scn)
{
std::string w = where;
throw rld::error ("Section not initialised.", "section:check:" + w);
}
}
void
section::check_writable (const char* where) const
{
check (where);
if (!file_->is_writable ())
{
std::string w = where;
throw rld::error ("File is read-only.", "section:check:");
}
}
program_header::program_header ()
{
memset (&phdr, 0, sizeof (phdr));
}
program_header::~program_header ()
{
}
void
program_header::set (elf_word type,
elf_word flags,
elf_off offset,
elf_xword filesz,
elf_xword memsz,
elf_xword align,
elf_addr vaddr,
elf_addr paddr)
{
phdr.p_type = type;
phdr.p_flags = flags;
phdr.p_offset = offset;
phdr.p_vaddr = vaddr;
phdr.p_paddr = paddr;
phdr.p_filesz = filesz;
phdr.p_memsz = memsz;
phdr.p_align = align;
}
file::file ()
: fd_ (-1),
refs (0),
archive (false),
writable (false),
elf_ (0),
mtype (0),
oclass (0),
ident_str (0),
ident_size (0),
ehdr (0),
phdr (0)
{
}
file::~file ()
{
try
{
end ();
}
catch (rld::error re)
{
std::cerr << "error: rld::elf::file::~file: "
<< re.where << ": " << re.what
<< std::endl;
}
catch (...)
{
std::cerr << "error: rld::elf::file::~file: unhandled exception"
<< std::endl;
}
}
void
file::reference_obtain ()
{
++refs;
}
void
file::reference_release ()
{
if (refs > 0)
--refs;
}
void
file::begin (const std::string& name__, int fd__, const bool writable_)
{
begin (name__, fd__, writable_, 0, 0);
}
void
file::begin (const std::string& name__, file& archive_, off_t offset)
{
archive_.check ("begin:archive");
if (archive_.writable)
throw rld::error ("archive is writable", "elf:file:begin");
begin (name__, archive_.fd_, false, &archive_, offset);
}
#define rld_archive_fhdr_size (60)
void
file::begin (const std::string& name__,
int fd__,
const bool writable_,
file* archive_,
off_t offset_)
{
if (fd__ < 0)
throw rld::error ("No file descriptor", "elf:file:begin");
/*
* Begin's are not nesting.
*/
if (elf_ || (fd_ >= 0))
throw rld::error ("Already called", "elf:file:begin");
/*
* Cannot write directly into archive. Create a file then archive it.
*/
if (archive_ && writable_)
throw rld::error ("Cannot write into archives directly",
"elf:file:begin");
libelf_initialise ();
/*
* Is this image part of an archive ?
*/
if (archive_)
{
ssize_t offset = offset_ - rld_archive_fhdr_size;
if (::elf_rand (archive_->elf_, offset) != offset)
libelf_error ("rand: " + archive_->name_);
}
/*
* Note, the elf passed is either the archive or NULL.
*/
elf* elf__ = ::elf_begin (fd__,
writable_ ? ELF_C_WRITE : ELF_C_READ,
archive_ ? archive_->elf_ : 0);
if (!elf__)
libelf_error ("begin: " + name__);
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf::begin: " << elf__ << ' ' << name__ << std::endl;
elf_kind ek = ::elf_kind (elf__);
/*
* If this is inside an archive it must be an ELF file.
*/
if (archive_ && (ek != ELF_K_ELF))
throw rld::error ("File format in archive not ELF",
"elf:file:begin: " + name__);
if (ek == ELF_K_AR)
archive = true;
else if (ek == ELF_K_ELF)
archive = false;
else
throw rld::error ("File format not ELF or archive",
"elf:file:begin: " + name__);
if (!writable_)
{
/*
* If an ELF file make sure they all match. On the first file that
* begins an ELF session record its settings.
*/
if (ek == ELF_K_ELF)
{
oclass = ::gelf_getclass (elf__);
ident_str = ::elf_getident (elf__, &ident_size);
}
}
fd_ = fd__;
name_ = name__;
writable = writable_;
elf_ = elf__;
if (!archive && !writable)
{
load_header ();
load_sections ();
}
}
void
file::end ()
{
if (refs > 0)
throw rld::error ("References still held", "elf:file:end: " + name_);
if (fd_ >= 0)
{
if (!writable)
{
if (ehdr)
{
delete ehdr;
ehdr = 0;
}
if (phdr)
{
delete phdr;
phdr = 0;
}
}
fd_ = -1;
name_.clear ();
archive = false;
oclass = 0;
ident_str = 0;
ident_size = 0;
writable = false;
secs.clear ();
if (elf_)
{
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "libelf::end: " << elf_
<< ' ' << name_ << std::endl;
::elf_end (elf_);
elf_ = 0;
}
}
}
void
file::write ()
{
check_writable ("write");
std::string shstrtab;
for (section_table::iterator sti = secs.begin ();
sti != secs.end ();
++sti)
{
section& sec = (*sti).second;
int added_at = shstrtab.size ();
shstrtab += '\0' + sec.name ();
sec.set_name (added_at + 1);
}
unsigned int shstrtab_name = shstrtab.size () + 1;
/*
* Done this way to clang happy on darwin.
*/
shstrtab += '\0';
shstrtab += ".shstrtab";
/*
* Create the string table section.
*/
section shstrsec (*this,
secs.size () + 1, /* index */
".shstrtab", /* name */
SHT_STRTAB, /* type */
1, /* alignment */
SHF_STRINGS | SHF_ALLOC, /* flags */
0, /* address */
0, /* offset */
shstrtab.size ()); /* size */
shstrsec.add_data (ELF_T_BYTE,
1,
shstrtab.size (),
(void*) shstrtab.c_str ());
shstrsec.set_name (shstrtab_name);
::elf_setshstrndx (elf_, shstrsec.index ());
::elf_flagehdr (elf_, ELF_C_SET, ELF_F_DIRTY);
if (elf_update (elf_, ELF_C_NULL) < 0)
libelf_error ("elf_update:layout: " + name_);
::elf_flagphdr (elf_, ELF_C_SET, ELF_F_DIRTY);
if (::elf_update (elf_, ELF_C_WRITE) < 0)
libelf_error ("elf_update:write: " + name_);
}
void
file::load_header ()
{
check ("load_header");
if (!ehdr)
{
if (!writable)
ehdr = new elf_ehdr;
else
{
throw rld::error ("No ELF header; set the header first",
"elf:file:load_header: " + name_);
}
}
if (::gelf_getehdr (elf_, ehdr) == 0)
error ("gelf_getehdr");
}
unsigned int
file::machinetype () const
{
check_ehdr ("machinetype");
return ehdr->e_machine;
}
unsigned int
file::type () const
{
check_ehdr ("type");
return ehdr->e_type;
}
unsigned int
file::object_class () const
{
check ("object_class");
return oclass;
}
unsigned int
file::data_type () const
{
check ("data_type");
if (!ident_str)
throw rld::error ("No ELF ident str", "elf:file:data_type: " + name_);
return ident_str[EI_DATA];
}
bool
file::is_archive () const
{
check ("is_archive");
return archive;
}
bool
file::is_executable () const
{
check_ehdr ("is_executable");
return ehdr->e_type != ET_REL;
}
bool
file::is_relocatable() const
{
check_ehdr ("is_relocatable");
return ehdr->e_type == ET_REL;
}
int
file::section_count () const
{
check_ehdr ("section_count");
return ehdr->e_shnum;
}
void
file::load_sections ()
{
if (secs.empty ())
{
check ("load_sections_headers");
for (int sn = 0; sn < section_count (); ++sn)
{
section sec (*this, sn);
secs[sec.name ()] = sec;
}
}
}
void
file::get_sections (sections& filtered_secs, unsigned int type)
{
load_sections ();
for (section_table::iterator si = secs.begin ();
si != secs.end ();
++si)
{
section& sec = (*si).second;
if ((type == 0) || (sec.type () == type))
filtered_secs.push_back (&sec);
}
}
section&
file::get_section (int index)
{
load_sections ();
for (section_table::iterator si = secs.begin ();
si != secs.end ();
++si)
{
section& sec = (*si).second;
if (index == sec.index ())
return sec;
}
throw rld::error ("section index '" + rld::to_string (index) + "'not found",
"elf:file:get_section: " + name_);
}
int
file::strings_section () const
{
check_ehdr ("strings_sections");
return ehdr->e_shstrndx;
}
void
file::load_symbols ()
{
if (symbols.empty ())
{
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf:symbol: " << name () << std::endl;
sections symbol_secs;
get_sections (symbol_secs, SHT_SYMTAB);
for (sections::iterator si = symbol_secs.begin ();
si != symbol_secs.end ();
++si)
{
section& sec = *(*si);
int syms = sec.entries ();
for (int s = 0; s < syms; ++s)
{
elf_sym esym;
if (!::gelf_getsym (sec.data (), s, &esym))
error ("gelf_getsym");
std::string name = get_string (sec.link (), esym.st_name);
symbols::symbol sym (s, name, esym);
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf:symbol: " << sym << std::endl;
symbols.push_back (sym);
}
}
}
}
void
file::get_symbols (symbols::pointers& filtered_syms,
bool unresolved,
bool local,
bool weak,
bool global)
{
if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
std::cout << "elf:get-syms: unresolved:" << unresolved
<< " local:" << local
<< " weak:" << weak
<< " global:" << global
<< " " << name_
<< std::endl;
load_symbols ();
filtered_syms.clear ();
for (symbols::bucket::iterator si = symbols.begin ();
si != symbols.end ();
++si)
{
symbols::symbol& sym = *si;
int stype = sym.type ();
int sbind = sym.binding ();
/*
* If wanting unresolved symbols and the type is no-type and the
* section is undefined, or, the type is no-type or object or function
* and the bind is local and we want local symbols, or the bind is weak
* and we want weak symbols, or the bind is global and we want global
* symbols then add the filtered symbols container.
*/
bool add = false;
if ((stype == STT_NOTYPE) &&
(sbind == STB_GLOBAL) &&
(sym.section_index () == SHN_UNDEF))
{
if (unresolved)
add = true;
}
else
{
if (((stype == STT_NOTYPE) ||
(stype == STT_OBJECT) ||
(stype == STT_FUNC)) &&
((weak && (sbind == STB_WEAK)) ||
(!unresolved && ((local && (sbind == STB_LOCAL)) ||
(global && (sbind == STB_GLOBAL))))))
add = true;
}
if (add)
filtered_syms.push_back (&sym);
}
}
const symbols::symbol&
file::get_symbol (const int index) const
{
for (symbols::bucket::const_iterator si = symbols.begin ();
si != symbols.end ();
++si)
{
const symbols::symbol& sym = *si;
if (index == sym.index ())
return sym;
}
throw rld::error ("symbol index '" + rld::to_string (index) + "' not found",
"elf:file:get_symbol: " + name_);
}
void
file::load_relocations ()
{
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf:reloc: " << name () << std::endl;
sections rel_secs;
get_sections (rel_secs, SHT_REL);
get_sections (rel_secs, SHT_RELA);
for (sections::iterator si = rel_secs.begin ();
si != rel_secs.end ();
++si)
{
section& sec = *(*si);
section& targetsec = get_section (sec.info ());
int rels = sec.entries ();
bool rela = sec.type () == SHT_RELA;
targetsec.set_reloc_type (rela);
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf:reloc: " << sec.name ()
<< " -> " << targetsec.name ()
<< std::endl;
for (int r = 0; r < rels; ++r)
{
if (rela)
{
elf_rela erela;
if (!::gelf_getrela (sec.data (), r, &erela))
error ("gelf_getrela");
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf:reloc: rela: offset: " << erela.r_offset
<< " sym:" << GELF_R_SYM (erela.r_info)
<< " type:" << GELF_R_TYPE (erela.r_info)
<< " addend:" << erela.r_addend
<< std::endl;
/*
* The target section is updated with the fix up, and symbol
* section indicates the section offset being referenced by the
* fixup.
*/
const symbols::symbol& sym = get_symbol (GELF_R_SYM (erela.r_info));
relocation reloc (sym,
erela.r_offset,
erela.r_info,
erela.r_addend);
targetsec.add (reloc);
}
else
{
elf_rel erel;
if (!::gelf_getrel (sec.data (), r, &erel))
error ("gelf_getrel");
if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
std::cout << "elf:reloc: rel: offset: " << erel.r_offset
<< " sym:" << GELF_R_SYM (erel.r_info)
<< " type:" << GELF_R_TYPE (erel.r_info)
<< std::endl;
const symbols::symbol& sym = get_symbol (GELF_R_SYM (erel.r_info));
relocation reloc (sym, erel.r_offset, erel.r_info);
targetsec.add (reloc);
}
}
}
}
std::string
file::get_string (int section, size_t offset)
{
check ("get_string");
char* s = ::elf_strptr (elf_, section, offset);
if (!s)
error ("elf_strptr");
return s;
}
std::string
file::get_string (size_t offset)
{
check ("get_string");
char* s = ::elf_strptr (elf_, strings_section (), offset);
if (!s)
error ("elf_strptr");
return s;
}
void
file::set_header (elf_half type,
int class_,
elf_half machinetype,
unsigned char datatype)
{
check_writable ("set_header");
if (ehdr)
throw rld::error ("ELF header already set",
"elf:file:set_header: " + name_);
ehdr = (elf_ehdr*) ::gelf_newehdr (elf_, class_);
if (ehdr == 0)
error ("gelf_newehdr");
if (class_ == ELFCLASS32)
{
if((ehdr = (elf_ehdr*) ::elf32_getehdr (elf_)) == 0)
error ("elf32_getehdr");
}
else if (::gelf_getehdr (elf_, ehdr) == 0)
error ("gelf_getehdr");
if (class_ == ELFCLASS32)
{
((elf32_ehdr*)ehdr)->e_type = type;
((elf32_ehdr*)ehdr)->e_machine = machinetype;
((elf32_ehdr*)ehdr)->e_flags = 0;
((elf32_ehdr*)ehdr)->e_ident[EI_DATA] = datatype;
((elf32_ehdr*)ehdr)->e_version = EV_CURRENT;
}
else
{
ehdr->e_type = type;
ehdr->e_machine = machinetype;
ehdr->e_flags = 0;
ehdr->e_ident[EI_DATA] = datatype;
ehdr->e_version = EV_CURRENT;
}
::elf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY);
}
void
file::add (section& sec)
{
check_writable ("add");
secs[sec.name ()] = sec;
}
void
file::add (program_header& phdr)
{
check_writable ("add");
phdrs.push_back (phdr);
}
elf*
file::get_elf ()
{
return elf_;
}
const std::string&
file::name () const
{
return name_;
}
bool
file::is_writable () const
{
return writable;
}
size_t
file::machine_size () const
{
size_t bytes;
switch (object_class ())
{
case ELFCLASS64:
bytes = sizeof (uint64_t);
break;
default:
bytes = sizeof (uint32_t);
break;
}
return bytes;
}
bool
file::is_little_endian () const
{
return data_type () == ELFDATA2LSB;
}
void
file::check (const char* where) const
{
if (!elf_ || (fd_ < 0))
{
std::string w = where;
throw rld::error ("No ELF file or file descriptor", "elf:file:" + w);
}
}
void
file::check_ehdr (const char* where) const
{
check (where);
if (!ehdr)
{
std::string w = where;
throw rld::error ("no elf header", "elf:file:" + w);
}
}
void
file::check_phdr (const char* where) const
{
check (where);
if (!phdr)
{
std::string w = where;
throw rld::error ("no elf program header", "elf:file:" + w);
}
}
void
file::check_writable (const char* where) const
{
check (where);
if (!writable)
{
std::string w = where;
throw rld::error ("not writable", "elf:file:" + w);
}
}
void
file::error (const char* where) const
{
std::string w = where;
libelf_error (w + ": " + name_);
}
const std::string
machine_type (unsigned int machinetype)
{
struct types_and_labels
{
const char* name; //< The RTEMS label.
unsigned int machinetype; //< The machine type.
};
types_and_labels types_to_labels[] =
{
{ "arm", EM_ARM },
{ "avr", EM_AVR },
{ "bfin", EM_BLACKFIN },
{ "h8300", EM_H8_300 },
{ "i386", EM_386 },
/* { "m32c", EM_M32C }, Not in libelf I imported */
{ "m32r", EM_M32R },
{ "m68k", EM_68K },
{ "m68k", EM_COLDFIRE },
{ "mips", EM_MIPS },
{ "powerpc", EM_PPC },
#ifndef EM_RISCV
{ "riscv", 243 }, /* If not in libelf yet */
#else
{ "riscv", EM_RISCV },
#endif
{ "sh", EM_SH },
{ "sparc", EM_SPARC },
{ "sparc64", EM_SPARC },
{ 0, EM_NONE }
};
int m = 0;
while (types_to_labels[m].machinetype != EM_NONE)
{
if (machinetype == types_to_labels[m].machinetype)
return types_to_labels[m].name;
++m;
}
std::ostringstream what;
what << "unknown machine type: " << elf_object_machinetype;
throw rld::error (what, "machine-type");
}
const std::string
machine_type ()
{
return machine_type (elf_object_machinetype);
}
unsigned int
object_class ()
{
return elf_object_class;
}
unsigned int
object_machine_type ()
{
return elf_object_machinetype;
}
unsigned int
object_datatype ()
{
return elf_object_datatype;
}
void
check_file(const file& file)
{
if (elf_object_machinetype == EM_NONE)
elf_object_machinetype = file.machinetype ();
else if (file.machinetype () != elf_object_machinetype)
{
std::ostringstream oss;
oss << "elf:check_file:" << file.name ()
<< ": " << elf_object_machinetype << '/' << file.machinetype ();
throw rld::error ("Mixed machine types not supported.", oss.str ());
}
if (elf_object_class == ELFCLASSNONE)
elf_object_class = file.object_class ();
else if (file.object_class () != elf_object_class)
throw rld::error ("Mixed classes not allowed (32bit/64bit).",
"elf:check_file: " + file.name ());
if (elf_object_datatype == ELFDATANONE)
elf_object_datatype = file.data_type ();
else if (elf_object_datatype != file.data_type ())
throw rld::error ("Mixed data types not allowed (LSB/MSB).",
"elf:check_file: " + file.name ());
}
}
}