From b871922a988ff4ca2409fa886811ec68f5f9a568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Sat, 16 May 2026 22:41:53 +0300 Subject: [PATCH] implement the atomic extension trivially by ignoring concurrency guards --- librz/arch/isa/riscv/riscv_il.c | 100 ++++++++++++ librz/arch/isa/riscv/riscv_il_a.h | 226 +++++++++++++++++++++++++++ librz/arch/isa/riscv/riscv_il_base.h | 20 ++- 3 files changed, 342 insertions(+), 4 deletions(-) create mode 100644 librz/arch/isa/riscv/riscv_il_a.h diff --git a/librz/arch/isa/riscv/riscv_il.c b/librz/arch/isa/riscv/riscv_il.c index 5c2474e1d43..6a612030737 100644 --- a/librz/arch/isa/riscv/riscv_il.c +++ b/librz/arch/isa/riscv/riscv_il.c @@ -4,6 +4,7 @@ #include "riscv_il.h" #include "riscv_il_integer.h" #include "riscv_il_m.h" +#include "riscv_il_a.h" #include "riscv_il_compressed.h" static void label_ecall(RzILVM *vm, RzILOpEffect *op) { @@ -87,6 +88,105 @@ static const RiscvInstructionLifter riscv_lifters[] = { USE_LIFTER(divuw, DIVUW), USE_LIFTER(remw, REMW), USE_LIFTER(remuw, REMUW), + /* ---------------------------------- A extension ---------------------------------*/ + // Load-Reserved / Store-Conditional + USE_LIFTER(lr_w, LR_W), + USE_LIFTER(lr_w_aq, LR_W_AQ), + USE_LIFTER(lr_w_rl, LR_W_RL), + USE_LIFTER(lr_w_aqrl, LR_W_AQRL), + USE_LIFTER(lr_d, LR_D), + USE_LIFTER(lr_d_aq, LR_D_AQ), + USE_LIFTER(lr_d_rl, LR_D_RL), + USE_LIFTER(lr_d_aqrl, LR_D_AQRL), + USE_LIFTER(sc_w, SC_W), + USE_LIFTER(sc_w_aq, SC_W_AQ), + USE_LIFTER(sc_w_rl, SC_W_RL), + USE_LIFTER(sc_w_aqrl, SC_W_AQRL), + USE_LIFTER(sc_d, SC_D), + USE_LIFTER(sc_d_aq, SC_D_AQ), + USE_LIFTER(sc_d_rl, SC_D_RL), + USE_LIFTER(sc_d_aqrl, SC_D_AQRL), + // AMO swap + USE_LIFTER(amoswap_w, AMOSWAP_W), + USE_LIFTER(amoswap_w_aq, AMOSWAP_W_AQ), + USE_LIFTER(amoswap_w_rl, AMOSWAP_W_RL), + USE_LIFTER(amoswap_w_aqrl, AMOSWAP_W_AQRL), + USE_LIFTER(amoswap_d, AMOSWAP_D), + USE_LIFTER(amoswap_d_aq, AMOSWAP_D_AQ), + USE_LIFTER(amoswap_d_rl, AMOSWAP_D_RL), + USE_LIFTER(amoswap_d_aqrl, AMOSWAP_D_AQRL), + // AMO add + USE_LIFTER(amoadd_w, AMOADD_W), + USE_LIFTER(amoadd_w_aq, AMOADD_W_AQ), + USE_LIFTER(amoadd_w_rl, AMOADD_W_RL), + USE_LIFTER(amoadd_w_aqrl, AMOADD_W_AQRL), + USE_LIFTER(amoadd_d, AMOADD_D), + USE_LIFTER(amoadd_d_aq, AMOADD_D_AQ), + USE_LIFTER(amoadd_d_rl, AMOADD_D_RL), + USE_LIFTER(amoadd_d_aqrl, AMOADD_D_AQRL), + // AMO xor + USE_LIFTER(amoxor_w, AMOXOR_W), + USE_LIFTER(amoxor_w_aq, AMOXOR_W_AQ), + USE_LIFTER(amoxor_w_rl, AMOXOR_W_RL), + USE_LIFTER(amoxor_w_aqrl, AMOXOR_W_AQRL), + USE_LIFTER(amoxor_d, AMOXOR_D), + USE_LIFTER(amoxor_d_aq, AMOXOR_D_AQ), + USE_LIFTER(amoxor_d_rl, AMOXOR_D_RL), + USE_LIFTER(amoxor_d_aqrl, AMOXOR_D_AQRL), + // AMO and + USE_LIFTER(amoand_w, AMOAND_W), + USE_LIFTER(amoand_w_aq, AMOAND_W_AQ), + USE_LIFTER(amoand_w_rl, AMOAND_W_RL), + USE_LIFTER(amoand_w_aqrl, AMOAND_W_AQRL), + USE_LIFTER(amoand_d, AMOAND_D), + USE_LIFTER(amoand_d_aq, AMOAND_D_AQ), + USE_LIFTER(amoand_d_rl, AMOAND_D_RL), + USE_LIFTER(amoand_d_aqrl, AMOAND_D_AQRL), + // AMO or + USE_LIFTER(amoor_w, AMOOR_W), + USE_LIFTER(amoor_w_aq, AMOOR_W_AQ), + USE_LIFTER(amoor_w_rl, AMOOR_W_RL), + USE_LIFTER(amoor_w_aqrl, AMOOR_W_AQRL), + USE_LIFTER(amoor_d, AMOOR_D), + USE_LIFTER(amoor_d_aq, AMOOR_D_AQ), + USE_LIFTER(amoor_d_rl, AMOOR_D_RL), + USE_LIFTER(amoor_d_aqrl, AMOOR_D_AQRL), + // AMO signed min + USE_LIFTER(amomin_w, AMOMIN_W), + USE_LIFTER(amomin_w_aq, AMOMIN_W_AQ), + USE_LIFTER(amomin_w_rl, AMOMIN_W_RL), + USE_LIFTER(amomin_w_aqrl, AMOMIN_W_AQRL), + USE_LIFTER(amomin_d, AMOMIN_D), + USE_LIFTER(amomin_d_aq, AMOMIN_D_AQ), + USE_LIFTER(amomin_d_rl, AMOMIN_D_RL), + USE_LIFTER(amomin_d_aqrl, AMOMIN_D_AQRL), + // AMO signed max + USE_LIFTER(amomax_w, AMOMAX_W), + USE_LIFTER(amomax_w_aq, AMOMAX_W_AQ), + USE_LIFTER(amomax_w_rl, AMOMAX_W_RL), + USE_LIFTER(amomax_w_aqrl, AMOMAX_W_AQRL), + USE_LIFTER(amomax_d, AMOMAX_D), + USE_LIFTER(amomax_d_aq, AMOMAX_D_AQ), + USE_LIFTER(amomax_d_rl, AMOMAX_D_RL), + USE_LIFTER(amomax_d_aqrl, AMOMAX_D_AQRL), + // AMO unsigned min + USE_LIFTER(amominu_w, AMOMINU_W), + USE_LIFTER(amominu_w_aq, AMOMINU_W_AQ), + USE_LIFTER(amominu_w_rl, AMOMINU_W_RL), + USE_LIFTER(amominu_w_aqrl, AMOMINU_W_AQRL), + USE_LIFTER(amominu_d, AMOMINU_D), + USE_LIFTER(amominu_d_aq, AMOMINU_D_AQ), + USE_LIFTER(amominu_d_rl, AMOMINU_D_RL), + USE_LIFTER(amominu_d_aqrl, AMOMINU_D_AQRL), + // AMO unsigned max + USE_LIFTER(amomaxu_w, AMOMAXU_W), + USE_LIFTER(amomaxu_w_aq, AMOMAXU_W_AQ), + USE_LIFTER(amomaxu_w_rl, AMOMAXU_W_RL), + USE_LIFTER(amomaxu_w_aqrl, AMOMAXU_W_AQRL), + USE_LIFTER(amomaxu_d, AMOMAXU_D), + USE_LIFTER(amomaxu_d_aq, AMOMAXU_D_AQ), + USE_LIFTER(amomaxu_d_rl, AMOMAXU_D_RL), + USE_LIFTER(amomaxu_d_aqrl, AMOMAXU_D_AQRL), /* ---------------------------------- Compressed ---------------------------------*/ USE_LIFTER(c_addi, C_ADDI), USE_LIFTER(c_addi16sp, C_ADDI16SP), diff --git a/librz/arch/isa/riscv/riscv_il_a.h b/librz/arch/isa/riscv/riscv_il_a.h new file mode 100644 index 00000000000..0b273fe1e3b --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_a.h @@ -0,0 +1,226 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_A_H +#define RISCV_IL_A_H + +#include "riscv_il_base.h" + +#include + +// Decoder: rd=REG[0], addr=MEM[1].base (lr.w / lr.d) +#define DECODE_RD_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *addr = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); + +// Decoder: rd=REG[0], addr=MEM[1].base, rs2=REG[2] (sc.* / amo*.*) +#define DECODE_RD_MEM_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *addr = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[2].reg); + +// 64-bit-only variants (RV64A .d instructions) +#define DECODE_RD_MEM_64(analysis, insn) \ + REQUIRE_64_BIT(analysis); \ + DECODE_RD_MEM(analysis, insn) + +#define DECODE_RD_MEM_RS_64(analysis, insn) \ + REQUIRE_64_BIT(analysis); \ + DECODE_RD_MEM_RS(analysis, insn) + +// A extension: atomic instructions (RV32A / RV64A) +// +// Sequential-execution assumption +// -------------------------------- +// This entire file assumes the RzIL VM is completely sequential with no parallelism or +// asynchrony of any kind. Under that assumption every "atomic" concern reduces as follows: +// +// Acquire/release ordering (.aq / .rl / .aqrl variants) +// Collapse to no-ops. Ordering constraints only matter when multiple execution flows +// share memory concurrently. All ordering variants are therefore aliased to the base +// instruction with no extra fence or barrier logic. +// +// Load-Reserved / Store-Conditional reservations +// Are trivially always valid. The only execution flow that could invalidate a reservation +// between lr and sc are external ones — another hart, a DMA engine, an interrupt +// handler that writes to the same address, memory-mapped I/O side-effects, etc. — +// none of which exist in this model. lr.* is therefore a plain load and sc.* +// is an unconditional store that always reports success (rd = 0). +// +// AMO read-modify-write atomicity +// Is trivially preserved. There is no window in which another execution flow could observe +// or modify memory between the internal load and store, so the straightforward +// SEQ-based implementation is fully correct and complete. +// +// If the VM ever gains any form of parallelism or asynchrony — including but not limited +// to hardware threads (harts), DMA engines, memory-mapped I/O with side-effects, interrupt +// delivery modelled between individual instructions, or speculative / out-of-order execution +// — this file MUST be revisited. + +// Load-Reserved: plain load as in riscv_il_integer.h; reservation is not modelled +DEFINE_LIFTER(lr_w, DECODE_RD_MEM, + analysis->bits == 32 ? LOADW(32, addr) : SIGNED(analysis->bits, LOADW(32, addr))) +DEFINE_ALIAS_LIFTER(lr_w_aq, lr_w) +DEFINE_ALIAS_LIFTER(lr_w_rl, lr_w) +DEFINE_ALIAS_LIFTER(lr_w_aqrl, lr_w) + +DEFINE_LIFTER(lr_d, DECODE_RD_MEM_64, LOADW(64, addr)) +DEFINE_ALIAS_LIFTER(lr_d_aq, lr_d) +DEFINE_ALIAS_LIFTER(lr_d_rl, lr_d) +DEFINE_ALIAS_LIFTER(lr_d_aqrl, lr_d) + +// Store-Conditional: unconditional store as in riscv_il_integer.h, rd = 0 (always succeeds; see sequential assumption above) +DEFINE_LIFTER_WITH_PRE_EFFECT(sc_w, DECODE_RD_MEM_RS, + STOREW(addr, CAST(32, IL_FALSE, rs2)), + UN(analysis->bits, 0)) +DEFINE_ALIAS_LIFTER(sc_w_aq, sc_w) +DEFINE_ALIAS_LIFTER(sc_w_rl, sc_w) +DEFINE_ALIAS_LIFTER(sc_w_aqrl, sc_w) + +DEFINE_LIFTER_WITH_PRE_EFFECT(sc_d, DECODE_RD_MEM_RS_64, + STOREW(addr, rs2), + UN(analysis->bits, 0)) +DEFINE_ALIAS_LIFTER(sc_d_aq, sc_d) +DEFINE_ALIAS_LIFTER(sc_d_rl, sc_d) +DEFINE_ALIAS_LIFTER(sc_d_aqrl, sc_d) + +// AMO .w helper: atomically read-modify-write 32-bit memory, return old value sign-extended to XLEN. +// new32 may reference VARL("_v32") (old 32-bit mem val) and VARL("_r32") (rs2 lower 32 bits). +#define AMO_W(rd, addr, rs2, new32) \ + SEQ5( \ + SETL("_a", (addr)), \ + SETL("_v32", LOADW(32, VARL("_a"))), \ + SETL("_r32", CAST(32, IL_FALSE, (rs2))), \ + STOREW(VARL("_a"), (new32)), \ + RISCV_SET_REG((rd), SIGNED(analysis->bits, VARL("_v32")))) + +// AMO .d helper: atomically read-modify-write 64-bit memory, return old value in rd. +// new64 may reference VARL("_v") (old 64-bit mem val) and VARL("_r") (rs2). +#define AMO_D(rd, addr, rs2, new64) \ + SEQ5( \ + SETL("_a", (addr)), \ + SETL("_v", LOADW(64, VARL("_a"))), \ + SETL("_r", (rs2)), \ + STOREW(VARL("_a"), (new64)), \ + RISCV_SET_REG((rd), VARL("_v"))) + +// AMO swap: mem = rs2, rd = old_mem +DEFINE_LIFTER_WITH_EFFECT(amoswap_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, VARL("_r32"))) +DEFINE_ALIAS_LIFTER(amoswap_w_aq, amoswap_w) +DEFINE_ALIAS_LIFTER(amoswap_w_rl, amoswap_w) +DEFINE_ALIAS_LIFTER(amoswap_w_aqrl, amoswap_w) + +DEFINE_LIFTER_WITH_EFFECT(amoswap_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, VARL("_r"))) +DEFINE_ALIAS_LIFTER(amoswap_d_aq, amoswap_d) +DEFINE_ALIAS_LIFTER(amoswap_d_rl, amoswap_d) +DEFINE_ALIAS_LIFTER(amoswap_d_aqrl, amoswap_d) + +// AMO add +DEFINE_LIFTER_WITH_EFFECT(amoadd_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, ADD(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoadd_w_aq, amoadd_w) +DEFINE_ALIAS_LIFTER(amoadd_w_rl, amoadd_w) +DEFINE_ALIAS_LIFTER(amoadd_w_aqrl, amoadd_w) + +DEFINE_LIFTER_WITH_EFFECT(amoadd_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, ADD(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoadd_d_aq, amoadd_d) +DEFINE_ALIAS_LIFTER(amoadd_d_rl, amoadd_d) +DEFINE_ALIAS_LIFTER(amoadd_d_aqrl, amoadd_d) + +// AMO xor +DEFINE_LIFTER_WITH_EFFECT(amoxor_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, LOGXOR(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoxor_w_aq, amoxor_w) +DEFINE_ALIAS_LIFTER(amoxor_w_rl, amoxor_w) +DEFINE_ALIAS_LIFTER(amoxor_w_aqrl, amoxor_w) + +DEFINE_LIFTER_WITH_EFFECT(amoxor_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, LOGXOR(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoxor_d_aq, amoxor_d) +DEFINE_ALIAS_LIFTER(amoxor_d_rl, amoxor_d) +DEFINE_ALIAS_LIFTER(amoxor_d_aqrl, amoxor_d) + +// AMO and +DEFINE_LIFTER_WITH_EFFECT(amoand_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, LOGAND(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoand_w_aq, amoand_w) +DEFINE_ALIAS_LIFTER(amoand_w_rl, amoand_w) +DEFINE_ALIAS_LIFTER(amoand_w_aqrl, amoand_w) + +DEFINE_LIFTER_WITH_EFFECT(amoand_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, LOGAND(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoand_d_aq, amoand_d) +DEFINE_ALIAS_LIFTER(amoand_d_rl, amoand_d) +DEFINE_ALIAS_LIFTER(amoand_d_aqrl, amoand_d) + +// AMO or +DEFINE_LIFTER_WITH_EFFECT(amoor_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, LOGOR(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoor_w_aq, amoor_w) +DEFINE_ALIAS_LIFTER(amoor_w_rl, amoor_w) +DEFINE_ALIAS_LIFTER(amoor_w_aqrl, amoor_w) + +DEFINE_LIFTER_WITH_EFFECT(amoor_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, LOGOR(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoor_d_aq, amoor_d) +DEFINE_ALIAS_LIFTER(amoor_d_rl, amoor_d) +DEFINE_ALIAS_LIFTER(amoor_d_aqrl, amoor_d) + +// AMO signed min/max: operands are 32-bit bitvectors (_v32, _r32), so SLT/SGT is 32-bit signed +DEFINE_LIFTER_WITH_EFFECT(amomin_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(SLT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amomin_w_aq, amomin_w) +DEFINE_ALIAS_LIFTER(amomin_w_rl, amomin_w) +DEFINE_ALIAS_LIFTER(amomin_w_aqrl, amomin_w) + +DEFINE_LIFTER_WITH_EFFECT(amomin_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(SLT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amomin_d_aq, amomin_d) +DEFINE_ALIAS_LIFTER(amomin_d_rl, amomin_d) +DEFINE_ALIAS_LIFTER(amomin_d_aqrl, amomin_d) + +DEFINE_LIFTER_WITH_EFFECT(amomax_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(SGT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amomax_w_aq, amomax_w) +DEFINE_ALIAS_LIFTER(amomax_w_rl, amomax_w) +DEFINE_ALIAS_LIFTER(amomax_w_aqrl, amomax_w) + +DEFINE_LIFTER_WITH_EFFECT(amomax_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(SGT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amomax_d_aq, amomax_d) +DEFINE_ALIAS_LIFTER(amomax_d_rl, amomax_d) +DEFINE_ALIAS_LIFTER(amomax_d_aqrl, amomax_d) + +// AMO unsigned min/max: _v32/_r32 are 32-bit bitvectors, so ULT/UGT is 32-bit unsigned +DEFINE_LIFTER_WITH_EFFECT(amominu_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(ULT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amominu_w_aq, amominu_w) +DEFINE_ALIAS_LIFTER(amominu_w_rl, amominu_w) +DEFINE_ALIAS_LIFTER(amominu_w_aqrl, amominu_w) + +DEFINE_LIFTER_WITH_EFFECT(amominu_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(ULT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amominu_d_aq, amominu_d) +DEFINE_ALIAS_LIFTER(amominu_d_rl, amominu_d) +DEFINE_ALIAS_LIFTER(amominu_d_aqrl, amominu_d) + +DEFINE_LIFTER_WITH_EFFECT(amomaxu_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(UGT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amomaxu_w_aq, amomaxu_w) +DEFINE_ALIAS_LIFTER(amomaxu_w_rl, amomaxu_w) +DEFINE_ALIAS_LIFTER(amomaxu_w_aqrl, amomaxu_w) + +DEFINE_LIFTER_WITH_EFFECT(amomaxu_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(UGT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amomaxu_d_aq, amomaxu_d) +DEFINE_ALIAS_LIFTER(amomaxu_d_rl, amomaxu_d) +DEFINE_ALIAS_LIFTER(amomaxu_d_aqrl, amomaxu_d) + +#undef DECODE_RD_MEM +#undef DECODE_RD_MEM_RS +#undef DECODE_RD_MEM_64 +#undef DECODE_RD_MEM_RS_64 +#undef AMO_W +#undef AMO_D + +#include + +#endif // RISCV_IL_A_H diff --git a/librz/arch/isa/riscv/riscv_il_base.h b/librz/arch/isa/riscv/riscv_il_base.h index d570f5c1080..8d530aab169 100644 --- a/librz/arch/isa/riscv/riscv_il_base.h +++ b/librz/arch/isa/riscv/riscv_il_base.h @@ -53,14 +53,24 @@ static const char *riscv_register_names[] = { return RISCV_SET_REG(rd, result); \ } -// by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) -#define DEFINE_LIFTER_FOR_JUMP(name, decoder, result, jmp_effect) \ +// rd = result, then post_effect (e.g. jump: set return address, then redirect PC) +#define DEFINE_LIFTER_WITH_POST_EFFECT(name, decoder, result, post_effect) \ static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ decoder(analysis, insn); \ return SEQ2( \ RISCV_SET_REG(rd, result), \ - jmp_effect); \ + post_effect); \ + } + +// pre_effect, then rd = result (e.g. store-conditional: store first, then write success flag) +#define DEFINE_LIFTER_WITH_PRE_EFFECT(name, decoder, pre_effect, result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ + decoder(analysis, insn); \ + return SEQ2( \ + pre_effect, \ + RISCV_SET_REG(rd, result)); \ } #define DEFINE_LIFTER_WITH_EFFECT(name, decoder, effect) \ @@ -70,8 +80,10 @@ static const char *riscv_register_names[] = { return effect; \ } +// by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) +#define DEFINE_LIFTER_FOR_JUMP DEFINE_LIFTER_WITH_POST_EFFECT // oneway jumps are those that don't have a destination register -#define DEFINE_LIFTER_FOR_ONEWAY_JUMP DEFINE_LIFTER_WITH_EFFECT +#define DEFINE_LIFTER_FOR_ONEWAY_JUMP DEFINE_LIFTER_WITH_EFFECT #define DEFINE_ALIAS_LIFTER(alias, name) static const RiscvInstructionLifter rz_riscv_lift_##alias = rz_riscv_lift_##name;