From 9a017e5c5efcf3ec5d26741f4e278bfcb234d714 Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 16:48:32 +0800 Subject: [PATCH 1/8] test: add riscv init support Signed-off-by: Jvle --- test/arch/riscv/arch.py | 160 ++++++++++++++++++++++++++++++++++++++++ test/test_all.py | 2 +- 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 test/arch/riscv/arch.py diff --git a/test/arch/riscv/arch.py b/test/arch/riscv/arch.py new file mode 100644 index 000000000..4e80480b3 --- /dev/null +++ b/test/arch/riscv/arch.py @@ -0,0 +1,160 @@ +import sys +import time + +from miasm.core.utils import decode_hex +from miasm.arch.riscv.arch import mn_riscv +from miasm.core.locationdb import LocationDB + +loc_db = LocationDB() + +# little-endian +reg_tests_riscv = [ + + ("XXXXXXXX ADDI X1, X2, 0x0", + "00010093"), # addi x1, x2, 0 + + ("XXXXXXXX ANDI X2, X1, 0xFF", + "0FF0F113"), # andi x2, x1, 0xFF + + ("XXXXXXXX SLTI X3, X4, 0x1", + "00122193"), # slti x3, x4, 1 + + ("XXXXXXXX SLTIU X4, X5, 0x2", + "0022B213"), # sltiu x4, x5, 2 + + ("XXXXXXXX XORI X6, X7, 0xAA", + "0AA3C313"), # xori x6, x7, 0xAA + + ("XXXXXXXX ORI X7, X8, 0x55", + "05546393"), # ori x7, x8, 0x55 + + ("XXXXXXXX ADD X3, X1, X2", + "002081B3"), # add x3, x1, x2 + + ("XXXXXXXX SUB X5, X6, X7", + "407302B3"), # sub x5, x6, x7 + + ("XXXXXXXX AND X8, X9, X10", + "00A4F433"), # and x8, x9, x10 + + ("XXXXXXXX OR X11, X12, X13", + "00D665B3"), # or x11, x12, x13 + + ("XXXXXXXX XOR X14, X15, X16", + "0107C733"), # xor x14, x15, x16 + + ("XXXXXXXX SLL X6, X7, X8", + "00839333"), # sll x6, x7, x8 + + ("XXXXXXXX SRL X9, X10, X11", + "00b554B3"), # srl x9, x10, x11 + + ("XXXXXXXX SRA X12, X13, X14", + "40E6D633"), # sra x12, x13, x14 + + ("XXXXXXXX SLT X15, X16, X17", + "011827B3"), # slt x15, x16, x17 + + ("XXXXXXXX SLTU X18, X19, X20", + "0149B933"), # sltu x18, x19, x20 + + ("XXXXXXXX LW X5, X1, 0x0", + "0000A283"), # lw x5, 0(x1) + + ("XXXXXXXX LB X2, X3, 0x10", + "01018103"), # lb x2, 16(x3) + + ("XXXXXXXX LH X4, X5, 0x20", + "02029203"), # lh x4, 32(x5) + + ("XXXXXXXX LD X6, X7, 0x0", + "0003B303"), # ld x6, 0(x7) + + ("XXXXXXXX LBU X8, X9, 0x4", + "0044C403"), # lbu x8, 4(x9) + + ("XXXXXXXX LHU X10, X11, 0x6", + "0065D503"), # lhu x10, 6(x11) + + ("XXXXXXXX LWU X12, X13, 0x8", + "0086E603"), # lwu x12, 8(x13) + + ("XXXXXXXX SW X5, X1, 0x4", + "0050A223"), # sw x5, 4(x1) + + ("XXXXXXXX SB X2, X3, 0x0", + "00218023"), # sb x2, 0(x3) + + ("XXXXXXXX SH X4, X5, 0x2", + "00429123"), # sh x4, 2(x5) + + ("XXXXXXXX SD X6, X7, 0x8", + "0063B423"), # sd x6, 8(x7) + + ("XXXXXXXX BEQ X1, X2, 0x8", + "00208463"), # beq x1, x2, 8 + + ("XXXXXXXX BNE X3, X4, 0xC", + "00419663"), # bne x3, x4, 12 + + ("XXXXXXXX BLT X5, X6, 0x10", + "0062C863"), # blt x5, x6, 16 + + ("XXXXXXXX BGE X7, X8, 0x14", + "0083da63"), # bge x7, x8, 20 + + ("XXXXXXXX BLTU X9, X10, 0x18", + "00A4EC63"), # bltu x9, x10, 24 + + ("XXXXXXXX BGEU X11, X12, 0x1C", + "00C5FE63"), # bgeu x11, x12, 28 + + ("XXXXXXXX JALR X1, X2, 0x0", + "000100E7"), # jalr x1, 0(x2) + + ("XXXXXXXX JAL X1, 0x10", + "010000EF"), # jal x1, 16 + + ("XXXXXXXX LUI X1, 0x10000", + "100000B7"), # lui x1, 0x10000 + + ("XXXXXXXX AUIPC X2, 0x20000", + "20000117"), # auipc x2, 0x20000 +] + + + +def h2i(s): + return decode_hex(s.replace(' ', '')) + + +def main(): + ts = time.time() + + for s, l in reg_tests_riscv[:]: + print("-" * 80) + print(s[:12], l) + asm_str = s[12:] + b = h2i(l) + + mn = mn_riscv.dis(b, 64) + print("[args]", [str(x) for x in mn.args]) + print("expected asm:", asm_str) + print("disasm asm: ", mn) + + assert str(mn) == asm_str + + l_obj = mn_riscv.fromstring(asm_str, loc_db, 64) + assert str(l_obj) == asm_str + + a = mn_riscv.asm(l_obj) + print("asm bytes:", [x for x in a]) + print("orig bytes:", repr(b)) + assert b in a + + print(l_obj.to_html()) + + print("done in %f seconds" % (time.time() - ts)) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/test_all.py b/test/test_all.py index ab2d898bf..a853f2ab0 100755 --- a/test/test_all.py +++ b/test/test_all.py @@ -65,7 +65,7 @@ def get_sample(cls, sample_name): testset += RegressionTest(["msp430/arch.py"], base_dir="arch") testset += RegressionTest(["mips32/arch.py"], base_dir="arch") testset += RegressionTest(["ppc32/arch.py"], base_dir="arch") - +testset += RegressionTest(["riscv/arch.py"], base_dir="arch") ### ArchUnit regression tests From a49e00c754736344d9f991af352f86947b72eebc Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 16:57:32 +0800 Subject: [PATCH 2/8] riscv: add init jitter support Signed-off-by: Jvle --- miasm/jitter/arch/JitCore_riscv.c | 471 ++++++++++++++++++++++++++++++ miasm/jitter/arch/JitCore_riscv.h | 51 ++++ miasm/jitter/jitcore_llvm.py | 1 + miasm/jitter/jitload.py | 2 + miasm/jitter/loader/elf.py | 1 + miasm/loader/elf.py | 1 + 6 files changed, 527 insertions(+) create mode 100644 miasm/jitter/arch/JitCore_riscv.c create mode 100644 miasm/jitter/arch/JitCore_riscv.h diff --git a/miasm/jitter/arch/JitCore_riscv.c b/miasm/jitter/arch/JitCore_riscv.c new file mode 100644 index 000000000..154093fd8 --- /dev/null +++ b/miasm/jitter/arch/JitCore_riscv.c @@ -0,0 +1,471 @@ +#include +#include "structmember.h" +#include +#include +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "../op_semantics.h" +#include "JitCore_riscv.h" + +reg_dict gpreg_dict[] = { + {.name = "X0", .offset = offsetof(struct vm_cpu, X0), .size = 64}, + {.name = "X1", .offset = offsetof(struct vm_cpu, X1), .size = 64}, + {.name = "X2", .offset = offsetof(struct vm_cpu, X2), .size = 64}, + {.name = "X3", .offset = offsetof(struct vm_cpu, X3), .size = 64}, + {.name = "X4", .offset = offsetof(struct vm_cpu, X4), .size = 64}, + {.name = "X5", .offset = offsetof(struct vm_cpu, X5), .size = 64}, + {.name = "X6", .offset = offsetof(struct vm_cpu, X6), .size = 64}, + {.name = "X7", .offset = offsetof(struct vm_cpu, X7), .size = 64}, + {.name = "X8", .offset = offsetof(struct vm_cpu, X8), .size = 64}, + {.name = "X9", .offset = offsetof(struct vm_cpu, X9), .size = 64}, + {.name = "X10", .offset = offsetof(struct vm_cpu, X10), .size = 64}, + {.name = "X11", .offset = offsetof(struct vm_cpu, X11), .size = 64}, + {.name = "X12", .offset = offsetof(struct vm_cpu, X12), .size = 64}, + {.name = "X13", .offset = offsetof(struct vm_cpu, X13), .size = 64}, + {.name = "X14", .offset = offsetof(struct vm_cpu, X14), .size = 64}, + {.name = "X15", .offset = offsetof(struct vm_cpu, X15), .size = 64}, + {.name = "X16", .offset = offsetof(struct vm_cpu, X16), .size = 64}, + {.name = "X17", .offset = offsetof(struct vm_cpu, X17), .size = 64}, + {.name = "X18", .offset = offsetof(struct vm_cpu, X18), .size = 64}, + {.name = "X19", .offset = offsetof(struct vm_cpu, X19), .size = 64}, + {.name = "X20", .offset = offsetof(struct vm_cpu, X20), .size = 64}, + {.name = "X21", .offset = offsetof(struct vm_cpu, X21), .size = 64}, + {.name = "X22", .offset = offsetof(struct vm_cpu, X22), .size = 64}, + {.name = "X23", .offset = offsetof(struct vm_cpu, X23), .size = 64}, + {.name = "X24", .offset = offsetof(struct vm_cpu, X24), .size = 64}, + {.name = "X25", .offset = offsetof(struct vm_cpu, X25), .size = 64}, + {.name = "X26", .offset = offsetof(struct vm_cpu, X26), .size = 64}, + {.name = "X27", .offset = offsetof(struct vm_cpu, X27), .size = 64}, + {.name = "X28", .offset = offsetof(struct vm_cpu, X28), .size = 64}, + {.name = "X29", .offset = offsetof(struct vm_cpu, X29), .size = 64}, + {.name = "X30", .offset = offsetof(struct vm_cpu, X30), .size = 64}, + {.name = "X31", .offset = offsetof(struct vm_cpu, X31), .size = 64}, + + {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 64}, + + {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32}, + {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32}, +}; + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(X0); + get_reg(X1); + get_reg(X2); + get_reg(X3); + get_reg(X4); + get_reg(X5); + get_reg(X6); + get_reg(X7); + get_reg(X8); + get_reg(X9); + get_reg(X10); + get_reg(X11); + get_reg(X12); + get_reg(X13); + get_reg(X14); + get_reg(X15); + get_reg(X16); + get_reg(X17); + get_reg(X18); + get_reg(X19); + get_reg(X20); + get_reg(X21); + get_reg(X22); + get_reg(X23); + get_reg(X24); + get_reg(X25); + get_reg(X26); + get_reg(X27); + get_reg(X28); + get_reg(X29); + get_reg(X30); + get_reg(X31); + get_reg(PC); + + get_reg(exception_flags); + get_reg(interrupt_num); + + return dict; +} + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val32; + uint64_t val64; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + + while(PyDict_Next(dict, &pos, &d_key, &d_value)) { + PyGetStr(d_key_name, d_key); + found = 0; + for (i = 0; i < sizeof(gpreg_dict) / sizeof(reg_dict); i++) { + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + found = 1; + switch (gpreg_dict[i].size) { + default: + RAISE(PyExc_TypeError, "Unsupported size"); + break; + case 32: + PyGetInt_uint32_t(d_value, val32); + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val32; + break; + case 64: + PyGetInt_uint64_t(d_value, val64); + *((uint64_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val64; + break; + } + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + printf("X0 %.16"PRIX64" X1 %.16"PRIX64" X2 %.16"PRIX64" X3 %.16"PRIX64"\n", + vmcpu->X0, vmcpu->X1, vmcpu->X2, vmcpu->X3); + printf("X4 %.16"PRIX64" X5 %.16"PRIX64" X6 %.16"PRIX64" X7 %.16"PRIX64"\n", + vmcpu->X4, vmcpu->X5, vmcpu->X6, vmcpu->X7); + printf("X8 %.16"PRIX64" X9 %.16"PRIX64" X10 %.16"PRIX64" X11 %.16"PRIX64"\n", + vmcpu->X8, vmcpu->X9, vmcpu->X10, vmcpu->X11); + printf("X12 %.16"PRIX64" X13 %.16"PRIX64" X14 %.16"PRIX64" X15 %.16"PRIX64"\n", + vmcpu->X12, vmcpu->X13, vmcpu->X14, vmcpu->X15); + printf("X16 %.16"PRIX64" X17 %.16"PRIX64" X18 %.16"PRIX64" X19 %.16"PRIX64"\n", + vmcpu->X16, vmcpu->X17, vmcpu->X18, vmcpu->X19); + printf("X20 %.16"PRIX64" X21 %.16"PRIX64" X22 %.16"PRIX64" X23 %.16"PRIX64"\n", + vmcpu->X20, vmcpu->X21, vmcpu->X22, vmcpu->X23); + printf("X24 %.16"PRIX64" X25 %.16"PRIX64" X26 %.16"PRIX64" X27 %.16"PRIX64"\n", + vmcpu->X24, vmcpu->X25, vmcpu->X26, vmcpu->X27); + printf("X28 %.16"PRIX64" X29 %.16"PRIX64" X30 %.16"PRIX64" X31 %.16"PRIX64"\n", + vmcpu->X28, vmcpu->X29, vmcpu->X30, vmcpu->X31); + + printf("PC %.16"PRIX64" exception_flags %08"PRIX32" interrupt_num %08"PRIX32"\n", + vmcpu->PC, + vmcpu->exception_flags, + vmcpu->interrupt_num); +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +static PyMemberDef JitCpu_members[] = { + {NULL} +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + +getset_reg_u64(X0); +getset_reg_u64(X1); +getset_reg_u64(X2); +getset_reg_u64(X3); +getset_reg_u64(X4); +getset_reg_u64(X5); +getset_reg_u64(X6); +getset_reg_u64(X7); +getset_reg_u64(X8); +getset_reg_u64(X9); +getset_reg_u64(X10); +getset_reg_u64(X11); +getset_reg_u64(X12); +getset_reg_u64(X13); +getset_reg_u64(X14); +getset_reg_u64(X15); +getset_reg_u64(X16); +getset_reg_u64(X17); +getset_reg_u64(X18); +getset_reg_u64(X19); +getset_reg_u64(X20); +getset_reg_u64(X21); +getset_reg_u64(X22); +getset_reg_u64(X23); +getset_reg_u64(X24); +getset_reg_u64(X25); +getset_reg_u64(X26); +getset_reg_u64(X27); +getset_reg_u64(X28); +getset_reg_u64(X29); +getset_reg_u64(X30); +getset_reg_u64(X31); +getset_reg_u64(PC); + +getset_reg_u32(exception_flags); +getset_reg_u32(interrupt_num); + + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg_off(exception_flags); + + get_reg_off(X0); + get_reg_off(X1); + get_reg_off(X2); + get_reg_off(X3); + get_reg_off(X4); + get_reg_off(X5); + get_reg_off(X6); + get_reg_off(X7); + get_reg_off(X8); + get_reg_off(X9); + get_reg_off(X10); + get_reg_off(X11); + get_reg_off(X12); + get_reg_off(X13); + get_reg_off(X14); + get_reg_off(X15); + get_reg_off(X16); + get_reg_off(X17); + get_reg_off(X18); + get_reg_off(X19); + get_reg_off(X20); + get_reg_off(X21); + get_reg_off(X22); + get_reg_off(X23); + get_reg_off(X24); + get_reg_off(X25); + get_reg_off(X26); + get_reg_off(X27); + get_reg_off(X28); + get_reg_off(X29); + get_reg_off(X30); + get_reg_off(X31); + get_reg_off(PC); + + get_reg_off(interrupt_num); + + return dict; +} + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + {"X0" , (getter)JitCpu_get_X0 , (setter)JitCpu_set_X0 , "X0" , NULL}, + {"X1" , (getter)JitCpu_get_X1 , (setter)JitCpu_set_X1 , "X1" , NULL}, + {"X2" , (getter)JitCpu_get_X2 , (setter)JitCpu_set_X2 , "X2" , NULL}, + {"X3" , (getter)JitCpu_get_X3 , (setter)JitCpu_set_X3 , "X3" , NULL}, + {"X4" , (getter)JitCpu_get_X4 , (setter)JitCpu_set_X4 , "X4" , NULL}, + {"X5" , (getter)JitCpu_get_X5 , (setter)JitCpu_set_X5 , "X5" , NULL}, + {"X6" , (getter)JitCpu_get_X6 , (setter)JitCpu_set_X6 , "X6" , NULL}, + {"X7" , (getter)JitCpu_get_X7 , (setter)JitCpu_set_X7 , "X7" , NULL}, + {"X8" , (getter)JitCpu_get_X8 , (setter)JitCpu_set_X8 , "X8" , NULL}, + {"X9" , (getter)JitCpu_get_X9 , (setter)JitCpu_set_X9 , "X9" , NULL}, + {"X10", (getter)JitCpu_get_X10, (setter)JitCpu_set_X10, "X10", NULL}, + {"X11", (getter)JitCpu_get_X11, (setter)JitCpu_set_X11, "X11", NULL}, + {"X12", (getter)JitCpu_get_X12, (setter)JitCpu_set_X12, "X12", NULL}, + {"X13", (getter)JitCpu_get_X13, (setter)JitCpu_set_X13, "X13", NULL}, + {"X14", (getter)JitCpu_get_X14, (setter)JitCpu_set_X14, "X14", NULL}, + {"X15", (getter)JitCpu_get_X15, (setter)JitCpu_set_X15, "X15", NULL}, + {"X16", (getter)JitCpu_get_X16, (setter)JitCpu_set_X16, "X16", NULL}, + {"X17", (getter)JitCpu_get_X17, (setter)JitCpu_set_X17, "X17", NULL}, + {"X18", (getter)JitCpu_get_X18, (setter)JitCpu_set_X18, "X18", NULL}, + {"X19", (getter)JitCpu_get_X19, (setter)JitCpu_set_X19, "X19", NULL}, + {"X20", (getter)JitCpu_get_X20, (setter)JitCpu_set_X20, "X20", NULL}, + {"X21", (getter)JitCpu_get_X21, (setter)JitCpu_set_X21, "X21", NULL}, + {"X22", (getter)JitCpu_get_X22, (setter)JitCpu_set_X22, "X22", NULL}, + {"X23", (getter)JitCpu_get_X23, (setter)JitCpu_set_X23, "X23", NULL}, + {"X24", (getter)JitCpu_get_X24, (setter)JitCpu_set_X24, "X24", NULL}, + {"X25", (getter)JitCpu_get_X25, (setter)JitCpu_set_X25, "X25", NULL}, + {"X26", (getter)JitCpu_get_X26, (setter)JitCpu_set_X26, "X26", NULL}, + {"X27", (getter)JitCpu_get_X27, (setter)JitCpu_set_X27, "X27", NULL}, + {"X28", (getter)JitCpu_get_X28, (setter)JitCpu_set_X28, "X28", NULL}, + {"X29", (getter)JitCpu_get_X29, (setter)JitCpu_set_X29, "X29", NULL}, + {"X30", (getter)JitCpu_get_X30, (setter)JitCpu_set_X30, "X30", NULL}, + {"X31", (getter)JitCpu_get_X31, (setter)JitCpu_set_X31, "X31", NULL}, + + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + + {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL}, + {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL}, + + {NULL} +}; + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_riscv.JitCpu", /* tp_name */ + sizeof(JitCpu), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)JitCpu_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + +static PyMethodDef JitCore_riscv_Methods[] = { + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} +}; + +MOD_INIT(JitCore_riscv) +{ + PyObject *module = NULL; + + MOD_DEF(module, + "JitCore_riscv", + "JitCore_riscv module", + JitCore_riscv_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", + (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} \ No newline at end of file diff --git a/miasm/jitter/arch/JitCore_riscv.h b/miasm/jitter/arch/JitCore_riscv.h new file mode 100644 index 000000000..3f193132b --- /dev/null +++ b/miasm/jitter/arch/JitCore_riscv.h @@ -0,0 +1,51 @@ +// 64-bit RISC-V JitCore header file for Miasm Jitter +struct vm_cpu { + uint32_t exception_flags; + uint32_t interrupt_num; + + /* gpregs: RISC-V x0 ~ x31 */ + uint64_t X0; + uint64_t X1; + uint64_t X2; + uint64_t X3; + uint64_t X4; + uint64_t X5; + uint64_t X6; + uint64_t X7; + uint64_t X8; + uint64_t X9; + uint64_t X10; + uint64_t X11; + uint64_t X12; + uint64_t X13; + uint64_t X14; + uint64_t X15; + uint64_t X16; + uint64_t X17; + uint64_t X18; + uint64_t X19; + uint64_t X20; + uint64_t X21; + uint64_t X22; + uint64_t X23; + uint64_t X24; + uint64_t X25; + uint64_t X26; + uint64_t X27; + uint64_t X28; + uint64_t X29; + uint64_t X30; + uint64_t X31; + + /* program counter */ + uint64_t PC; +}; + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; \ No newline at end of file diff --git a/miasm/jitter/jitcore_llvm.py b/miasm/jitter/jitcore_llvm.py index 4f1871b2a..4d407ccdf 100644 --- a/miasm/jitter/jitcore_llvm.py +++ b/miasm/jitter/jitcore_llvm.py @@ -25,6 +25,7 @@ class JitCore_LLVM(jitcore.JitCore): "msp430": "JitCore_msp430", "mips32": "JitCore_mips32", "aarch64": "JitCore_aarch64", + "riscv": "JitCore_riscv", "ppc32": "JitCore_ppc32", } diff --git a/miasm/jitter/jitload.py b/miasm/jitter/jitload.py index 99e4429d5..682a70cef 100644 --- a/miasm/jitter/jitload.py +++ b/miasm/jitter/jitload.py @@ -222,6 +222,8 @@ def __init__(self, lifter, jit_type="gcc"): elif arch_name == "armt": from miasm.jitter.arch import JitCore_arm as jcore lifter.arch.name = 'arm' + elif arch_name == "riscv": + from miasm.jitter.arch import JitCore_riscv as jcore elif arch_name == "aarch64": from miasm.jitter.arch import JitCore_aarch64 as jcore elif arch_name == "msp430": diff --git a/miasm/jitter/loader/elf.py b/miasm/jitter/loader/elf.py index 91d1c18bb..0cc19d267 100644 --- a/miasm/jitter/loader/elf.py +++ b/miasm/jitter/loader/elf.py @@ -322,6 +322,7 @@ class libimp_elf(libimp): # machine, size, sex -> arch_name ELF_machine = {(elf_csts.EM_ARM, 32, elf_csts.ELFDATA2LSB): "arml", (elf_csts.EM_ARM, 32, elf_csts.ELFDATA2MSB): "armb", + (elf_csts.EM_RISCV, 64, elf_csts.ELFDATA2LSB): "riscv64", (elf_csts.EM_AARCH64, 64, elf_csts.ELFDATA2LSB): "aarch64l", (elf_csts.EM_AARCH64, 64, elf_csts.ELFDATA2MSB): "aarch64b", (elf_csts.EM_MIPS, 32, elf_csts.ELFDATA2MSB): "mips32b", diff --git a/miasm/loader/elf.py b/miasm/loader/elf.py index 742587826..5b086c2d0 100644 --- a/miasm/loader/elf.py +++ b/miasm/loader/elf.py @@ -189,6 +189,7 @@ class Dynamic(CStruct): EM_TINYJ = 61 # Advanced Logic Corp. Tinyj emb.fam*/ EM_X86_64 = 62 # AMD x86-64 architecture EM_AARCH64 = 183 # Aarch64 architecture +EM_RISCV = 243 # RISC-V 64/32 architecture EM_PDSP = 63 # Sony DSP Processor EM_FX66 = 66 # Siemens FX66 microcontroller From 34ad671febd3f7c354e01ae968b8492ba711670c Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 17:06:35 +0800 Subject: [PATCH 3/8] riscv: add register definitions Signed-off-by: Jvle --- miasm/arch/riscv/__init__.py | 1 + miasm/arch/riscv/regs.py | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 miasm/arch/riscv/__init__.py create mode 100644 miasm/arch/riscv/regs.py diff --git a/miasm/arch/riscv/__init__.py b/miasm/arch/riscv/__init__.py new file mode 100644 index 000000000..4f1f2010b --- /dev/null +++ b/miasm/arch/riscv/__init__.py @@ -0,0 +1 @@ +__all__ = ["arch", "disasm", "regs", "sem"] \ No newline at end of file diff --git a/miasm/arch/riscv/regs.py b/miasm/arch/riscv/regs.py new file mode 100644 index 000000000..2610a2364 --- /dev/null +++ b/miasm/arch/riscv/regs.py @@ -0,0 +1,64 @@ +# -*- coding:utf-8 -*- + +from builtins import range +from miasm.expression.expression import ExprId +from miasm.core.cpu import gen_reg, gen_regs, reg_info + +exception_flags = ExprId('exception_flags', 32) +interrupt_num = ExprId('interrupt_num', 32) + +# riscv64/32 regs are similar, the only difference being their width. +xregs_str = ["X%d" % i for i in range(32)] +xregs_expr, xregs_init, xregs_info = gen_regs( + xregs_str, globals(), 64) + +PC, pc_info = gen_reg("PC", 64) + +csr_str = [ + # User-level + "USTATUS", "UIE", "UTVEC", + "USCRATCH", "UEPC", "UCAUSE", "UTVAL", "UIP", + + # Supervisor-level + "SSTATUS", "SIE", "STVEC", + "SSCRATCH", "SEPC", "SCAUSE", "STVAL", "SIP", + "SATP", + + # Machine-level + "MSTATUS", "MISA", "MIE", "MTVEC", + "MSCRATCH", "MEPC", "MCAUSE", "MTVAL", "MIP", + + # hart info + "MVENDORID", "MARCHID", "MIMPID", "MHARTID", +] + +csr_expr, csr_init, csr_info = gen_regs(csr_str, globals(), 64) + +# TODO: add more special regs if needed +''' + ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, + A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, + S8, S9, S10, S11, T3, T4, T5, T6, + PC +''' +all_regs_ids = [ + X0, X1, X2, X3, X4, X5, X6, X7, + X8, X9, X10, X11, X12, X13, X14, X15, + X16, X17, X18, X19, X20, X21, X22, X23, + X24, X25, X26, X27, X28, X29, X30, X31, + PC +] + csr_expr + +all_regs_ids_no_alias = all_regs_ids +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + +all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids] +regs_init = {} +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] + +attrib_to_regs = { + 64: all_regs_ids_no_alias, +} + +regs_flt_expr = [] \ No newline at end of file From 1db11a9d2078d61bcc2e7d8f5086a5d3904fde70 Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 17:13:21 +0800 Subject: [PATCH 4/8] riscv: add RV64I init encode/decode Signed-off-by: Jvle --- miasm/arch/riscv/arch.py | 549 +++++++++++++++++++++++++++++++++++++ miasm/arch/riscv/disasm.py | 21 ++ 2 files changed, 570 insertions(+) create mode 100644 miasm/arch/riscv/arch.py create mode 100644 miasm/arch/riscv/disasm.py diff --git a/miasm/arch/riscv/arch.py b/miasm/arch/riscv/arch.py new file mode 100644 index 000000000..adc6cb44b --- /dev/null +++ b/miasm/arch/riscv/arch.py @@ -0,0 +1,549 @@ +#-*- coding:utf-8 -*- + +from __future__ import print_function +from builtins import range +import re + +from future.utils import viewitems + +from miasm.core import utils +from miasm.expression.expression import * +from pyparsing import * +from miasm.core.cpu import * +from collections import defaultdict +import miasm.arch.riscv.regs as regs_module +from miasm.arch.riscv.regs import * +from miasm.core.asm_ast import AstNode, AstInt, AstId, AstMem, AstOp +from miasm.ir.ir import color_expr_html +from miasm.core.utils import BRACKET_O, BRACKET_C + + +log = logging.getLogger("riscv_arch") +console_handler = logging.StreamHandler() +console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(console_handler) +log.setLevel(logging.WARN) + +gpregs_64 = (xregs_info.parser) + +gpregs_info = {64: xregs_info, } + +BRCOND = ["BEQ", "BNE", "BLT", "BGE", "BLTU", "BGEU"] + +CALL = ["JAL", "JALR"] + +# TODO: support 32-bit mode +XLEN64 = 64 + + +class riscv_gpreg_noarg(reg_noarg): + parser = gpregs_64 + gpregs_info = gpregs_info + + def decode(self, v): + # TODO: support 32-bit mode + size = XLEN64 + self.expr = self.gpregs_info[size].expr[v & 0x1F] + return True + + def encode(self): + if not self.expr.size in self.gpregs_info: + return False + if not self.expr in self.gpregs_info[self.expr.size].expr: + return False + self.value = self.gpregs_info[self.expr.size].expr.index(self.expr) + return True + +class riscv_arg(m_arg): + def asm_ast_to_expr(self, value, loc_db, size_hint=None, fixed_size=None): + if size_hint is None: + # TODO: support 32-bit mode + size_hint = XLEN64 + if fixed_size is None: + fixed_size = set() + + if isinstance(value, AstId): + if value.name in all_regs_ids_byname: + reg = all_regs_ids_byname[value.name] + fixed_size.add(reg.size) + return reg + + if isinstance(value.name, ExprId): + fixed_size.add(value.name.size) + return value.name + + loc_key = loc_db.get_or_create_name_location(value.name) + return m2_expr.ExprLoc(loc_key, size_hint) + + if isinstance(value, AstInt): + assert size_hint is not None + return m2_expr.ExprInt(value.value, size_hint) + + if isinstance(value, AstOp): + args = [self.asm_ast_to_expr(arg, loc_db, None, fixed_size) + for arg in value.args] + + if len(fixed_size) == 0: + pass + elif len(fixed_size) == 1: + size = list(fixed_size)[0] + args = [self.asm_ast_to_expr(arg, loc_db, size, fixed_size) + for arg in value.args] + else: + raise ValueError("Size conflict") + + return m2_expr.ExprOp(value.op, *args) + + return None + +class riscv_imm_I(imm_noarg, riscv_arg): + parser = base_expr + intsize = XLEN64 + + def decode(self, v): + v &= self.lmask + if v & (1 << (self.l - 1)): + v -= 1 << self.l + self.expr = m2_expr.ExprInt(v, self.intsize) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + v = int(self.expr) + if v < -(1 << (self.l - 1)) or v >= (1 << (self.l - 1)): + return False + self.value = v & self.lmask + return True + +class riscv_imm_S(imm_noarg, riscv_arg): + """ + S-type store imm[11:0] = {imm[11:5], imm[4:0]}, sign-extended + """ + parser = base_expr + intsize = XLEN64 + + def decode(self, v): + # v = imm[4:0] + lo = v & self.lmask + hi = self.parent.imm_S_hi.value + + imm12 = (hi << 5) | lo + + if imm12 & (1 << 11): + imm12 -= 1 << 12 + + self.expr = m2_expr.ExprInt(imm12, self.intsize) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + + v = int(self.expr) + if v < -(1 << 11) or v >= (1 << 11): + return False + + imm12 = v & 0xFFF + lo = imm12 & 0x1F + hi = (imm12 >> 5) & 0x7F + + self.parent.imm_S_hi.value = hi + self.value = lo + return True + +class riscv_imm_B(imm_noarg, riscv_arg): + """ + B-type branch offset + """ + parser = base_expr + intsize = XLEN64 + + def decode(self, v): + # imm[11] + bit11 = v & 0x1 + bit12 = self.parent.b_imm_12.value + bits10_5 = self.parent.b_imm_10_5.value + bits4_1 = self.parent.b_imm_4_1.value + + imm = (bit12 << 12) | (bit11 << 11) | (bits10_5 << 5) | (bits4_1 << 1) + + # 13-bit sign-extend + if imm & (1 << 12): + imm -= 1 << 13 + + self.expr = m2_expr.ExprInt(imm, self.intsize) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + + imm = int(self.expr) + + # RISC-V B-type offset must 2 Bytes aligned + if imm & 1: + return False + + if imm < -(1 << 12) or imm >= (1 << 12): + return False + + imm &= (1 << 13) - 1 # 13 bits + + bit12 = (imm >> 12) & 0x1 + bit11 = (imm >> 11) & 0x1 + bits10_5 = (imm >> 5) & 0x3F + bits4_1 = (imm >> 1) & 0xF + + self.parent.b_imm_12.value = bit12 + self.parent.b_imm_10_5.value = bits10_5 + self.parent.b_imm_4_1.value = bits4_1 + self.value = bit11 # imm[11] + return True + + +class riscv_imm_U(imm_noarg, riscv_arg): + """ + U-type imm[31:12] + """ + parser = base_expr + intsize = XLEN64 + + def decode(self, v): + v &= self.lmask + if v & (1 << 19): + v -= 1 << 20 + self.expr = m2_expr.ExprInt(v, self.intsize) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + + val = int(self.expr) + if val < -(1 << 19) or val >= (1 << 19): + return False + + self.value = val & self.lmask + return True + + +class riscv_imm_J(imm_noarg, riscv_arg): + """ + J-type JAL offset: imm[20|10:1|11|19:12] << 1, sign-extended + """ + parser = base_expr + intsize = XLEN64 + + def decode(self, v): + bits19_12 = v & self.lmask + + bit20 = self.parent.j_imm_20.value + bits10_1 = self.parent.j_imm_10_1.value + bit11 = self.parent.j_imm_11.value + + imm = (bit20 << 20) | (bits19_12 << 12) | (bit11 << 11) | (bits10_1 << 1) + + if imm & (1 << 20): + imm -= 1 << 21 + + self.expr = m2_expr.ExprInt(imm, self.intsize) + return True + + def encode(self): + if not isinstance(self.expr, m2_expr.ExprInt): + return False + + imm = int(self.expr) + + if imm & 1: + return False + + if imm < -(1 << 20) or imm >= (1 << 20): + return False + + imm &= (1 << 21) - 1 + + bit20 = (imm >> 20) & 0x1 + bits19_12 = (imm >> 12) & 0xFF + bit11 = (imm >> 11) & 0x1 + bits10_1 = (imm >> 1) & 0x3FF + + self.parent.j_imm_20.value = bit20 + self.parent.j_imm_10_1.value = bits10_1 + self.parent.j_imm_11.value = bit11 + self.value = bits19_12 + return True + +class riscv_gpreg(riscv_gpreg_noarg, riscv_arg): + pass + +class additional_info(object): + + def __init__(self): + self.except_on_instr = False + +class instruction_riscv(instruction): + __slots__ = [] + + def __init__(self, *args, **kargs): + super(instruction_riscv, self).__init__(*args, **kargs) + + @staticmethod + def arg2str(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int(): + return str(expr) + + if expr.is_loc(): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + + if isinstance(expr, m2_expr.ExprOp) and expr.op == "+": + base, off = expr.args + if off.is_int(): + return "%s(%s)" % (off, base) + return "%s + %s" % (base, off) + + if isinstance(expr, m2_expr.ExprOp): + return "%s(%s)" % (expr.op, ", ".join(str(a) for a in expr.args)) + + raise NotImplementedError("bad op %r" % (expr,)) + + @staticmethod + def arg2html(expr, index=None, loc_db=None): + if expr.is_id() or expr.is_int() or expr.is_loc(): + return color_expr_html(expr, loc_db) + + if isinstance(expr, m2_expr.ExprOp) and expr.op == "+": + base, off = expr.args + if off.is_int(): + return "%s(%s)" % ( + color_expr_html(off, loc_db), + color_expr_html(base, loc_db), + ) + return "%s + %s" % ( + color_expr_html(base, loc_db), + color_expr_html(off, loc_db), + ) + + if isinstance(expr, m2_expr.ExprOp): + args_html = ", ".join(color_expr_html(a, loc_db) for a in expr.args) + return "%s(%s)" % ( + utils.set_html_text_color(expr.op, utils.COLOR_OP), + args_html, + ) + + raise NotImplementedError("bad op %r" % (expr,)) + + def splitflow(self): + if self.name in BRCOND: + return True + + if self.name == "JAL": + return True + + if self.name == "JALR": + rd = self.args[0] + + if rd != X0: + return True + + return False + + return False + + + def dstflow(self): + if self.name in BRCOND: + return True + + if self.name == "JAL": + return True + + if self.name == "JALR": + rd = self.args[0] + + if rd != X0: + return True + + return False + + return False + + def dstflow2label(self, loc_db): + index = self.mnemo_flow_to_dst_index(self.name) + expr = self.args[index] + + if not expr.is_int(): + return + + addr = (int(expr) + self.offset) & int(expr.mask) + loc_key = loc_db.get_or_create_offset_location(addr) + self.args[index] = m2_expr.ExprLoc(loc_key, expr.size) + + def mnemo_flow_to_dst_index(self, name): + if self.name in BRCOND: + return 2 + + elif self.name in ["JAL"]: + return len(self.args) - 1 + + elif self.name in ["JALR"]: + return 1 + + else: + return 0 + + def getdstflow(self, loc_db): + index = self.mnemo_flow_to_dst_index(self.name) + return [self.args[index]] + + + def breakflow(self): + return self.name in ( + BRCOND + + CALL + + ["RET", "ECALL", "EBREAK", "MRET", "SRET", "URET"] + ) + + def is_subcall(self): + return self.name in CALL + +class mn_riscv(cls_mn): + name = "riscv" + regs = regs_module + num = 0 + all_mn = [] + all_mn_mode = defaultdict(list) + all_mn_name = defaultdict(list) + all_mn_inst = defaultdict(list) + bintree = {} + delayslot = 0 + # TODO: support 32-bit mode, however RISC-V is mostly 64-bit now. + pc = {64: PC} + sp = {64: X2} + instruction = instruction_riscv + max_instruction_len = 4 + + @classmethod + def getpc(cls, attrib=None): + return PC + + @classmethod + def getsp(cls, attrib=None): + return X2 + + def additional_info(self): + info = additional_info() + return info + + @classmethod + def check_mnemo(cls, fields): + pass + + @classmethod + def getmn(cls, name): + return name.upper() + + @classmethod + def mod_fields(cls, fields): + l = sum(x.l for x in fields) + # RISC-V only has 16-bit and 32-bit instructions + if l not in (16, 32): + raise ValueError(f"Invalid RISC-V instruction length: {l}") + return fields + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + dct['mode'] = None + return [(subcls, name, bases, dct, fields)] + +def riscvop(name, fields, args=None, alias=False): + dct = {"fields": fields} + dct["alias"] = alias + if args is not None: + dct['args'] = args + type(name, (mn_riscv,), dct) + +# general regs +rd = bs(l=5, cls=(riscv_gpreg,), fname="rd") +rs1 = bs(l=5, cls=(riscv_gpreg,), fname="rs1") +rs2 = bs(l=5, cls=(riscv_gpreg,), fname="rs2") + +# I-type imm[11:0] +imm_I = bs(l=12, cls=(riscv_imm_I,), fname="imm_I") + +# S-type imm[11:5] | imm[4:0] +imm_S_hi = bs(l=7, fname="imm_S_hi") +imm_S = bs(l=5, cls=(riscv_imm_S,), fname="imm_S") + +# B-type imm[12|10:5|4:1|11] merge to b_imm +b_imm_12 = bs(l=1, fname="b_imm_12") +b_imm_10_5 = bs(l=6, fname="b_imm_10_5") +b_imm_4_1 = bs(l=4, fname="b_imm_4_1") +b_imm = bs(l=1, cls=(riscv_imm_B,), fname="b_imm") + + +# U-type imm[31:12] << 12 +u_imm = bs(l=20, cls=(riscv_imm_U,), fname="u_imm") + +# J-type JAL offset +j_imm_20 = bs(l=1, fname="j_imm_20") +j_imm_10_1 = bs(l=10, fname="j_imm_10_1") +j_imm_11 = bs(l=1, fname="j_imm_11") +j_imm = bs(l=8, cls=(riscv_imm_J,), fname="j_imm") + + +# R-type integer ALU +riscvop("add", [bs("0000000"), rs2, rs1, bs("000"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("sub", [bs("0100000"), rs2, rs1, bs("000"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("and", [bs("0000000"), rs2, rs1, bs("111"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("or", [bs("0000000"), rs2, rs1, bs("110"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("xor", [bs("0000000"), rs2, rs1, bs("100"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("sll", [bs("0000000"), rs2, rs1, bs("001"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("srl", [bs("0000000"), rs2, rs1, bs("101"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("sra", [bs("0100000"), rs2, rs1, bs("101"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("slt", [bs("0000000"), rs2, rs1, bs("010"), rd, bs("0110011")], [rd, rs1, rs2]) +riscvop("sltu", [bs("0000000"), rs2, rs1, bs("011"), rd, bs("0110011")], [rd, rs1, rs2]) + +# I-type ALU imm +# NOP: addi x0, x0, x0 +riscvop("addi", [imm_I, rs1, bs("000"), rd, bs("0010011")], [rd, rs1, imm_I]) +riscvop("slti", [imm_I, rs1, bs("010"), rd, bs("0010011")], [rd, rs1, imm_I]) +riscvop("sltiu", [imm_I, rs1, bs("011"), rd, bs("0010011")], [rd, rs1, imm_I]) +riscvop("xori", [imm_I, rs1, bs("100"), rd, bs("0010011")], [rd, rs1, imm_I]) +riscvop("ori", [imm_I, rs1, bs("110"), rd, bs("0010011")], [rd, rs1, imm_I]) +riscvop("andi", [imm_I, rs1, bs("111"), rd, bs("0010011")], [rd, rs1, imm_I]) + +# I-type LOAD +riscvop("lb", [imm_I, rs1, bs("000"), rd, bs("0000011")], [rd, rs1, imm_I]) +riscvop("lh", [imm_I, rs1, bs("001"), rd, bs("0000011")], [rd, rs1, imm_I]) +riscvop("lw", [imm_I, rs1, bs("010"), rd, bs("0000011")], [rd, rs1, imm_I]) +riscvop("ld", [imm_I, rs1, bs("011"), rd, bs("0000011")], [rd, rs1, imm_I]) +riscvop("lbu",[imm_I, rs1, bs("100"), rd, bs("0000011")], [rd, rs1, imm_I]) +riscvop("lhu",[imm_I, rs1, bs("101"), rd, bs("0000011")], [rd, rs1, imm_I]) +riscvop("lwu",[imm_I, rs1, bs("110"), rd, bs("0000011")], [rd, rs1, imm_I]) +# JALR (it approach to I-Type) +riscvop("jalr", [imm_I, rs1, bs("000"), rd, bs("1100111")], [rd, rs1, imm_I]) + +# S-type STORE +riscvop("sb", [imm_S_hi, rs2, rs1, bs("000"), imm_S, bs("0100011")], [rs2, rs1, imm_S]) +riscvop("sh", [imm_S_hi, rs2, rs1, bs("001"), imm_S, bs("0100011")], [rs2, rs1, imm_S]) +riscvop("sw", [imm_S_hi, rs2, rs1, bs("010"), imm_S, bs("0100011")], [rs2, rs1, imm_S]) +riscvop("sd", [imm_S_hi, rs2, rs1, bs("011"), imm_S, bs("0100011")], [rs2, rs1, imm_S]) + +# B-type BRCOND +riscvop("beq", [b_imm_12, b_imm_10_5, rs2, rs1, bs("000"), b_imm_4_1, b_imm, bs("1100011")], [rs1, rs2, b_imm]) +riscvop("bne", [b_imm_12, b_imm_10_5, rs2, rs1, bs("001"), b_imm_4_1, b_imm, bs("1100011")], [rs1, rs2, b_imm]) +riscvop("blt", [b_imm_12, b_imm_10_5, rs2, rs1, bs("100"), b_imm_4_1, b_imm, bs("1100011")], [rs1, rs2, b_imm]) +riscvop("bge", [b_imm_12, b_imm_10_5, rs2, rs1, bs("101"), b_imm_4_1, b_imm, bs("1100011")], [rs1, rs2, b_imm]) +riscvop("bltu", [b_imm_12, b_imm_10_5, rs2, rs1, bs("110"), b_imm_4_1, b_imm, bs("1100011")], [rs1, rs2, b_imm]) +riscvop("bgeu", [b_imm_12, b_imm_10_5, rs2, rs1, bs("111"), b_imm_4_1, b_imm, bs("1100011")], [rs1, rs2, b_imm]) + +# U-type (LUI / AUIPC) +riscvop("lui", [u_imm, rd, bs("0110111")], [rd, u_imm]) +riscvop("auipc", [u_imm, rd, bs("0010111")], [rd, u_imm]) + +# J-type JAL +riscvop("jal", [j_imm_20, j_imm_10_1, j_imm_11, j_imm, rd, bs("1101111")], [rd, j_imm]) \ No newline at end of file diff --git a/miasm/arch/riscv/disasm.py b/miasm/arch/riscv/disasm.py new file mode 100644 index 000000000..ec2bf4f7d --- /dev/null +++ b/miasm/arch/riscv/disasm.py @@ -0,0 +1,21 @@ +from miasm.core.asmblock import disasmEngine +from miasm.arch.riscv.arch import mn_riscv + + +cb_riscv_funcs = [] + + +def cb_riscv_disasm(*args, **kwargs): + for func in cb_riscv_funcs: + func(*args, **kwargs) + + +class dis_riscv(disasmEngine): + attrib = None + + def __init__(self, bs=None, **kwargs): + super(dis_riscv, self).__init__(mn_riscv, self.attrib, bs, **kwargs) + self.dis_block_callback = cb_riscv_disasm + +class dis_riscv64(dis_riscv): + attrib = 64 \ No newline at end of file From e88f2887bbf295009272507125c5ff16e494d89c Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 17:14:33 +0800 Subject: [PATCH 5/8] riscv: add RV64I init IR semantics Signed-off-by: Jvle --- miasm/arch/riscv/sem.py | 408 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 miasm/arch/riscv/sem.py diff --git a/miasm/arch/riscv/sem.py b/miasm/arch/riscv/sem.py new file mode 100644 index 000000000..30237e333 --- /dev/null +++ b/miasm/arch/riscv/sem.py @@ -0,0 +1,408 @@ +from builtins import range +from future.utils import viewitems + +from miasm.expression.expression import ExprId, ExprInt, ExprLoc, ExprMem, \ + ExprCond, ExprCompose, ExprOp, ExprAssign +from miasm.ir.ir import Lifter, IRBlock, AssignBlock +from miasm.arch.riscv.arch import mn_riscv +from miasm.arch.riscv.regs import * +from miasm.core.sembuilder import SemBuilder +from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_INT_XX + +# System register for riscv64 +system_regs = { + # User-level + 0x000: USTATUS, + 0x004: UIE, + 0x005: UTVEC, + 0x040: USCRATCH, + 0x041: UEPC, + 0x042: UCAUSE, + 0x043: UTVAL, + 0x044: UIP, + + # Supervisor-level + 0x100: SSTATUS, + 0x104: SIE, + 0x105: STVEC, + 0x140: SSCRATCH, + 0x141: SEPC, + 0x142: SCAUSE, + 0x143: STVAL, + 0x144: SIP, + 0x180: SATP, + + # Machine-level + 0x300: MSTATUS, + 0x301: MISA, + 0x304: MIE, + 0x305: MTVEC, + 0x340: MSCRATCH, + 0x341: MEPC, + 0x342: MCAUSE, + 0x343: MTVAL, + 0x344: MIP, + + # hart info + 0xF11: MVENDORID, + 0xF12: MARCHID, + 0xF13: MIMPID, + 0xF14: MHARTID, +} + +# SemBuilder context +ctx = { + "PC": PC, + "ExprId": ExprId, + "exception_flags": exception_flags, + "interrupt_num": interrupt_num, + "EXCEPT_DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO, + "EXCEPT_INT_XX": EXCEPT_INT_XX, +} + +sbuild = SemBuilder(ctx) + + +# instruction definition ############## + +@sbuild.parse +def add(rd, rs1, rs2): + rd = rs1 + rs2 + +@sbuild.parse +def sub(rd, rs1, rs2): + rd = rs1 - rs2 + +@sbuild.parse +def xor(rd, rs1, rs2): + rd = rs1 ^ rs2 + +@sbuild.parse +def or_(rd, rs1, rs2): + rd = rs1 | rs2 + +@sbuild.parse +def and_(rd, rs1, rs2): + rd = rs1 & rs2 + +@sbuild.parse +def sll(rd, rs1, rs2): + sh = rs2 & ExprInt(rs1.size - 1, rs1.size) + rd = rs1 << sh + +@sbuild.parse +def srl(rd, rs1, rs2): + sh = rs2 & ExprInt(rs1.size - 1, rs1.size) + rd = rs1 >> sh + +@sbuild.parse +def sra(rd, rs1, rs2): + sh = rs2 & ExprInt(rs1.size - 1, rs1.size) + tmp = rs1.signExtend(rs1.size * 2) + rd = (tmp >> sh).zeroExtend(rd.size) + +@sbuild.parse +def addi(rd, rs1, imm): + rd = rs1 + imm.signExtend(rs1.size) + +@sbuild.parse +def andi(rd, rs1, imm): + rd = rs1 & imm.zeroExtend(rs1.size) + +@sbuild.parse +def slt(rd, rs1, rs2): + rd = ExprCond( + ExprOp("<", rs1, rs2), + ExprInt(1, rd.size), + ExprInt(0, rd.size), + ) + +@sbuild.parse +def sltu(rd, rs1, rs2): + rd = ExprCond( + ExprOp("u<", rs1, rs2), + ExprInt(1, rd.size), + ExprInt(0, rd.size), + ) + +@sbuild.parse +def slti(rd, rs1, imm): + tmp = imm.signExtend(rs1.size) + rd = ExprCond( + ExprOp("<", rs1, tmp), + ExprInt(1, rd.size), + ExprInt(0, rd.size), + ) + +@sbuild.parse +def sltiu(rd, rs1, imm): + tmp = imm.signExtend(rs1.size) + rd = ExprCond( + ExprOp("u<", rs1, tmp), + ExprInt(1, rd.size), + ExprInt(0, rd.size), + ) + +@sbuild.parse +def xori(rd, rs1, imm): + rd = rs1 ^ imm + +@sbuild.parse +def ori(rd, rs1, imm): + rd = rs1 | imm + +@sbuild.parse +def beq(rs1, rs2, target): + cond = ExprOp("==", rs1, rs2) + + fallthrough = ExprLoc(ir.get_next_loc_key(instr), PC.size) + + dst = ExprCond(cond, target, fallthrough) + + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bne(rs1, rs2, target): + cond = ExprOp("!=", rs1, rs2) + fallthrough = ExprLoc(ir.get_next_loc_key(instr), PC.size) + dst = ExprCond(cond, target, fallthrough) + + PC = dst + ir.IRDst = dst + +@sbuild.parse +def blt(rs1, rs2, target): + cond = ExprOp("<", rs1, rs2) + fallthrough = ExprLoc(ir.get_next_loc_key(instr), PC.size) + dst = ExprCond(cond, target, fallthrough) + + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bge(rs1, rs2, target): + cond = ExprOp(">=", rs1, rs2) + fallthrough = ExprLoc(ir.get_next_loc_key(instr), PC.size) + dst = ExprCond(cond, target, fallthrough) + + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bltu(rs1, rs2, target): + cond = ExprOp("u<", rs1, rs2) + fallthrough = ExprLoc(ir.get_next_loc_key(instr), PC.size) + dst = ExprCond(cond, target, fallthrough) + + PC = dst + ir.IRDst = dst + +@sbuild.parse +def bgeu(rs1, rs2, target): + cond = ExprOp("u>=", rs1, rs2) + fallthrough = ExprLoc(ir.get_next_loc_key(instr), PC.size) + dst = ExprCond(cond, target, fallthrough) + + PC = dst + ir.IRDst = dst + +@sbuild.parse +def jalr(rd, rs1, imm): + ret_addr = ExprInt(instr.offset + instr.l, PC.size) + rd = ret_addr + + dst = rs1 + imm.signExtend(rs1.size) + PC = dst + ir.IRDst = dst + +@sbuild.parse +def lui(rd, imm): + rd = imm << ExprInt(12, imm.size) + +@sbuild.parse +def auipc(rd, imm): + rd = PC + (imm << ExprInt(12, imm.size)) + + +@sbuild.parse +def ret(rd): + PC = rd + ir.IRDst = rd + +def jal(ir, instr, rd, target): + e = [] + ret_addr = ExprInt(instr.offset + instr.l, PC.size) + e.append(ExprAssign(rd, ret_addr)) + e.append(ExprAssign(PC, target)) + ir.IRDst = target + return e, [] + +def _load(ir, instr, rd, rs1, imm, size, signed): + e = [] + addr = rs1 + imm.signExtend(rs1.size) + mem = ExprMem(addr, size) + + if signed: + val = mem.signExtend(rd.size) + else: + val = mem.zeroExtend(rd.size) + + e.append(ExprAssign(rd, val)) + return e, [] + +def lb(ir, instr, rd, rs1, imm): + return _load(ir, instr, rd, rs1, imm, 8, True) + +def lh(ir, instr, rd, rs1, imm): + return _load(ir, instr, rd, rs1, imm, 16, True) + +def lw(ir, instr, rd, rs1, imm): + return _load(ir, instr, rd, rs1, imm, 32, True) + +def ld(ir, instr, rd, rs1, imm): + e = [] + addr = rs1 + imm.signExtend(rs1.size) + e.append(ExprAssign(rd, ExprMem(addr, rd.size))) + return e, [] + +def lbu(ir, instr, rd, rs1, imm): + return _load(ir, instr, rd, rs1, imm, 8, False) + +def lhu(ir, instr, rd, rs1, imm): + return _load(ir, instr, rd, rs1, imm, 16, False) + +def lwu(ir, instr, rd, rs1, imm): + return _load(ir, instr, rd, rs1, imm, 32, False) + +def _store(ir, instr, rs1, rs2, imm, size): + e = [] + addr = rs1 + imm.signExtend(rs1.size) + if size < rs2.size: + data = rs2[:size] + else: + data = rs2 + e.append(ExprAssign(ExprMem(addr, size), data)) + return e, [] + +def sb(ir, instr, rs1, rs2, imm): + return _store(ir, instr, rs1, rs2, imm, 8) + +def sh(ir, instr, rs1, rs2, imm): + return _store(ir, instr, rs1, rs2, imm, 16) + +def sw(ir, instr, rs1, rs2, imm): + return _store(ir, instr, rs1, rs2, imm, 32) + +def sd(ir, instr, rs1, rs2, imm): + return _store(ir, instr, rs1, rs2, imm, 64) + +# system-level instr +# TODO: add more instr for system-level instr + +mnemo_func = sbuild.functions +mnemo_func.update({ + "and": and_, + "or": or_, + "jal": jal, + "lb": lb, + "lh": lh, + "lw": lw, + "ld": ld, + "lbu": lbu, + "lhu": lhu, + "lwu": lwu, + "sb": sb, + "sh": sh, + "sw": sw, + "sd": sd, +}) + + +def get_mnemo_expr(ir, instr, *args): + if not instr.name.lower() in mnemo_func: + raise NotImplementedError('unknown mnemo %s' % instr) + instr_ir, extra_ir = mnemo_func[instr.name.lower()](ir, instr, *args) + return instr_ir, extra_ir + +class riscvinfo(object): + mode = "riscv" + # offset + + +class Lifter_Riscv64(Lifter): + + def __init__(self, loc_db): + # TODO: support 32 bits mode + Lifter.__init__(self, mn_riscv, 64, loc_db) + self.pc = PC + self.sp = X2 + self.IRDst = ExprId('IRDst', 64) + self.addrsize = 64 + + def get_ir(self, instr): + instr_ir, extra_ir = get_mnemo_expr(self, instr, *instr.args) + self.mod_pc(instr, instr_ir, extra_ir) + instr_ir, extra_ir = self.del_dst_zr(instr, instr_ir, extra_ir) + return instr_ir, extra_ir + + def expraff_fix_regs_for_mode(self, e): + dst = e.dst + src = e.src + return ExprAssign(dst, src) + + def irbloc_fix_regs_for_mode(self, irblock, mode=64): + irs = [] + for assignblk in irblock: + new_assignblk = dict(assignblk) + for dst, src in viewitems(assignblk): + del(new_assignblk[dst]) + new_assignblk[dst] = src + irs.append(AssignBlock(new_assignblk, assignblk.instr)) + return IRBlock(self.loc_db, irblock.loc_key, irs) + + def mod_pc(self, instr, instr_ir, extra_ir): + "Replace PC by the instruction's offset" + cur_offset = ExprInt(instr.offset, 64) + pc_fixed = {self.pc: cur_offset} + for i, expr in enumerate(instr_ir): + dst, src = expr.dst, expr.src + if dst != self.pc: + dst = dst.replace_expr(pc_fixed) + src = src.replace_expr(pc_fixed) + instr_ir[i] = ExprAssign(dst, src) + + for idx, irblock in enumerate(extra_ir): + extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \ + if expr != self.pc else expr, + lambda expr: expr.replace_expr(pc_fixed)) + + + def del_dst_zr(self, instr, instr_ir, extra_ir): + "Writes to x0 (zero register) are discarded" + # riscv: ZERO=>X0 + regs_to_fix = [X0] + + instr_ir = [expr for expr in instr_ir if expr.dst not in regs_to_fix] + + new_irblocks = [] + for irblock in extra_ir: + irs = [] + for assignblk in irblock: + new_dsts = { + dst: src for dst, src in viewitems(assignblk) + if dst not in regs_to_fix + } + irs.append(AssignBlock(new_dsts, assignblk.instr)) + new_irblocks.append(IRBlock(self.loc_db, irblock.loc_key, irs)) + + return instr_ir, new_irblocks + +# TODO: implement CSR access functions +def get_csr_reg(csr): + if not csr.is_int(): + raise NotImplementedError("CSR must be an immediate in IR, got %r" % (csr,)) + csr_num = int(csr) + if csr_num not in system_regs: + raise NotImplementedError("Unknown CSR 0x%03x" % csr_num) + return system_regs[csr_num] \ No newline at end of file From bc550814dfd9ee3e284a3b0d55348ff7773af25d Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 17:20:49 +0800 Subject: [PATCH 6/8] riscv: add jit and lifter_model_call Signed-off-by: Jvle --- miasm/arch/riscv/jit.py | 76 +++++++++++++++++++++++++++ miasm/arch/riscv/lifter_model_call.py | 35 ++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 miasm/arch/riscv/jit.py create mode 100644 miasm/arch/riscv/lifter_model_call.py diff --git a/miasm/arch/riscv/jit.py b/miasm/arch/riscv/jit.py new file mode 100644 index 000000000..b79dca7b2 --- /dev/null +++ b/miasm/arch/riscv/jit.py @@ -0,0 +1,76 @@ +from builtins import range +import logging + +from miasm.jitter.jitload import Jitter, named_arguments +from miasm.core.utils import pck64, upck64 +from miasm.arch.riscv.sem import Lifter_Riscv64 + +log = logging.getLogger('jit_riscv64') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + +class jitter_riscv64(Jitter): + # a0 - a7 + max_reg_arg = 8 + + def __init__(self, loc_db, *args, **kwargs): + Jitter.__init__(self, Lifter_Riscv64(loc_db), *args, **kwargs) + self.vm.set_little_endian() # RISC-V is little-endian + + def push_uint64_t(self, value): + self.cpu.X2 -= 8 + self.vm.set_mem(self.cpu.X2, pck64(value)) + + def pop_uint64_t(self): + value = self.vm.get_u64(self.cpu.X2) + self.cpu.X2 += 8 + return value + + def get_stack_arg(self, index): + return self.vm.get_u64(self.cpu.X2 + 8 * index) + + # calling conventions + + @named_arguments + def func_args_stdcall(self, n_args): + args = [] + for i in range(min(n_args, self.max_reg_arg)): + args.append(getattr(self.cpu, 'X%d' % (10 + i))) + for i in range(max(0, n_args - self.max_reg_arg)): + args.append(self.get_stack_arg(i)) + ret_ad = self.cpu.X1 + return ret_ad, args + def func_ret_stdcall(self, ret_addr, ret_value=None): + self.pc = self.cpu.PC = ret_addr + if ret_value is not None: + self.cpu.X10 = ret_value + return True + + + def get_arg_n_stdcall(self, index): + if index < self.max_reg_arg: + # a0..a7 = X10..X17 + reg_name = 'X%d' % (10 + index) + arg = self.cpu.get_gpreg()[reg_name] + else: + arg = self.get_stack_arg(index - self.max_reg_arg) + return arg + + def func_prepare_stdcall(self, ret_addr, *args): + for index in range(min(len(args), self.max_reg_arg)): + setattr(self.cpu, 'X%d' % (10 + index), args[index]) + for index in range(self.max_reg_arg, len(args)): + self.vm.set_mem(self.cpu.X2 + 8 * (index - self.max_reg_arg), + pck64(args[index])) + self.cpu.X1 = ret_addr + + func_args_systemv = func_args_stdcall + func_ret_systemv = func_ret_stdcall + get_arg_n_systemv = get_arg_n_stdcall + func_prepare_systemv = func_prepare_stdcall + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc \ No newline at end of file diff --git a/miasm/arch/riscv/lifter_model_call.py b/miasm/arch/riscv/lifter_model_call.py new file mode 100644 index 000000000..771c39065 --- /dev/null +++ b/miasm/arch/riscv/lifter_model_call.py @@ -0,0 +1,35 @@ +#-*- coding:utf-8 -*- + +from miasm.ir.analysis import LifterModelCall +from miasm.arch.riscv.sem import Lifter_Riscv64 + +class LifterModelCallRiscv64Base(Lifter_Riscv64, LifterModelCall): + + def __init__(self, loc_db): + Lifter_Riscv64.__init__(self, loc_db) + self.ret_reg = self.arch.regs.X0 + + +class LifterModelCallRiscv64(LifterModelCallRiscv64Base): + + def __init__(self, loc_db): + LifterModelCallRiscv64Base.__init__(self, loc_db) + self.ret_reg = self.arch.regs.X0 + + def get_out_regs(self, _): + return set([self.ret_reg, self.sp]) + + def sizeof_char(self): + return 8 + + def sizeof_short(self): + return 16 + + def sizeof_int(self): + return 32 + + def sizeof_long(self): + return 32 + + def sizeof_pointer(self): + return 32 \ No newline at end of file From b29a70ff3d6e554da4008b3a50b7d1809c94a9d0 Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 17:21:54 +0800 Subject: [PATCH 7/8] riscv: add machine support Signed-off-by: Jvle --- miasm/analysis/machine.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/miasm/analysis/machine.py b/miasm/analysis/machine.py index cc86d7533..8fabf348b 100644 --- a/miasm/analysis/machine.py +++ b/miasm/analysis/machine.py @@ -12,7 +12,7 @@ class Machine(object): __gdbserver = None # GdbServer handler __available = ["arml", "armb", "armtl", "armtb", "sh4", "x86_16", "x86_32", - "x86_64", "msp430", "mips32b", "mips32l", + "x86_64", "msp430", "mips32b", "mips32l", "riscv", "aarch64l", "aarch64b", "ppc32b", "mepl", "mepb"] @@ -51,6 +51,17 @@ def __init__(self, machine_name): mn = arch.mn_arm from miasm.arch.arm.lifter_model_call import LifterModelCallArmb as lifter_model_call from miasm.arch.arm.sem import Lifter_Armb as lifter + elif machine_name == "riscv": + from miasm.arch.riscv.disasm import dis_riscv64 as dis_engine + from miasm.arch.riscv import arch + try: + from miasm.arch.riscv import jit + jitter = jit.jitter_riscv64 + except ImportError: + pass + mn = arch.mn_riscv + from miasm.arch.riscv.lifter_model_call import LifterModelCallRiscv64 as lifter_model_call + from miasm.arch.riscv.sem import Lifter_Riscv64 as lifter elif machine_name == "aarch64l": from miasm.arch.aarch64.disasm import dis_aarch64l as dis_engine from miasm.arch.aarch64 import arch From 14f1f07be6e91e97ed3626751a2fafc3ed562ab7 Mon Sep 17 00:00:00 2001 From: Jvle Date: Fri, 12 Dec 2025 17:25:03 +0800 Subject: [PATCH 8/8] riscv: add setup option Signed-off-by: Jvle --- setup.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/setup.py b/setup.py index 3cc7b5a58..ec7374a00 100644 --- a/setup.py +++ b/setup.py @@ -135,6 +135,7 @@ def build_all(): "miasm/arch/x86", "miasm/arch/arm", "miasm/arch/aarch64", + "miasm/arch/riscv", "miasm/arch/msp430", "miasm/arch/mep", "miasm/arch/sh4", @@ -183,6 +184,17 @@ def build_all(): "miasm/jitter/arch/JitCore_arm.c" ] ), + Extension( + "miasm.jitter.arch.JitCore_riscv", + [ + "miasm/jitter/JitCore.c", + "miasm/jitter/vm_mngr.c", + "miasm/jitter/vm_mngr_py.c", + "miasm/jitter/op_semantics.c", + "miasm/jitter/bn.c", + "miasm/jitter/arch/JitCore_riscv.c" + ] + ), Extension( "miasm.jitter.arch.JitCore_aarch64", [