ファイル内のtarget/i386/translate.c
コマンドCALL
(opcode 0xe8)は、次のように実装されます。
case 0xe8: /* call im */
{
if (dflag != MO_16) {
tval = (int32_t)insn_get(env, s, MO_32);
} else {
tval = (int16_t)insn_get(env, s, MO_16);
}
next_eip = s->pc - s->cs_base;
tval += next_eip;
if (dflag == MO_16) {
tval &= 0xffff;
} else if (!CODE64(s)) {
tval &= 0xffffffff;
}
tcg_gen_movi_tl(cpu_T0, next_eip);
gen_push_v(s, cpu_T0);
gen_bnd_jmp(s);
gen_jmp(s, tval);
}
break;
next_eip
次の呼び出しで値が保存されます。
tcg_gen_movi_tl(cpu_T0, next_eip);
gen_push_v(s, cpu_T0);
next_eip
ただし、この値()が実装でどのように使用されているかがわかりませんRET
。
case 0xc3: /* ret */
ot = gen_pop_T0(s);
gen_pop_update(s, ot);
/* Note that gen_pop_T0 uses a zero-extending load. */
gen_op_jmp_v(cpu_T0);
gen_bnd_jmp(s);
gen_jr(s, cpu_T0);
break;
実装を追跡すると、CALL
戻りアドレスを使用するコードが表示されます。
void tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2)
{
TCGOp *op = tcg_emit_op(opc); // INDEX_op_movi_i64
op->args[0] = a1; // address of register
op->args[1] = a2; // **REAL RETURN ADDRESS**
}
RET
ただし、実装を追跡すると、実際の返品先住所が見つかりません。
RET
命令の実装がどこで使用されているのか誰が教えてもらえますかnext_eip
?
ベストアンサー1
値がnext_eip
スタックからポップされます。
ot = gen_pop_T0(s);
副作用として、このアップデートはcpu_T0
ジャンプに使用されます。実行を参照してくださいgen_pop_T0
。
TCGMemOp d_ot = mo_pushpop(s, s->dflag);
gen_lea_v_seg(s, mo_stacksize(s), cpu_regs[R_ESP], R_SS, -1);
gen_op_ld_v(s, d_ot, cpu_T0, cpu_A0);
return d_ot;
RET
プッシュされた値を取得する方法は次のとおりですCALL
。
tcg_gen_movi_tl(cpu_T0, next_eip);
gen_push_v(s, cpu_T0);
RET
命令を解釈するとき、シミュレータは内部知識に頼ることはできません。シミュレータはRET
命令と同じように動作し、スタックから戻りアドレスを取得する必要があります。 (実際のコードでは、RET
sJMP
の後にaCALL
の代わりに手動で設定したスタックが付いてくる、aがaにつながらない、またはコードがスタックのCALL
値を変更してRET
aの戻りアドレスを変更することが多いです。RET
)これがまさにaです。 QEMURET
の役割:gen_pop_T0
戻りアドレスをスタック()から取り出し、処理します。