From 39df51900dd1f7901fbe6b223111cd4334fc2d48 Mon Sep 17 00:00:00 2001 From: Toni Date: Sun, 8 Mar 2026 22:46:58 +0100 Subject: [PATCH] use mmap for memory, implement gettimeofday, fix setup argc/argv/envp on the stack --- riscv64.cc | 91 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/riscv64.cc b/riscv64.cc index f815dad..404b729 100644 --- a/riscv64.cc +++ b/riscv64.cc @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include using i8 = int8_t; @@ -29,7 +31,8 @@ static_assert(sizeof(size_t) == sizeof(u64), "u64 must be 64-bit"); static_assert(std::endian::native == std::endian::little, "Big endianness not supported"); -static constexpr u64 MEMORY_SIZE = 20 * 1024 * 1024; // should be enough +static constexpr u64 MEMORY_SIZE = + 2ULL * 1024 * 1024 * 1024; // should be enough static constexpr std::array REGS = { "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", "a0", @@ -165,11 +168,23 @@ static constexpr std::array OP_TABLE = {{ class RISCV64 { public: RISCV64(const std::vector &exe_bytes) { + m_memory = (u8 *)mmap(nullptr, MEMORY_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (m_memory == MAP_FAILED) { + std::println(stderr, "Failed to mmap memory"); + exit(1); + } + Elf *elf = elf_memory(const_cast(exe_bytes.data()), exe_bytes.size()); GElf_Ehdr ehdr; gelf_getehdr(elf, &ehdr); + if (ehdr.e_machine != EM_RISCV) { + std::println(stderr, "ehdr.e_machine != EM_RISCV"); + exit(1); + } + m_code_section = get_code_section(elf, ehdr); m_pc = m_code_section.offset; @@ -178,7 +193,7 @@ public: gelf_getphdr(elf, i, &phdr); if (phdr.p_type == PT_LOAD) { std::copy_n(exe_bytes.data() + phdr.p_offset, phdr.p_filesz, - m_memory.data() + phdr.p_vaddr); + m_memory + phdr.p_vaddr); } } elf_end(elf); @@ -187,12 +202,13 @@ public: m_decoded.resize(num_ins); for (u64 i = 0; i < num_ins; i++) { u32 raw; - std::memcpy(&raw, m_memory.data() + m_code_section.offset + i * 4, - sizeof(raw)); + std::memcpy(&raw, m_memory + m_code_section.offset + i * 4, sizeof(raw)); m_decoded[i] = decode_raw(raw); } } + ~RISCV64() { munmap(m_memory, MEMORY_SIZE); } + void disassemble_all() { for (m_pc = m_code_section.offset; m_pc < m_code_section.offset + m_code_section.size; m_pc += 4) { @@ -250,10 +266,36 @@ public: std::println(); } + void push_u64(u64 x) { + m_regs[2] -= 8; + *(u64 *)(m_memory + m_regs[2]) = x; + } + void execute() { m_pc = m_code_section.entrypoint; - m_regs[2] = MEMORY_SIZE - 1024; // set the stack pointer + // set up the stack + i64 &sp = m_regs[2]; + sp = MEMORY_SIZE - 1024; + + // push "program" + const char *prog = "program"; + u64 len = strlen(prog) + 1; + sp -= len; + std::memcpy(m_memory + sp, prog, len); + u64 prog_ptr = sp; + sp &= ~15; + + // auxv = {0} + push_u64(0); + push_u64(0); + // envp = {0} + push_u64(0); + // argv = {prog_ptr, 0} + push_u64(0); + push_u64(prog_ptr); + // argc = 1 + push_u64(1); while (m_pc < MEMORY_SIZE) { m_regs[0] = 0; // clear the zero register @@ -339,10 +381,14 @@ public: } }; break; case Op::DIVW: { - if (m_regs[i.rs2] == 0) { + i32 a = m_regs[i.rs1]; + i32 b = m_regs[i.rs2]; + if (b == 0) { m_regs[i.rd] = (u64)(i64)(-1); + } else if (a == INT32_MIN && b == -1) { + m_regs[i.rd] = (i64)INT32_MIN; } else { - m_regs[i.rd] = (i64)(m_regs[i.rs1] / m_regs[i.rs2]); + m_regs[i.rd] = (i64)(a / b); } }; break; case Op::ECALL: { @@ -388,21 +434,22 @@ public: return; }; break; case 169: { // gettimeofday - // TODO: actually return the time i64 tv_addr = m_regs[10]; i64 tz_addr = m_regs[11]; - u8 tv_buf[16] = { - 0xD2, 0x02, 0x96, 0x49, - 0x00, 0x00, 0x00, 0x00, // tv_sec = 1234567890 - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // tv_usec = 0 - }; - memcpy(&m_memory[tv_addr], tv_buf, 16); + struct timeval tv; + struct timezone tz; - memset(&m_memory[tz_addr], 0, 8); - - m_regs[10] = 0; + i32 ret = gettimeofday(&tv, (tz_addr != 0) ? &tz : nullptr); + if (ret == 0) { + memcpy(&m_memory[tv_addr], &tv, sizeof(tv)); + if (tz_addr != 0) { + memcpy(&m_memory[tz_addr], &tz, sizeof(tz)); + } + m_regs[10] = 0; + } else { + m_regs[10] = -errno; + } }; break; default: std::println(stderr, "Unimplemented syscall: {}", m_regs[17]); @@ -600,7 +647,7 @@ public: } private: - std::vector m_memory = std::vector(MEMORY_SIZE, 0); + u8 *m_memory; std::vector m_decoded; u64 m_pc; std::array m_regs{}; @@ -753,7 +800,7 @@ private: i.imm = ((i32)raw) >> 20; if (funct3 == 0b000) { - if (i.imm == 0) { + if (i.imm == 0b000000000000) { i.op = Op::ECALL; } else { std::println(stderr, "I-type 4: funct3=000 unrecognized imm: {:b}", @@ -863,9 +910,9 @@ private: exit(1); } } else if (funct3 == 0b111) { - if (funct7 == 0b000) { + if (funct7 == 0b0000000) { i.op = Op::AND; - } else if (funct7 == 0b001) { + } else if (funct7 == 0b0000001) { i.op = Op::REMU; } else { std::println(stderr,