Implement loading of test signatures

This commit is contained in:
Konstantin Nazarov 2024-12-15 21:33:00 +00:00
parent 89d9ca3814
commit 40179ed237
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
6 changed files with 167 additions and 29 deletions

View file

@ -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<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
@ -143,7 +152,7 @@ std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
throw std::runtime_error("No loadable sections found");
}
std::vector<uint8_t> loadedData(memoryEnd-memoryStart, 0);
std::vector<uint8_t> loadedData(memoryEnd - memoryStart, 0);
// Load .text and .sdata sections
for (const Elf32Section& shdr : sectionHeaders) {
@ -153,8 +162,9 @@ std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
}
file.seekg(shdr.sh_offset);
file.read(reinterpret_cast<char*>(&loadedData[shdr.sh_addr-memoryStart]),
shdr.sh_size);
file.read(
reinterpret_cast<char*>(&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<uint8_t> load_elf(const std::string& filename, size_t memory_size) {
return loadedData;
}
std::tuple<uint32_t, uint32_t> 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<char*>(&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<Elf32Section> sectionHeaders(ehdr.e_shnum);
for (size_t i = 0; i < ehdr.e_shnum; ++i) {
file.read(reinterpret_cast<char*>(&sectionHeaders[i]),
sizeof(Elf32Section));
if (!file) {
throw std::runtime_error("Failed to read section headers");
}
}
// Load symbols
std::vector<Elf32Sym> sectionSymTable;
std::vector<char> 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<Elf32Sym>(symbol_count);
file.seekg(shdr.sh_offset);
file.read(reinterpret_cast<char*>(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<char>(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 = &sectionStrTable[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<uint32_t, uint32_t>(0, 0);
}
return std::make_tuple(begin_signature, end_signature);
}

View file

@ -5,3 +5,5 @@
#include <vector>
std::vector<uint8_t> load_elf(const std::string& filename, size_t memory_size);
std::tuple<uint32_t, uint32_t> elf_get_signature(const std::string& filename);

View file

@ -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<uint8_t> memory;
std::tuple<uint32_t, uint32_t> 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<uint8_t> 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<uint32_t *>(&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"

View file

@ -47,6 +47,7 @@ void VM::setreg(int regnum, uint32_t value) {
std::vector<uint8_t> VM::read_memory(size_t start, size_t size) {
if (start >= PROGRAM_ADDR) {
start -= PROGRAM_ADDR;
if (start + size > memory_.size()) {
return std::vector<uint8_t>(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

View file

@ -15,6 +15,7 @@
li x1, 1; \
write_tohost: \
sw x1, tohost, t5; \
ebreak
j write_tohost;
#define RVMODEL_BOOT

View file

@ -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"'