emit_fcache_enter_common
>>> append_fcache_enter_prologue
mv a1, a5 # dont care
mv a5, a0 # 将 ARG1(dc) 赋值给 a5,因为 a5 是 REG_DCXT
...
>>>>>> insert_load_dr_tls_base
sd tp, 0(a5) # 将原始 tp 放到 dc 的 X0 slot 中保存
ld tp, -8(tp) # 拿到 dtv.private 所指向的结构体(spill_state)
tp 从这里开始指向 spill_state
>>> append_setup_fcache_target
ld a0, NEXT_TAG_OFFSET(a5) # 初始化完成后跳转到的地址,加载到 a0
sd a0, A2_SLOT(tp) # 把 a0 的值放到 A2 slot
>>> body
ld a0, 96(a5) # 把 dc->a0 加载到 a0
ld a1, 104(a5) # 把 dc->a1 加载到 a1
sd a0, 0(tp) # 把 a0 保存到 spill_state A0 slot
sd a1, 8(tp) # 把 a1 保存到 spill_state A1 slot
>>> append_restore_xflags (用了 a0)
>>> append_restore_gpr
ld a0, REG_OFFSET(tp)(a5) # 把 dc->tp 加载到 a0
sd a0, stolen_slot(tp) # 把 a0 存进 spill state stolen slot
sd tp, REG_OFFSET(tp)(a5) # 把 tp 存到到 dc->tp
... 所有寄存器(除 tp)都替换为 dc 中的值
>>> append_jmp_to_fcache_target
ld a0, A2_SLOT(tp) # 把 A2 slot 的值放回 A0(跳转地址)
jr a0
| jump
insert_fragment_prefix
ld a0, 0(tp) # 从 spill_state A0 slot 加载到 a0
ld a1, 8(tp) # 从 spill_state A1 slot 加载到 a1
到这里,除了 tp,所有的寄存器的值都是 dc 中的值了
tp 指向了 spill_state (TODO:所有读写 tp 的指令都需要 mangle!!)
actual bb
| jump to exit stub
insert_exit_stub_other_flags
sd a0, 0(tp) # 把 a0 的值存回 spill_state
sd a1, 8(tp) # 把 a1 的值存回 spill_state
li a0, link_stub # 把 link_stub 地址存入 a0
auipc a1, 0
ld a1, xxx(a1) # a1 中保存 exit_stub 最后的那个地址,也就是 fcache_return 的地址
jr a1
| jump
append_fcache_return_common
>>> append_prepare_fcache_return
sd a5, A3_SLOT(tp) # a5 存到 spill_state A3 slot
ld a5, DC_SLOT(tp) # 将 spill_state dc slot 放入 a5
此时,a5 又恢复了“正常”了!
>>> append_save_gpr
... # 将除 A0, A1 外的寄存器保存到 dc
ld a1, A3_SLOT(tp)
sd a1, REG_OFFSET(a5)(a5) # 把正确的 A5 值保存到 dc
ld a1, stolen_slot(tp)
sd a1, REG_OFFSET(tp)(a5) # 把正确的 tp 保存到 dc
ld tp, 0(a5) # 把原始 tp 加载回来
>>> body
ld sp, dstack_offs(a5) # 切换到一个干净的栈上
... # 把 fcsr 写回 dc
sd a0, last_exit(a5) # dc->last_exit = (link_stub)
>>> append_call_dispatch
>>>>>> dr_insert_call_noreturn (TODO: port to RISC-V maybe?)
call d_r_dispatch with no return.
所以问题的原因是最后一个 bb 回到
d_r_dispatch 的时候, dcontext->thread_stats 不知道怎么的被改了,这他妈也太怪了