From 40179ed237fe48943b2c8423ef4aeae66b431b3d Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Sun, 15 Dec 2024 21:33:00 +0000 Subject: [PATCH] Implement loading of test signatures --- src/elf.cpp | 141 +++++++++++++++++++++++++++++++------- src/elf.hpp | 2 + src/rve.cpp | 40 ++++++++++- src/vm.cpp | 8 +++ test/rve/env/model_test.h | 3 +- test/rve/riscof_rve.py | 2 +- 6 files changed, 167 insertions(+), 29 deletions(-) diff --git a/src/elf.cpp b/src/elf.cpp index 96823fa..1b13a4e 100644 --- a/src/elf.cpp +++ b/src/elf.cpp @@ -57,29 +57,38 @@ struct Elf32Section { uint32_t sh_entsize; // Entry size if section holds table }; -bool should_load_section(const Elf32Section& section_header) { - // Check if the section has the SHF_ALLOC flag, which indicates - // the section should be loaded into memory - if (section_header.sh_flags & SHF_ALLOC) { - // Further filter out sections that shouldn't be loaded - switch (section_header.sh_type) { - case SHT_PROGBITS: // Typically contains code or data - case SHT_INIT_ARRAY: // Initialization function pointers - case SHT_FINI_ARRAY: // Termination function pointers - case SHT_NOBITS: // .bss section (uninitialized data) - return true; +struct Elf32Sym { + uint32_t st_name; // Symbol name (index into string table) + uint32_t st_value; // Symbol value (address or offset) + uint32_t st_size; // Size of the symbol + uint8_t st_info; // Symbol type and binding attributes + uint8_t st_other; // Symbol visibility + uint16_t st_shndx; // Section header index related to this symbol +}; - // Exclude debug and other non-loadable sections - case SHT_SYMTAB: // Symbol table - case SHT_STRTAB: // String table - case SHT_RELA: // Relocation entries - case SHT_DYNAMIC: // Dynamic linking information - case SHT_NOTE: // Note section - default: - return false; - } +bool should_load_section(const Elf32Section& section_header) { + // Check if the section has the SHF_ALLOC flag, which indicates + // the section should be loaded into memory + if (section_header.sh_flags & SHF_ALLOC) { + // Further filter out sections that shouldn't be loaded + switch (section_header.sh_type) { + case SHT_PROGBITS: // Typically contains code or data + case SHT_INIT_ARRAY: // Initialization function pointers + case SHT_FINI_ARRAY: // Termination function pointers + case SHT_NOBITS: // .bss section (uninitialized data) + return true; + + // Exclude debug and other non-loadable sections + case SHT_SYMTAB: // Symbol table + case SHT_STRTAB: // String table + case SHT_RELA: // Relocation entries + case SHT_DYNAMIC: // Dynamic linking information + case SHT_NOTE: // Note section + default: + return false; } - return false; + } + return false; } std::vector load_elf(const std::string& filename, size_t memory_size) { @@ -143,7 +152,7 @@ std::vector load_elf(const std::string& filename, size_t memory_size) { throw std::runtime_error("No loadable sections found"); } - std::vector loadedData(memoryEnd-memoryStart, 0); + std::vector loadedData(memoryEnd - memoryStart, 0); // Load .text and .sdata sections for (const Elf32Section& shdr : sectionHeaders) { @@ -153,8 +162,9 @@ std::vector load_elf(const std::string& filename, size_t memory_size) { } file.seekg(shdr.sh_offset); - file.read(reinterpret_cast(&loadedData[shdr.sh_addr-memoryStart]), - shdr.sh_size); + file.read( + reinterpret_cast(&loadedData[shdr.sh_addr - memoryStart]), + shdr.sh_size); if (!file) { throw std::runtime_error("Failed to read section data"); } @@ -163,3 +173,86 @@ std::vector load_elf(const std::string& filename, size_t memory_size) { return loadedData; } + +std::tuple elf_get_signature(const std::string& filename) { + std::ifstream file(filename, std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("Failed to open ELF file"); + } + + // Read the ELF header + Elf32Header ehdr; + file.read(reinterpret_cast(&ehdr), sizeof(ehdr)); + if (!file) { + throw std::runtime_error("Failed to read ELF header"); + } + + // Validate ELF magic and basic properties + if (std::memcmp(ehdr.e_ident, ELF_MAGIC, sizeof(ELF_MAGIC)) != 0) { + throw std::runtime_error("Invalid ELF magic number"); + } + if (ehdr.e_ident[4] != ELF_CLASS_32 || ehdr.e_ident[5] != ELF_LITTLE_ENDIAN) { + throw std::runtime_error("Unsupported ELF class or endianness"); + } + if (ehdr.e_type != ELF_TYPE_EXECUTABLE || + ehdr.e_machine != ELF_MACHINE_RISCV) { + throw std::runtime_error("Unsupported ELF type or machine"); + } + + // Read section headers + file.seekg(ehdr.e_shoff); + std::vector sectionHeaders(ehdr.e_shnum); + for (size_t i = 0; i < ehdr.e_shnum; ++i) { + file.read(reinterpret_cast(§ionHeaders[i]), + sizeof(Elf32Section)); + if (!file) { + throw std::runtime_error("Failed to read section headers"); + } + } + + // Load symbols + std::vector sectionSymTable; + std::vector sectionStrTable; + + for (const Elf32Section& shdr : sectionHeaders) { + if (shdr.sh_type == SHT_SYMTAB) { + size_t symbol_count = shdr.sh_size / shdr.sh_entsize; + sectionSymTable = std::vector(symbol_count); + + file.seekg(shdr.sh_offset); + file.read(reinterpret_cast(sectionSymTable.data()), shdr.sh_size); + if (!file) { + throw std::runtime_error("Failed to read section symbol table"); + } + + const Elf32Section& strtab_shdr = sectionHeaders[shdr.sh_link]; + + sectionStrTable = std::vector(strtab_shdr.sh_size); + file.seekg(strtab_shdr.sh_offset); + file.read(sectionStrTable.data(), strtab_shdr.sh_size); + if (!file) { + throw std::runtime_error("Failed to read section symbol string table"); + } + } + } + + uint32_t begin_signature = 0; + uint32_t end_signature = 0; + + for (const Elf32Sym sym : sectionSymTable) { + const char* name = §ionStrTable[sym.st_name]; + + if (std::strcmp(name, "begin_signature") == 0) { + begin_signature = sym.st_value; + } + if (std::strcmp(name, "end_signature") == 0) { + end_signature = sym.st_value; + } + } + + if (end_signature == 0 || begin_signature >= end_signature) { + return std::make_tuple(0, 0); + } + + return std::make_tuple(begin_signature, end_signature); +} diff --git a/src/elf.hpp b/src/elf.hpp index 99534d2..1562c76 100644 --- a/src/elf.hpp +++ b/src/elf.hpp @@ -5,3 +5,5 @@ #include std::vector load_elf(const std::string& filename, size_t memory_size); + +std::tuple elf_get_signature(const std::string& filename); diff --git a/src/rve.cpp b/src/rve.cpp index a8c1abe..7c7cc6c 100644 --- a/src/rve.cpp +++ b/src/rve.cpp @@ -14,12 +14,19 @@ int main(int argc, char *argv[]) { bool debug = false; std::string program_filename = ""; + std::string signature_filename = ""; for (int i = 1; i < argc; ++i) { - if (std::string(argv[i]) == "--debug") + if (std::string(argv[i]) == "--debug") { debug = true; - else + } else if (std::string(argv[i]) == "--signature") { + if (i + 1 < argc) { + signature_filename = argv[i + 1]; + ++i; + } + } else { program_filename = std::filesystem::absolute(argv[i]); + } } if (program_filename == "") { std::cerr << "Expected filename of program to execute" << std::endl; @@ -27,14 +34,17 @@ int main(int argc, char *argv[]) { } std::vector memory; + std::tuple signature; try { memory = load_elf(program_filename, MEMORY_SIZE); + + signature = elf_get_signature(program_filename); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; return 1; } - memory.resize(MEMORY_SIZE, 0); + memory.resize(std::max(memory.size(), MEMORY_SIZE), 0); VM vm(memory, program_filename); @@ -46,6 +56,30 @@ int main(int argc, char *argv[]) { std::cerr << "Emulator error: " << e.what() << std::endl; return 1; } + + if (signature_filename.size() > 0) { + uint32_t signature_begin = std::get<0>(signature) + 4; + uint32_t signature_end = std::get<1>(signature); + + std::vector mem = + vm.read_memory(signature_begin, signature_end - signature_begin); + + std::ofstream file(signature_filename); + if (!file) { + throw std::runtime_error("Failed to open signature file for writing"); + } + + for (size_t i = 0; i < mem.size() / 4; i++) { + uint32_t val = *reinterpret_cast(&mem[i * 4]); + file << std::hex << std::setfill('0') << std::setw(8) << val << std::dec + << "\n"; + } + + file.close(); + if (!file) { + throw std::runtime_error("Error occurred while writing to file"); + } + } } else { // to debug, do: "set debug remote 1" in gdb // and then "target remote :1234" diff --git a/src/vm.cpp b/src/vm.cpp index 238be6c..3eb470a 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -47,6 +47,7 @@ void VM::setreg(int regnum, uint32_t value) { std::vector VM::read_memory(size_t start, size_t size) { if (start >= PROGRAM_ADDR) { + start -= PROGRAM_ADDR; if (start + size > memory_.size()) { return std::vector(size, 0); } @@ -172,6 +173,13 @@ void VM::step() { int32_t imm; switch (opcode) { + case 0x0F: { + if (instr == 0xff0000f) { // fence iorw, iorw + } else { + throw std::runtime_error("Unknown fence instruction"); + } + break; + } case 0x33: { // R-type if (funct7 == 0x00) { if (funct3 == 0x0) { // ADD diff --git a/test/rve/env/model_test.h b/test/rve/env/model_test.h index 80101da..39727de 100644 --- a/test/rve/env/model_test.h +++ b/test/rve/env/model_test.h @@ -15,6 +15,7 @@ li x1, 1; \ write_tohost: \ sw x1, tohost, t5; \ + ebreak j write_tohost; #define RVMODEL_BOOT @@ -28,7 +29,7 @@ //RV_COMPLIANCE_DATA_END #define RVMODEL_DATA_END \ .align 4;\ - .global end_signature; end_signature: + .global end_signature; end_signature: //RVTEST_IO_INIT #define RVMODEL_IO_INIT diff --git a/test/rve/riscof_rve.py b/test/rve/riscof_rve.py index 991c2f3..7a7e8f6 100644 --- a/test/rve/riscof_rve.py +++ b/test/rve/riscof_rve.py @@ -145,7 +145,7 @@ class rve(pluginTemplate): # echo statement. if self.target_run: # set up the simulation command. Template is for spike. Please change. - simcmd = self.dut_exe + ' {0}'.format(elf) + simcmd = self.dut_exe + ' --signature {0} {1}'.format(sig_file, elf) else: simcmd = 'echo "NO RUN"'