diff --git a/.gitmodules b/.gitmodules index cc399330..2db6b7be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "riscv-tests"] path = tests/riscv-official/riscv-tests url = https://github.com/riscv-software-src/riscv-tests.git +[submodule "external/libelfin"] + path = external/libelfin + url = https://github.com/mortbopet/libelfin diff --git a/external/libelfin b/external/libelfin new file mode 160000 index 00000000..49d16531 --- /dev/null +++ b/external/libelfin @@ -0,0 +1 @@ +Subproject commit 49d16531a11f5f288e77795a5c6bdd75b46657f7 diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index f3cca553..ebb42560 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -77,7 +77,7 @@ add_library(machine STATIC ${machine_HEADERS}) target_link_libraries(machine PRIVATE ${QtLib}::Core - PUBLIC libelf) + PUBLIC elf++ dwarf++) if(NOT ${WASM}) # Machine tests (not available on WASM) @@ -181,7 +181,7 @@ if(NOT ${WASM}) symboltable.h ) target_link_libraries(program_loader_test - PRIVATE ${QtLib}::Core ${QtLib}::Test libelf) + PRIVATE ${QtLib}::Core ${QtLib}::Test elf++ dwarf++) add_test(NAME program_loader COMMAND program_loader_test) @@ -217,7 +217,7 @@ if(NOT ${WASM}) machineconfig.cpp ) target_link_libraries(core_test - PRIVATE ${QtLib}::Core ${QtLib}::Test libelf) + PRIVATE ${QtLib}::Core ${QtLib}::Test elf++ dwarf++) add_test(NAME core COMMAND core_test) add_custom_target(machine_unit_tests diff --git a/src/machine/programloader.cpp b/src/machine/programloader.cpp index 878527ad..f7c84121 100644 --- a/src/machine/programloader.cpp +++ b/src/machine/programloader.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include LOG_CATEGORY("machine.ProgramLoader"); @@ -17,141 +19,83 @@ LOG_CATEGORY("machine.ProgramLoader"); using namespace machine; -ProgramLoader::ProgramLoader(const QString &file) : elf_file(file) { - const GElf_Ehdr *elf_ehdr; - // Initialize elf library - if (elf_version(EV_CURRENT) == EV_NONE) { - throw SIMULATOR_EXCEPTION(Input, "Elf library initialization failed", elf_errmsg(-1)); - } - // Open source file - option QIODevice::ExistingOnly cannot be used on Qt - // <5.11 - if (!elf_file.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) { +ProgramLoader::ProgramLoader(const QString &file) { + fd = open(file.toLocal8Bit().constData(), O_RDONLY | O_BINARY); + if (fd < 0) { throw SIMULATOR_EXCEPTION( Input, QString("Can't open input elf file for reading (") + QString(file) + QString(")"), std::strerror(errno)); } - // Initialize elf - if (!(this->elf = elf_begin(elf_file.handle(), ELF_C_READ, nullptr))) { - throw SIMULATOR_EXCEPTION(Input, "Elf read begin failed", elf_errmsg(-1)); - } - // Check elf kind - if (elf_kind(this->elf) != ELF_K_ELF) { - throw SIMULATOR_EXCEPTION( - Input, "Invalid input file elf format, plain elf file expected", ""); - } - elf_ehdr = gelf_getehdr(this->elf, &this->hdr); - if (!elf_ehdr) { - throw SIMULATOR_EXCEPTION(Input, "Getting elf file header failed", elf_errmsg(-1)); + try { + elf_file = elf::elf(elf::create_mmap_loader(fd)); + } catch (const std::exception &e) { + close(fd); + throw SIMULATOR_EXCEPTION(Input, "Elf library initialization failed", e.what()); } - executable_entry = Address(elf_ehdr->e_entry); - // Check elf file format, executable expected, nothing else. - if (this->hdr.e_type != ET_EXEC) { + const auto &hdr = elf_file.get_hdr(); + executable_entry = Address(hdr.entry); + + if (hdr.type != elf::et::exec) { throw SIMULATOR_EXCEPTION(Input, "Invalid input file type", ""); } - // Check elf file architecture, of course only mips is supported. - // Note: This also checks that this is big endian as EM_MIPS is suppose to - // be: MIPS R3000 big-endian - if (this->hdr.e_machine != EM_RISCV) { + + if (hdr.machine != 243) { // EM_RISCV throw SIMULATOR_EXCEPTION(Input, "Invalid input file architecture", ""); } - // Check elf file class, only 32bit architecture is supported. - int elf_class; - if ((elf_class = gelf_getclass(this->elf)) == ELFCLASSNONE) { - throw SIMULATOR_EXCEPTION(Input, "Getting elf class failed", elf_errmsg(-1)); - } - // Get number of program sections in elf file - if (elf_getphdrnum(this->elf, &this->n_secs)) { - throw SIMULATOR_EXCEPTION(Input, "Elf program sections count query failed", elf_errmsg(-1)); - } - if (elf_class == ELFCLASS32) { + if (hdr.ei_class == elf::elfclass::_32) { LOG("Loaded executable: 32bit"); architecture_type = ARCH32; - // Get program sections headers - if (!(sections_headers.arch32 = elf32_getphdr(elf))) { - throw SIMULATOR_EXCEPTION(Input, "Elf program sections get failed", elf_errmsg(-1)); - } - // We want only LOAD sections so we create load_sections_indexes of those sections - for (unsigned i = 0; i < n_secs; i++) { - if (sections_headers.arch32[i].p_type != PT_LOAD) { continue; } - indexes_of_load_sections.push_back(i); - } - } else if (elf_class == ELFCLASS64) { + } else if (hdr.ei_class == elf::elfclass::_64) { LOG("Loaded executable: 64bit"); architecture_type = ARCH64; WARN("64bit simulation is not fully supported."); - // Get program sections headers - if (!(sections_headers.arch64 = elf64_getphdr(elf))) { - throw SIMULATOR_EXCEPTION(Input, "Elf program sections get failed", elf_errmsg(-1)); - } - // We want only LOAD sections so we create load_sections_indexes of those sections - for (unsigned i = 0; i < this->n_secs; i++) { - if (sections_headers.arch64[i].p_type != PT_LOAD) { continue; } - this->indexes_of_load_sections.push_back(i); - } - } else { - WARN("Unsupported elf class: %d", elf_class); throw SIMULATOR_EXCEPTION( Input, "Unsupported architecture type." "This simulator only supports 32bit and 64bit CPUs.", ""); } + + for (const auto &seg : elf_file.segments()) { + if (seg.get_hdr().type == elf::pt::load) { + load_segments.push_back(seg); + } + } } ProgramLoader::ProgramLoader(const char *file) : ProgramLoader(QString::fromLocal8Bit(file)) {} ProgramLoader::~ProgramLoader() { - // Close elf - elf_end(this->elf); - // Close file - elf_file.close(); + if (fd >= 0) { + close(fd); + } } void ProgramLoader::to_memory(Memory *mem) { - // Load program to memory (just dump it byte by byte) - if (architecture_type == ARCH32) { - for (size_t phdrs_i : this->indexes_of_load_sections) { - uint32_t base_address = this->sections_headers.arch32[phdrs_i].p_vaddr; - char *f = elf_rawfile(this->elf, nullptr); - for (unsigned y = 0; y < this->sections_headers.arch32[phdrs_i].p_filesz; y++) { - const auto buffer = (uint8_t)f[this->sections_headers.arch32[phdrs_i].p_offset + y]; - memory_write_u8(mem, base_address + y, buffer); - } - } - } else if (architecture_type == ARCH64) { - for (size_t phdrs_i : this->indexes_of_load_sections) { - uint32_t base_address = this->sections_headers.arch64[phdrs_i].p_vaddr; - char *f = elf_rawfile(this->elf, nullptr); - for (unsigned y = 0; y < this->sections_headers.arch64[phdrs_i].p_filesz; y++) { - const auto buffer = (uint8_t)f[this->sections_headers.arch64[phdrs_i].p_offset + y]; - memory_write_u8(mem, base_address + y, buffer); - } + for (const auto &seg : load_segments) { + uint64_t base_address = seg.get_hdr().vaddr; + const char *data = (const char *)seg.data(); + size_t filesz = seg.get_hdr().filesz; + for (size_t i = 0; i < filesz; i++) { + memory_write_u8(mem, base_address + i, (uint8_t)data[i]); } } } Address ProgramLoader::end() { - uint32_t last = 0; - // Go trough all sections and found out last one - if (architecture_type == ARCH32) { - for (size_t i : this->indexes_of_load_sections) { - Elf32_Phdr *phdr = &(this->sections_headers.arch32[i]); - if ((phdr->p_vaddr + phdr->p_filesz) > last) { last = phdr->p_vaddr + phdr->p_filesz; } - } - } else if (architecture_type == ARCH64) { - for (size_t i : this->indexes_of_load_sections) { - Elf64_Phdr *phdr = &(this->sections_headers.arch64[i]); - if ((phdr->p_vaddr + phdr->p_filesz) > last) { last = phdr->p_vaddr + phdr->p_filesz; } + uint64_t last = 0; + for (const auto &seg : load_segments) { + uint64_t end_addr = seg.get_hdr().vaddr + seg.get_hdr().filesz; + if (end_addr > last) { + last = end_addr; } } - return Address(last + 0x10); // We add offset so we are sure that also - // pipeline is empty TODO propagate address - // deeper + return Address(last + 0x10); } Address ProgramLoader::get_executable_entry() const { @@ -160,42 +104,21 @@ Address ProgramLoader::get_executable_entry() const { SymbolTable *ProgramLoader::get_symbol_table() { auto *p_st = new SymbolTable(); - Elf_Scn *scn = nullptr; - GElf_Shdr shdr; - Elf_Data *data; - int count, ii; - - elf_version(EV_CURRENT); - - while (true) { - if ((scn = elf_nextscn(this->elf, scn)) == nullptr) { return p_st; } - gelf_getshdr(scn, &shdr); - if (shdr.sh_type == SHT_SYMTAB) { - /* found a symbol table, go print it. */ - break; + for (const auto &sec : elf_file.sections()) { + if (sec.get_hdr().type == elf::sht::symtab) { + for (const auto &sym : sec.as_symtab()) { + const auto &d = sym.get_data(); + p_st->add_symbol(sym.get_name().c_str(), d.value, d.size, d.info, d.other); + } } } - - data = elf_getdata(scn, nullptr); - count = shdr.sh_size / shdr.sh_entsize; - - /* retrieve the symbol names */ - for (ii = 0; ii < count; ++ii) { - GElf_Sym sym; - gelf_getsym(data, ii, &sym); - p_st->add_symbol( - elf_strptr(elf, shdr.sh_link, sym.st_name), sym.st_value, sym.st_size, sym.st_info, - sym.st_other); - } - return p_st; } + Endian ProgramLoader::get_endian() const { - // Reading elf endian_id_byte according to the ELF specs. - unsigned char endian_id_byte = this->hdr.e_ident[EI_DATA]; - if (endian_id_byte == ELFDATA2LSB) { + if (elf_file.get_hdr().ei_data == elf::elfdata::lsb) { return LITTLE; - } else if (endian_id_byte == ELFDATA2MSB) { + } else if (elf_file.get_hdr().ei_data == elf::elfdata::msb) { return BIG; } else { throw SIMULATOR_EXCEPTION( @@ -206,6 +129,7 @@ Endian ProgramLoader::get_endian() const { ""); } } + ArchitectureType ProgramLoader::get_architecture_type() const { return architecture_type; } diff --git a/src/machine/programloader.h b/src/machine/programloader.h index c371061a..e92ed60c 100644 --- a/src/machine/programloader.h +++ b/src/machine/programloader.h @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include @@ -37,19 +37,11 @@ class ProgramLoader { ArchitectureType get_architecture_type() const; private: - QFile elf_file; - Elf *elf; - GElf_Ehdr hdr {}; // elf file header - size_t n_secs {}; // number of sections in elf program header + int fd; + elf::elf elf_file; ArchitectureType architecture_type; - -private: - union { - Elf32_Phdr *arch32; - Elf64_Phdr *arch64; - } sections_headers {}; - QVector indexes_of_load_sections; // external index to sections_headers index Address executable_entry; + std::vector load_segments; }; } // namespace machine