파일에서 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
s JMP
뒤에 a 대신 수동으로 설정한 스택이 따라오거나 CALL
, a가 a로 이어지지 않거나, 코드가 CALL
스택의 값을 변경하여 RET
a의 반환 주소를 변경하는 경우가 많습니다 . RET
) 이것이 바로 a입니다. QEMU RET
의 역할: gen_pop_T0
반환 주소를 스택()에서 꺼내어 처리합니다.