kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

emu.c (17201B)


      1 #include "emu/emu.h"
      2 
      3 #include <string.h>
      4 
      5 #include "arch/arch.h"
      6 #include "arch/riscv/isa.h"
      7 #include "core/slice.h"
      8 
      9 #define RV64_EMU_SYM_XREG "__emu_rv64_xreg"
     10 #define RV64_EMU_SYM_SET_XREG "__emu_rv64_set_xreg"
     11 #define RV64_EMU_SYM_JALR "__emu_rv64_jalr"
     12 
     13 typedef struct Rv64EmuCPUState {
     14   u64 x[32];
     15   u64 f[32];
     16   u32 fcsr;
     17   u64 reserved_addr;
     18   int has_reservation;
     19 } Rv64EmuCPUState;
     20 
     21 typedef struct Rv64EmuLiftSyms {
     22   KitCgSym xreg;
     23   KitCgSym set_xreg;
     24   KitCgSym load64;
     25   KitCgSym load64_checked;
     26   KitCgSym store64;
     27   KitCgSym jalr;
     28   KitCgSym syscall;
     29   KitCgTypeId xreg_fn;
     30   KitCgTypeId set_xreg_fn;
     31   KitCgTypeId load64_fn;
     32   KitCgTypeId load64_checked_fn;
     33   KitCgTypeId store64_fn;
     34   KitCgTypeId jalr_fn;
     35   KitCgTypeId syscall_fn;
     36   KitCgTypeId thread_ptr;
     37   KitCgTypeId i32;
     38   KitCgTypeId i64;
     39   KitCgTypeId i64_ptr;
     40   KitCgTypeId void_ty;
     41 } Rv64EmuLiftSyms;
     42 
     43 static KitCgSym rv64_emu_decl_helper(KitCompiler* c, KitCg* cg,
     44                                      const char* name, KitCgTypeId type) {
     45   KitCgDecl d;
     46   memset(&d, 0, sizeof(d));
     47   d.kind = KIT_CG_DECL_FUNC;
     48   d.linkage_name = kit_sym_intern(c, kit_slice_cstr(name));
     49   d.display_name = d.linkage_name;
     50   d.linkage_name = kit_cg_c_linkage_name(c, d.linkage_name);
     51   d.type = type;
     52   d.sym.bind = KIT_SB_GLOBAL;
     53   d.sym.visibility = KIT_CG_VIS_DEFAULT;
     54   return kit_cg_decl(cg, d);
     55 }
     56 
     57 static KitCgTypeId rv64_emu_func_type(KitCompiler* c, KitCgTypeId ret,
     58                                       const KitCgTypeId* params, u32 nparams) {
     59   KitCgFuncParam p[5];
     60   KitCgFuncResult result;
     61   KitCgFuncSig sig;
     62   u32 i;
     63   memset(p, 0, sizeof(p));
     64   for (i = 0; i < nparams; ++i) p[i].type = params[i];
     65   memset(&sig, 0, sizeof(sig));
     66   memset(&result, 0, sizeof(result));
     67   result.type = ret;
     68   sig.result = result;
     69   sig.params = p;
     70   sig.nparams = nparams;
     71   sig.call_conv = KIT_CG_CC_TARGET_C;
     72   return kit_cg_type_func(c, sig);
     73 }
     74 
     75 static void rv64_emu_lift_syms_init(KitCompiler* c, KitCg* cg,
     76                                     Rv64EmuLiftSyms* out) {
     77   KitCgTypeId params[5];
     78   memset(out, 0, sizeof(*out));
     79   out->void_ty = kit_cg_type_builtin(c, KIT_CG_BUILTIN_VOID);
     80   out->i32 = kit_cg_type_builtin(c, KIT_CG_BUILTIN_I32);
     81   out->i64 = kit_cg_type_builtin(c, KIT_CG_BUILTIN_I64);
     82   out->i64_ptr = kit_cg_type_ptr(c, out->i64, 0);
     83   out->thread_ptr = emu_thread_type((Compiler*)c);
     84 
     85   params[0] = out->thread_ptr;
     86   params[1] = out->i32;
     87   out->xreg_fn = rv64_emu_func_type(c, out->i64, params, 2);
     88 
     89   params[0] = out->thread_ptr;
     90   params[1] = out->i32;
     91   params[2] = out->i64;
     92   out->set_xreg_fn = rv64_emu_func_type(c, out->void_ty, params, 3);
     93 
     94   params[0] = out->thread_ptr;
     95   params[1] = out->i64;
     96   out->load64_fn = rv64_emu_func_type(c, out->i64, params, 2);
     97 
     98   {
     99     KitCgTypeId load_params[5];
    100     load_params[0] = out->thread_ptr;
    101     load_params[1] = out->i64;
    102     load_params[2] = out->i64;
    103     load_params[3] = out->i64;
    104     load_params[4] = out->i64_ptr;
    105     out->load64_checked_fn = rv64_emu_func_type(c, out->i64, load_params, 5);
    106   }
    107 
    108   {
    109     KitCgTypeId store_params[5];
    110     store_params[0] = out->thread_ptr;
    111     store_params[1] = out->i64;
    112     store_params[2] = out->i64;
    113     store_params[3] = out->i64;
    114     store_params[4] = out->i64;
    115     out->store64_fn = rv64_emu_func_type(c, out->i64, store_params, 5);
    116   }
    117 
    118   {
    119     KitCgTypeId jalr_params[5];
    120     jalr_params[0] = out->thread_ptr;
    121     jalr_params[1] = out->i64;
    122     jalr_params[2] = out->i64;
    123     jalr_params[3] = out->i64;
    124     jalr_params[4] = out->i64;
    125     out->jalr_fn = rv64_emu_func_type(c, out->i64, jalr_params, 5);
    126   }
    127 
    128   params[0] = out->thread_ptr;
    129   params[1] = out->i64;
    130   out->syscall_fn = rv64_emu_func_type(c, out->i64, params, 2);
    131 
    132   out->xreg = rv64_emu_decl_helper(c, cg, RV64_EMU_SYM_XREG, out->xreg_fn);
    133   out->set_xreg =
    134       rv64_emu_decl_helper(c, cg, RV64_EMU_SYM_SET_XREG, out->set_xreg_fn);
    135   out->load64 = rv64_emu_decl_helper(c, cg, EMU_SYM_LOAD64, out->load64_fn);
    136   out->load64_checked = rv64_emu_decl_helper(c, cg, EMU_SYM_LOAD64_CHECKED,
    137                                              out->load64_checked_fn);
    138   out->store64 = rv64_emu_decl_helper(c, cg, EMU_SYM_STORE64, out->store64_fn);
    139   out->jalr = rv64_emu_decl_helper(c, cg, RV64_EMU_SYM_JALR, out->jalr_fn);
    140   out->syscall = rv64_emu_decl_helper(c, cg, EMU_SYM_SYSCALL, out->syscall_fn);
    141 }
    142 
    143 static KitCgMemAccess rv64_emu_mem(KitCgTypeId type) {
    144   KitCgMemAccess m;
    145   memset(&m, 0, sizeof(m));
    146   m.type = type;
    147   return m;
    148 }
    149 
    150 static void rv64_emu_push_thread(KitCg* cg, KitCgLocal thread,
    151                                  KitCgTypeId thread_ptr) {
    152   kit_cg_push_local(cg, thread);
    153   kit_cg_load(cg, rv64_emu_mem(thread_ptr));
    154 }
    155 
    156 static void rv64_emu_push_xreg(KitCg* cg, const Rv64EmuLiftSyms* s,
    157                                KitCgLocal thread, u32 reg) {
    158   if (reg == 0u) {
    159     kit_cg_push_int(cg, 0, s->i64);
    160     return;
    161   }
    162   rv64_emu_push_thread(cg, thread, s->thread_ptr);
    163   kit_cg_push_int(cg, reg, s->i32);
    164   kit_cg_call_symbol(cg, s->xreg, 2, (KitCgCallAttrs){0});
    165 }
    166 
    167 static void rv64_emu_store_xreg_from_tmp(KitCg* cg, const Rv64EmuLiftSyms* s,
    168                                          KitCgLocal thread, KitCgLocal tmp,
    169                                          u32 reg) {
    170   if (reg == 0u) return;
    171   rv64_emu_push_thread(cg, thread, s->thread_ptr);
    172   kit_cg_push_int(cg, reg, s->i32);
    173   kit_cg_push_local(cg, tmp);
    174   kit_cg_load(cg, rv64_emu_mem(s->i64));
    175   kit_cg_call_symbol(cg, s->set_xreg, 3, (KitCgCallAttrs){0});
    176 }
    177 
    178 static void rv64_emu_store_xreg_from_stack(KitCg* cg, const Rv64EmuLiftSyms* s,
    179                                            KitCgLocal thread, u32 reg,
    180                                            KitCgLocal tmp) {
    181   kit_cg_push_local(cg, tmp);
    182   kit_cg_swap(cg);
    183   kit_cg_store(cg, rv64_emu_mem(s->i64));
    184   if (reg == 0u) return;
    185   rv64_emu_store_xreg_from_tmp(cg, s, thread, tmp, reg);
    186 }
    187 
    188 static void rv64_emu_store_local_from_stack(KitCg* cg, const Rv64EmuLiftSyms* s,
    189                                             KitCgLocal local) {
    190   kit_cg_push_local(cg, local);
    191   kit_cg_swap(cg);
    192   kit_cg_store(cg, rv64_emu_mem(s->i64));
    193 }
    194 
    195 static void rv64_emu_push_local_value(KitCg* cg, const Rv64EmuLiftSyms* s,
    196                                       KitCgLocal local) {
    197   kit_cg_push_local(cg, local);
    198   kit_cg_load(cg, rv64_emu_mem(s->i64));
    199 }
    200 
    201 static void rv64_emu_push_addr(KitCg* cg, const Rv64EmuLiftSyms* s,
    202                                KitCgLocal thread,
    203                                const KitDecodedOperand* mem) {
    204   rv64_emu_push_xreg(cg, s, thread, mem->reg);
    205   if (mem->imm) {
    206     kit_cg_push_int(cg, (u64)mem->imm, s->i64);
    207     kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0);
    208   }
    209 }
    210 
    211 static KitStatus rv64_emu_lift_block(Compiler* compiler, KitCg* cg,
    212                                      const KitDecodedInsn* insts, u32 n,
    213                                      const EmuLiftCtx* ctx) {
    214   Rv64EmuLiftSyms syms;
    215   KitCgLocal thread;
    216   KitCgLocal tmp;
    217   KitCgLocal fault_next;
    218   KitCgLocalAttrs attrs;
    219   u64 next_pc;
    220   u32 i;
    221   KitCompiler* c;
    222 
    223   if (!compiler || !cg || !insts || !ctx) return KIT_INVALID;
    224   c = (KitCompiler*)compiler;
    225   rv64_emu_lift_syms_init(c, cg, &syms);
    226 
    227   kit_cg_func_begin(cg, ctx->block_sym);
    228   memset(&attrs, 0, sizeof(attrs));
    229   attrs.name = kit_sym_intern(c, KIT_SLICE_LIT("thread"));
    230   thread = kit_cg_param(cg, 0, syms.thread_ptr, attrs);
    231   attrs.name = kit_sym_intern(c, KIT_SLICE_LIT("tmp"));
    232   tmp = kit_cg_local(cg, syms.i64, attrs);
    233   attrs.name = kit_sym_intern(c, KIT_SLICE_LIT("fault_next"));
    234   fault_next = kit_cg_local(cg, syms.i64, attrs);
    235 
    236   next_pc = ctx->guest_pc;
    237   for (i = 0; i < n; ++i) {
    238     const KitDecodedInsn* in = &insts[i];
    239     next_pc = in->pc + in->nbytes;
    240     switch (in->opcode) {
    241       case RV64_DEC_ADDI: {
    242         u32 rd = in->operands[0].reg;
    243         u32 rs1 = in->operands[1].reg;
    244         i64 imm = in->operands[2].imm;
    245         rv64_emu_push_xreg(cg, &syms, thread, rs1);
    246         kit_cg_push_int(cg, (u64)imm, syms.i64);
    247         kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0);
    248         rv64_emu_store_xreg_from_stack(cg, &syms, thread, rd, tmp);
    249         break;
    250       }
    251       case RV64_DEC_ADD: {
    252         u32 rd = in->operands[0].reg;
    253         u32 rs1 = in->operands[1].reg;
    254         u32 rs2 = in->operands[2].reg;
    255         rv64_emu_push_xreg(cg, &syms, thread, rs1);
    256         rv64_emu_push_xreg(cg, &syms, thread, rs2);
    257         kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0);
    258         rv64_emu_store_xreg_from_stack(cg, &syms, thread, rd, tmp);
    259         break;
    260       }
    261       case RV64_DEC_AUIPC: {
    262         u32 rd = in->operands[0].reg;
    263         i64 imm = in->operands[1].imm;
    264         kit_cg_push_int(cg, (u64)(in->pc + (u64)imm), syms.i64);
    265         rv64_emu_store_xreg_from_stack(cg, &syms, thread, rd, tmp);
    266         break;
    267       }
    268       case RV64_DEC_LD: {
    269         u32 rd = in->operands[0].reg;
    270         KitCgLabel ok = kit_cg_label_new(cg);
    271         rv64_emu_push_thread(cg, thread, syms.thread_ptr);
    272         rv64_emu_push_addr(cg, &syms, thread, &in->operands[1]);
    273         kit_cg_push_int(cg, in->pc, syms.i64);
    274         kit_cg_push_int(cg, next_pc, syms.i64);
    275         kit_cg_push_local_addr(cg, tmp);
    276         kit_cg_call_symbol(cg, syms.load64_checked, 5, (KitCgCallAttrs){0});
    277         rv64_emu_store_local_from_stack(cg, &syms, fault_next);
    278         rv64_emu_push_local_value(cg, &syms, fault_next);
    279         kit_cg_push_int(cg, 0, syms.i64);
    280         kit_cg_int_cmp(cg, KIT_CG_INT_NE);
    281         kit_cg_branch_false(cg, ok);
    282         rv64_emu_push_local_value(cg, &syms, fault_next);
    283         kit_cg_ret(cg);
    284         kit_cg_label_place(cg, ok);
    285         rv64_emu_store_xreg_from_tmp(cg, &syms, thread, tmp, rd);
    286         break;
    287       }
    288       case RV64_DEC_SD: {
    289         rv64_emu_push_thread(cg, thread, syms.thread_ptr);
    290         rv64_emu_push_addr(cg, &syms, thread, &in->operands[1]);
    291         rv64_emu_push_xreg(cg, &syms, thread, in->operands[0].reg);
    292         kit_cg_push_int(cg, in->pc, syms.i64);
    293         kit_cg_push_int(cg, next_pc, syms.i64);
    294         kit_cg_call_symbol(cg, syms.store64, 5, (KitCgCallAttrs){0});
    295         kit_cg_ret(cg);
    296         kit_cg_func_end(cg);
    297         return KIT_OK;
    298       }
    299       case RV64_DEC_JALR: {
    300         Rv64I ji = rv64_i_unpack(in->arch[0]);
    301         u32 rd = ji.rd;
    302         u32 rs1 = ji.rs1;
    303         i64 imm = rv64_sext(ji.imm12, 12);
    304         rv64_emu_push_thread(cg, thread, syms.thread_ptr);
    305         kit_cg_push_int(cg, rd, syms.i64);
    306         kit_cg_push_int(cg, rs1, syms.i64);
    307         kit_cg_push_int(cg, (u64)imm, syms.i64);
    308         kit_cg_push_int(cg, next_pc, syms.i64);
    309         kit_cg_call_symbol(cg, syms.jalr, 5, (KitCgCallAttrs){0});
    310         kit_cg_ret(cg);
    311         kit_cg_func_end(cg);
    312         return KIT_OK;
    313         break;
    314       }
    315       case RV64_DEC_ECALL:
    316         rv64_emu_push_thread(cg, thread, syms.thread_ptr);
    317         kit_cg_push_int(cg, next_pc, syms.i64);
    318         kit_cg_call_symbol(cg, syms.syscall, 2, (KitCgCallAttrs){0});
    319         kit_cg_ret(cg);
    320         kit_cg_func_end(cg);
    321         return KIT_OK;
    322       default:
    323         kit_cg_push_int(cg, in->pc, syms.i64);
    324         kit_cg_ret(cg);
    325         kit_cg_func_end(cg);
    326         return KIT_OK;
    327     }
    328   }
    329 
    330   kit_cg_push_int(cg, next_pc, syms.i64);
    331   kit_cg_ret(cg);
    332   kit_cg_func_end(cg);
    333   return KIT_OK;
    334 }
    335 
    336 static EmuCPUState* rv64_emu_cpu_new(Compiler* c, u64 initial_pc,
    337                                      u64 initial_sp) {
    338   EmuCPUState* cpu = emu_cpu_new_with_arch_state(c, KIT_ARCH_RV64, initial_pc,
    339                                                  sizeof(Rv64EmuCPUState),
    340                                                  _Alignof(Rv64EmuCPUState));
    341   Rv64EmuCPUState* rv = (Rv64EmuCPUState*)emu_cpu_arch_state(cpu);
    342   if (rv) rv->x[2] = initial_sp;
    343   return cpu;
    344 }
    345 
    346 static Rv64EmuCPUState* rv64_thread_state(EmuThread* thread) {
    347   return thread ? (Rv64EmuCPUState*)emu_cpu_arch_state(emu_thread_cpu(thread))
    348                 : NULL;
    349 }
    350 
    351 u64 emu_rv64_xreg(EmuThread* thread, u32 i) {
    352   Rv64EmuCPUState* rv = rv64_thread_state(thread);
    353   if (!rv || i >= 32u) return 0;
    354   return i == 0u ? 0u : rv->x[i];
    355 }
    356 
    357 void emu_rv64_set_xreg(EmuThread* thread, u32 i, u64 v) {
    358   Rv64EmuCPUState* rv = rv64_thread_state(thread);
    359   if (!rv || i >= 32u || i == 0u) return;
    360   rv->x[i] = v;
    361 }
    362 
    363 static u64 rv64_get_syscall_no(EmuThread* thread) {
    364   return emu_rv64_xreg(thread, 17u);
    365 }
    366 
    367 static u64 rv64_get_syscall_arg(EmuThread* thread, u32 index) {
    368   static const u32 regs[6] = {10u, 11u, 12u, 13u, 14u, 15u};
    369   return index < 6u ? emu_rv64_xreg(thread, regs[index]) : 0;
    370 }
    371 
    372 static void rv64_set_syscall_result(EmuThread* thread, u64 value) {
    373   emu_rv64_set_xreg(thread, 10u, value);
    374 }
    375 
    376 static u64 rv64_get_sp(EmuThread* thread) { return emu_rv64_xreg(thread, 2u); }
    377 
    378 static void rv64_set_sp(EmuThread* thread, u64 value) {
    379   emu_rv64_set_xreg(thread, 2u, value);
    380 }
    381 
    382 static u64 rv64_get_tp(EmuThread* thread) { return emu_rv64_xreg(thread, 4u); }
    383 
    384 static void rv64_set_tp(EmuThread* thread, u64 value) {
    385   emu_rv64_set_xreg(thread, 4u, value);
    386 }
    387 
    388 static void rv64_signal_wr64(u8* p, u64 v) {
    389   u32 i;
    390   for (i = 0; i < 8u; ++i) p[i] = (u8)(v >> (8u * i));
    391 }
    392 
    393 static u64 rv64_signal_rd64(const u8* p) {
    394   return (u64)p[0] | ((u64)p[1] << 8) | ((u64)p[2] << 16) | ((u64)p[3] << 24) |
    395          ((u64)p[4] << 32) | ((u64)p[5] << 40) | ((u64)p[6] << 48) |
    396          ((u64)p[7] << 56);
    397 }
    398 
    399 static u64 rv64_signal_context_size(EmuProcess* process, EmuThread* thread) {
    400   (void)process;
    401   (void)thread;
    402   return 32u * 8u;
    403 }
    404 
    405 static KitStatus rv64_save_signal_context(EmuProcess* process,
    406                                           EmuThread* thread, u8* dst,
    407                                           u64 size) {
    408   u32 i;
    409   (void)process;
    410   if (!thread || !dst || size < 32u * 8u) return KIT_INVALID;
    411   for (i = 0; i < 32u; ++i)
    412     rv64_signal_wr64(dst + (u64)i * 8u, emu_rv64_xreg(thread, i));
    413   return KIT_OK;
    414 }
    415 
    416 static KitStatus rv64_restore_signal_context(EmuProcess* process,
    417                                              EmuThread* thread, const u8* src,
    418                                              u64 size) {
    419   u32 i;
    420   (void)process;
    421   if (!thread || !src || size < 32u * 8u) return KIT_INVALID;
    422   for (i = 0; i < 32u; ++i)
    423     emu_rv64_set_xreg(thread, i, rv64_signal_rd64(src + (u64)i * 8u));
    424   return KIT_OK;
    425 }
    426 
    427 static KitStatus rv64_set_signal_handler_args(EmuProcess* process,
    428                                               EmuThread* thread, int signo,
    429                                               u64 siginfo, u64 ucontext) {
    430   (void)process;
    431   if (!thread) return KIT_INVALID;
    432   emu_rv64_set_xreg(thread, 10u, (u64)signo);
    433   emu_rv64_set_xreg(thread, 11u, siginfo);
    434   emu_rv64_set_xreg(thread, 12u, ucontext);
    435   return KIT_OK;
    436 }
    437 
    438 static u64 rv64_signal_stack_align(EmuProcess* process, EmuThread* thread) {
    439   (void)process;
    440   (void)thread;
    441   return 16u;
    442 }
    443 
    444 static KitStatus rv64_emit_import_thunk(EmuProcess* process, u64 thunk_vaddr) {
    445   u8 code[4];
    446   u32 word = 0x00008067u;
    447   u32 i;
    448   if (!process) return KIT_INVALID;
    449   for (i = 0; i < 4u; ++i) code[i] = (u8)(word >> (8u * i));
    450   return emu_addr_space_copy_in(&process->image.addr_space, thunk_vaddr, code,
    451                                 sizeof(code));
    452 }
    453 
    454 u64 emu_rv64_jalr(EmuThread* thread, u64 rd, u64 rs1, u64 imm, u64 next_pc) {
    455   EmuImportBinding* b = NULL;
    456   u64 target;
    457   if (rd != 0u) emu_rv64_set_xreg(thread, (u32)rd, next_pc);
    458   target = emu_rv64_xreg(thread, (u32)rs1) + imm;
    459   target &= ~1ull;
    460   if (emu_dl_resolve_import_thunk(thread ? thread->process : NULL, target,
    461                                   &b) == KIT_OK &&
    462       b) {
    463     u64 args[3];
    464     u64 result = 0;
    465     args[0] = emu_rv64_xreg(thread, 10u);
    466     args[1] = emu_rv64_xreg(thread, 11u);
    467     args[2] = emu_rv64_xreg(thread, 12u);
    468     if (emu_call_host_import(thread, b, args, 3u, &result) != KIT_OK) {
    469       emu_cpu_trap_fault(emu_thread_cpu(thread));
    470       return next_pc;
    471     }
    472     if (b->signature.result != KIT_EMU_VALUE_VOID)
    473       emu_rv64_set_xreg(thread, 10u, result);
    474     return next_pc;
    475   }
    476   return target;
    477 }
    478 
    479 static void* rv64_resolve_runtime_helper(void* emu, KitSlice name) {
    480   (void)emu;
    481   if (kit_slice_eq_cstr(name, RV64_EMU_SYM_XREG)) return (void*)emu_rv64_xreg;
    482   if (kit_slice_eq_cstr(name, RV64_EMU_SYM_SET_XREG))
    483     return (void*)emu_rv64_set_xreg;
    484   if (kit_slice_eq_cstr(name, RV64_EMU_SYM_JALR)) return (void*)emu_rv64_jalr;
    485   return NULL;
    486 }
    487 
    488 const ArchEmuOps rv64_emu_ops = {
    489     .cpu_new = rv64_emu_cpu_new,
    490     .block_fn_type = emu_block_fn_type,
    491     .lift_block = rv64_emu_lift_block,
    492     .get_gpr = emu_rv64_xreg,
    493     .set_gpr = emu_rv64_set_xreg,
    494     .get_syscall_no = rv64_get_syscall_no,
    495     .get_syscall_arg = rv64_get_syscall_arg,
    496     .set_syscall_result = rv64_set_syscall_result,
    497     .get_sp = rv64_get_sp,
    498     .set_sp = rv64_set_sp,
    499     .get_tp = rv64_get_tp,
    500     .set_tp = rv64_set_tp,
    501     .signal_context_size = rv64_signal_context_size,
    502     .save_signal_context = rv64_save_signal_context,
    503     .restore_signal_context = rv64_restore_signal_context,
    504     .set_signal_handler_args = rv64_set_signal_handler_args,
    505     .signal_stack_align = rv64_signal_stack_align,
    506     .import_thunk_size = 4u,
    507     .emit_import_thunk = rv64_emit_import_thunk,
    508     .resolve_runtime_helper = rv64_resolve_runtime_helper,
    509 };