Skip to content

Commit

Permalink
add support to load ET_DYN elf
Browse files Browse the repository at this point in the history
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 <cleger@rivosinc.com>
  • Loading branch information
clementleger committed May 21, 2024
1 parent c81d8e7 commit 436ff1e
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 14 deletions.
2 changes: 2 additions & 0 deletions fesvr/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stdint.h>

#define ET_EXEC 2
#define ET_DYN 3
#define EM_RISCV 243
#define EM_NONE 0
#define EV_CURRENT 1
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fesvr/elf2hex.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 12 additions & 7 deletions fesvr/elfloader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
#include <map>
#include <cerrno>

std::map<std::string, uint64_t> load_elf(const char* fn, memif_t* memif, reg_t* entry, unsigned required_xlen = 0)
std::map<std::string, uint64_t> 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;
Expand All @@ -41,30 +42,34 @@ std::map<std::string, uint64_t> 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<uint8_t> zeros;
std::map<std::string, uint64_t> symbols;

#define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t, bswap) \
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)) { \
uint32_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()); \
} \
} \
} \
Expand Down Expand Up @@ -96,7 +101,7 @@ std::map<std::string, uint64_t> 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)
Expand Down
3 changes: 2 additions & 1 deletion fesvr/elfloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <string>

class memif_t;
std::map<std::string, uint64_t> load_elf(const char* fn, memif_t* memif, reg_t* entry, unsigned required_xlen = 0);
std::map<std::string, uint64_t> load_elf(const char* fn, memif_t* memif, reg_t* entry,
reg_t load_offset, unsigned required_xlen = 0);

#endif
8 changes: 4 additions & 4 deletions fesvr/htif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ static void bad_address(const std::string& situation, reg_t addr)
exit(-1);
}

std::map<std::string, uint64_t> htif_t::load_payload(const std::string& payload, reg_t* entry)
std::map<std::string, uint64_t> 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)
Expand Down Expand Up @@ -143,7 +143,7 @@ std::map<std::string, uint64_t> 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();
Expand All @@ -152,7 +152,7 @@ std::map<std::string, uint64_t> htif_t::load_payload(const std::string& payload,

void htif_t::load_program()
{
std::map<std::string, uint64_t> symbols = load_payload(targs[0], &entry);
std::map<std::string, uint64_t> symbols = load_payload(targs[0], &entry, load_offset);

if (symbols.count("tohost") && symbols.count("fromhost")) {
tohost_addr = symbols["tohost"];
Expand All @@ -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 {
Expand Down
5 changes: 4 additions & 1 deletion fesvr/htif.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "syscall.h"
#include "device.h"
#include "byteorder.h"
#include "../riscv/platform.h"
#include <string.h>
#include <map>
#include <vector>
Expand Down Expand Up @@ -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<std::string, uint64_t> load_payload(const std::string& payload, reg_t* entry);
virtual std::map<std::string, uint64_t> load_payload(const std::string& payload, reg_t* entry,
reg_t load_addr);
virtual void load_program();
virtual void idle() {}

Expand All @@ -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;
Expand Down

0 comments on commit 436ff1e

Please sign in to comment.