diff options
Diffstat (limited to 'linkers/rld-elf.cpp')
-rw-r--r-- | linkers/rld-elf.cpp | 1210 |
1 files changed, 1210 insertions, 0 deletions
diff --git a/linkers/rld-elf.cpp b/linkers/rld-elf.cpp new file mode 100644 index 0000000..8b2ac5e --- /dev/null +++ b/linkers/rld-elf.cpp @@ -0,0 +1,1210 @@ +/* + * 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), + archive (false), + writable (false), + elf_ (0), + oclass (0), + ident_str (0), + ident_size (0), + ehdr (0), + phdr (0) + { + } + + file::~file () + { + end (); + } + + 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__); + else + { + 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 (elf_) + { + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + std::cout << "libelf::end: " << elf_ + << ' ' << name_ << std::endl; + ::elf_end (elf_); + elf_ = 0; + } + + if (fd_ >= 0) + { + if (!writable) + { + if (ehdr) + { + delete ehdr; + ehdr = 0; + } + if (phdr) + { + delete phdr; + phdr = 0; + } + } + + fd_ = -1; + name_.clear (); + archive = false; + elf_ = 0; + oclass = 0; + ident_str = 0; + ident_size = 0; + writable = false; + secs.clear (); + } + } + + 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; + } + + 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 }, + { "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 ()); + } + + } +} |