From a316a37331aaaa4c8905ba37a86bde42a2c75343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Wed, 15 May 2024 17:15:40 +0200 Subject: add support to load ET_DYN elf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiled as PIE, executable can be loaded at any memory address. Lately, OpenSBI switched to such behavior and spike was not able to load it anymore. This patch add an additional load_offset parameter for load_elf(). This load_offset value is passed as DRAM_BASE and used only for ET_DYN elfs. Signed-off-by: Clément Léger --- fesvr/elf.h | 2 ++ fesvr/elf2hex.cc | 2 +- fesvr/elfloader.cc | 19 ++++++++++++------- fesvr/elfloader.h | 3 ++- fesvr/htif.cc | 8 ++++---- fesvr/htif.h | 5 ++++- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/fesvr/elf.h b/fesvr/elf.h index 7b38bf1..b5a2a8d 100644 --- a/fesvr/elf.h +++ b/fesvr/elf.h @@ -6,6 +6,7 @@ #include #define ET_EXEC 2 +#define ET_DYN 3 #define EM_RISCV 243 #define EM_NONE 0 #define EV_CURRENT 1 @@ -21,6 +22,7 @@ #define IS_ELFLE(hdr) (IS_ELF(hdr) && (hdr).e_ident[5] == 1) #define IS_ELFBE(hdr) (IS_ELF(hdr) && (hdr).e_ident[5] == 2) #define IS_ELF_EXEC(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_type) == ET_EXEC) +#define IS_ELF_DYN(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_type) == ET_DYN) #define IS_ELF_RISCV(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_machine) == EM_RISCV) #define IS_ELF_EM_NONE(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_machine) == EM_NONE) #define IS_ELF_VCURRENT(hdr) (IS_ELF(hdr) && ELF_SWAP((hdr), (hdr).e_version) == EV_CURRENT) diff --git a/fesvr/elf2hex.cc b/fesvr/elf2hex.cc index 327cf2d..2638823 100644 --- a/fesvr/elf2hex.cc +++ b/fesvr/elf2hex.cc @@ -40,7 +40,7 @@ int main(int argc, char** argv) htif_hexwriter_t htif(base, width, depth); memif_t memif(&htif); reg_t entry; - load_elf(argv[3], &memif, &entry); + load_elf(argv[3], &memif, &entry, 0); std::cout << htif; return 0; diff --git a/fesvr/elfloader.cc b/fesvr/elfloader.cc index 391afa0..5cab050 100644 --- a/fesvr/elfloader.cc +++ b/fesvr/elfloader.cc @@ -18,7 +18,8 @@ #include #include -std::map load_elf(const char* fn, memif_t* memif, reg_t* entry, unsigned required_xlen = 0) +std::map load_elf(const char* fn, memif_t* memif, reg_t* entry, + reg_t load_offset, unsigned required_xlen = 0) { int fd = open(fn, O_RDONLY); struct stat s; @@ -41,10 +42,14 @@ std::map load_elf(const char* fn, memif_t* memif, reg_t* throw incompat_xlen(required_xlen, xlen); } assert(IS_ELFLE(*eh64) || IS_ELFBE(*eh64)); - assert(IS_ELF_EXEC(*eh64)); + assert(IS_ELF_EXEC(*eh64) || IS_ELF_DYN(*eh64)); assert(IS_ELF_RISCV(*eh64) || IS_ELF_EM_NONE(*eh64)); assert(IS_ELF_VCURRENT(*eh64)); + if (IS_ELF_EXEC(*eh64)) { + load_offset = 0; + } + std::vector zeros; std::map symbols; @@ -52,19 +57,19 @@ std::map load_elf(const char* fn, memif_t* memif, reg_t* do { \ ehdr_t* eh = (ehdr_t*)buf; \ phdr_t* ph = (phdr_t*)(buf + bswap(eh->e_phoff)); \ - *entry = bswap(eh->e_entry); \ + *entry = bswap(eh->e_entry) + load_offset; \ assert(size >= bswap(eh->e_phoff) + bswap(eh->e_phnum) * sizeof(*ph)); \ for (unsigned i = 0; i < bswap(eh->e_phnum); i++) { \ if (bswap(ph[i].p_type) == PT_LOAD && bswap(ph[i].p_memsz)) { \ + reg_t load_addr = bswap(ph[i].p_paddr) + load_offset; \ if (bswap(ph[i].p_filesz)) { \ assert(size >= bswap(ph[i].p_offset) + bswap(ph[i].p_filesz)); \ - memif->write(bswap(ph[i].p_paddr), bswap(ph[i].p_filesz), \ + memif->write(load_addr, bswap(ph[i].p_filesz), \ (uint8_t*)buf + bswap(ph[i].p_offset)); \ } \ if (size_t pad = bswap(ph[i].p_memsz) - bswap(ph[i].p_filesz)) { \ zeros.resize(pad); \ - memif->write(bswap(ph[i].p_paddr) + bswap(ph[i].p_filesz), pad, \ - zeros.data()); \ + memif->write(load_addr + bswap(ph[i].p_filesz), pad, zeros.data()); \ } \ } \ } \ @@ -96,7 +101,7 @@ std::map load_elf(const char* fn, memif_t* memif, reg_t* bswap(sh[strtabidx].sh_size) - bswap(sym[i].st_name); \ assert(bswap(sym[i].st_name) < bswap(sh[strtabidx].sh_size)); \ assert(strnlen(strtab + bswap(sym[i].st_name), max_len) < max_len); \ - symbols[strtab + bswap(sym[i].st_name)] = bswap(sym[i].st_value); \ + symbols[strtab + bswap(sym[i].st_name)] = bswap(sym[i].st_value) + load_offset; \ } \ } \ } while (0) diff --git a/fesvr/elfloader.h b/fesvr/elfloader.h index ae4ee78..0a250cd 100644 --- a/fesvr/elfloader.h +++ b/fesvr/elfloader.h @@ -8,6 +8,7 @@ #include class memif_t; -std::map load_elf(const char* fn, memif_t* memif, reg_t* entry, unsigned required_xlen = 0); +std::map load_elf(const char* fn, memif_t* memif, reg_t* entry, + reg_t load_offset, unsigned required_xlen = 0); #endif diff --git a/fesvr/htif.cc b/fesvr/htif.cc index 8b5eb8d..46f15d3 100644 --- a/fesvr/htif.cc +++ b/fesvr/htif.cc @@ -103,7 +103,7 @@ static void bad_address(const std::string& situation, reg_t addr) exit(-1); } -std::map htif_t::load_payload(const std::string& payload, reg_t* entry) +std::map htif_t::load_payload(const std::string& payload, reg_t* entry, reg_t load_offset) { std::string path; if (access(payload.c_str(), F_OK) == 0) @@ -143,7 +143,7 @@ std::map htif_t::load_payload(const std::string& payload, } preload_aware_memif(this); try { - return load_elf(path.c_str(), &preload_aware_memif, entry, expected_xlen); + return load_elf(path.c_str(), &preload_aware_memif, entry, load_offset, expected_xlen); } catch (mem_trap_t& t) { bad_address("loading payload " + payload, t.get_tval()); abort(); @@ -152,7 +152,7 @@ std::map htif_t::load_payload(const std::string& payload, void htif_t::load_program() { - std::map symbols = load_payload(targs[0], &entry); + std::map symbols = load_payload(targs[0], &entry, load_offset); if (symbols.count("tohost") && symbols.count("fromhost")) { tohost_addr = symbols["tohost"]; @@ -169,7 +169,7 @@ void htif_t::load_program() for (auto payload : payloads) { reg_t dummy_entry; - load_payload(payload, &dummy_entry); + load_payload(payload, &dummy_entry, 0); } class nop_memif_t : public memif_t { diff --git a/fesvr/htif.h b/fesvr/htif.h index dd7c060..74511f5 100644 --- a/fesvr/htif.h +++ b/fesvr/htif.h @@ -7,6 +7,7 @@ #include "syscall.h" #include "device.h" #include "byteorder.h" +#include "../riscv/platform.h" #include #include #include @@ -58,7 +59,8 @@ class htif_t : public chunked_memif_t virtual size_t chunk_align() = 0; virtual size_t chunk_max_size() = 0; - virtual std::map load_payload(const std::string& payload, reg_t* entry); + virtual std::map load_payload(const std::string& payload, reg_t* entry, + reg_t load_addr); virtual void load_program(); virtual void idle() {} @@ -79,6 +81,7 @@ class htif_t : public chunked_memif_t void register_devices(); void usage(const char * program_name); unsigned int expected_xlen = 0; + const reg_t load_offset = DRAM_BASE; memif_t mem; reg_t entry; bool writezeros; -- cgit v1.1