Merge pull request #4781 from Sonicadvance1/implement_call_ret_far

OpcodeDispatcher: Implement support for CALLF/RETF
This commit is contained in:
LC authored and GitHub committed 2025-08-14 00:15:31 -04:00
commit 2825ac282a
12 files changed
+231 -2

No files matched your search

@@ -959,6 +959,60 @@ void OpDispatchBuilder::JUMPFARIndirectOp(OpcodeArgs) {
ExitFunction(RIPOffset);
}
void OpDispatchBuilder::CALLFARIndirectOp(OpcodeArgs) {
const auto SrcSize = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REX_WIDENING ? OpSize::i64Bit : OpSize::i32Bit;
// Calculate flags early.
CalculateDeferredFlags();
BlockSetRIP = true;
Ref Src = MakeSegmentAddress(Op, Op->Dest);
AddressMode SrcCS = {.Base = Src, .Offset = 4, .AddrSize = OpSize::i64Bit};
auto RIPOffset = _LoadMemAutoTSO(GPRClass, OpSize::i32Bit, Src, OpSize::i8Bit);
auto NewSegmentCS = _LoadMemAutoTSO(GPRClass, OpSize::i16Bit, SrcCS, OpSize::i8Bit);
auto CurrentCS = _LoadContext(OpSize::i16Bit, GPRClass, offsetof(FEXCore::Core::CPUState, cs_idx));
auto NewRIP = GetRelocatedPC(Op);
// Push the current CS
Push(SrcSize, CurrentCS);
// Push the return address.
Push(SrcSize, NewRIP);
// Set up the new CSSegment.
_StoreContext(OpSize::i16Bit, GPRClass, NewSegmentCS, offsetof(FEXCore::Core::CPUState, cs_idx));
UpdatePrefixFromSegment(NewSegmentCS, FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX);
// Store the new RIP
ExitFunction(RIPOffset);
}
void OpDispatchBuilder::RETFARIndirectOp(OpcodeArgs) {
const auto GPRSize = GetGPROpSize();
const auto SrcSize = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REX_WIDENING ? OpSize::i64Bit : OpSize::i32Bit;
Ref SP = _RMWHandle(LoadGPRRegister(X86State::REG_RSP));
Ref NewRIP = Pop(SrcSize, SP);
Ref NewSegmentCS = Pop(SrcSize, SP);
// Optional SP offset.
if (Op->Src[0].IsLiteral()) {
SP = Add(GPRSize, SP, Op->Src[0].Literal());
}
// Store the new stack pointer
StoreGPRRegister(X86State::REG_RSP, SP);
_StoreContext(OpSize::i16Bit, GPRClass, NewSegmentCS, offsetof(FEXCore::Core::CPUState, cs_idx));
UpdatePrefixFromSegment(NewSegmentCS, FEXCore::X86Tables::DecodeFlags::FLAG_CS_PREFIX);
// Store the new RIP
ExitFunction(NewRIP);
BlockSetRIP = true;
}
void OpDispatchBuilder::TESTOp(OpcodeArgs, uint32_t SrcIndex) {
// TEST is an instruction that does an AND between the sources
// Result isn't stored in result, only writes to flags
@@ -349,6 +349,8 @@ public:
void JUMPOp(OpcodeArgs);
void JUMPAbsoluteOp(OpcodeArgs);
void JUMPFARIndirectOp(OpcodeArgs);
void CALLFARIndirectOp(OpcodeArgs);
void RETFARIndirectOp(OpcodeArgs);
void TESTOp(OpcodeArgs, uint32_t SrcIndex);
void MOVSXDOp(OpcodeArgs);
void MOVSXOp(OpcodeArgs);
@@ -57,6 +57,7 @@ constexpr inline DispatchTableEntry OpDispatch_BaseOpTable[] = {
{0xC2, 2, &OpDispatchBuilder::RETOp},
{0xC8, 1, &OpDispatchBuilder::EnterOp},
{0xC9, 1, &OpDispatchBuilder::LEAVEOp},
{0xCA, 2, &OpDispatchBuilder::RETFARIndirectOp},
{0xCC, 2, &OpDispatchBuilder::INTOp},
{0xCF, 1, &OpDispatchBuilder::IRETOp},
{0xD7, 2, &OpDispatchBuilder::XLATOp},
@@ -117,6 +117,7 @@ constexpr DispatchTableEntry OpDispatch_PrimaryGroupTables[] = {
{OPD(FEXCore::X86Tables::TYPE_GROUP_5, OpToIndex(0xFF), 0), 1, &OpDispatchBuilder::INCOp}, // INC
{OPD(FEXCore::X86Tables::TYPE_GROUP_5, OpToIndex(0xFF), 1), 1, &OpDispatchBuilder::DECOp}, // DEC
{OPD(FEXCore::X86Tables::TYPE_GROUP_5, OpToIndex(0xFF), 2), 1, &OpDispatchBuilder::CALLAbsoluteOp},
{OPD(FEXCore::X86Tables::TYPE_GROUP_5, OpToIndex(0xFF), 3), 1, &OpDispatchBuilder::CALLFARIndirectOp},
{OPD(FEXCore::X86Tables::TYPE_GROUP_5, OpToIndex(0xFF), 4), 1, &OpDispatchBuilder::JUMPAbsoluteOp},
{OPD(FEXCore::X86Tables::TYPE_GROUP_5, OpToIndex(0xFF), 5), 1, &OpDispatchBuilder::JUMPFARIndirectOp},
{OPD(FEXCore::X86Tables::TYPE_GROUP_5, OpToIndex(0xFF), 6), 1, &OpDispatchBuilder::PUSHOp},
@@ -171,7 +171,8 @@ std::array<X86InstInfo, MAX_PRIMARY_TABLE_SIZE> BaseOps = []() consteval {
{0xC3, 1, X86InstInfo{"RET", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_SETS_RIP | FLAGS_BLOCK_END , 0, nullptr}},
{0xC8, 1, X86InstInfo{"ENTER", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_DEBUG_MEM_ACCESS , 3, nullptr}},
{0xC9, 1, X86InstInfo{"LEAVE", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_DEBUG_MEM_ACCESS , 0, nullptr}},
{0xCA, 2, X86InstInfo{"RETF", TYPE_PRIV, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_SETS_RIP | FLAGS_BLOCK_END, 0, nullptr}},
{0xCA, 1, X86InstInfo{"RETF", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_SETS_RIP | FLAGS_BLOCK_END, 2, nullptr}},
{0xCB, 1, X86InstInfo{"RETF", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_SETS_RIP | FLAGS_BLOCK_END, 0, nullptr}},
{0xCC, 1, X86InstInfo{"INT3", TYPE_INST, FLAGS_BLOCK_END, 0, nullptr}},
{0xCD, 1, X86InstInfo{"INT", TYPE_INST, DEFAULT_SYSCALL_FLAGS, 1, nullptr}},
{0xCF, 1, X86InstInfo{"IRET", TYPE_INST, FLAGS_SETS_RIP | FLAGS_BLOCK_END, 0, nullptr}},
@@ -129,7 +129,7 @@ std::array<X86InstInfo, MAX_INST_GROUP_TABLE_SIZE> PrimaryInstGroupOps = []() co
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 0), 1, X86InstInfo{"INC", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}},
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 1), 1, X86InstInfo{"DEC", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}},
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 2), 1, X86InstInfo{"CALL", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_SETS_RIP | FLAGS_MODRM | FLAGS_BLOCK_END | FLAGS_CALL , 0, nullptr}},
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 3), 1, X86InstInfo{"CALLF", TYPE_INST, FLAGS_SETS_RIP | FLAGS_MODRM | FLAGS_BLOCK_END, 0, nullptr}},
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 3), 1, X86InstInfo{"CALLF", TYPE_INST, FLAGS_SETS_RIP | FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_SF_MOD_MEM_ONLY | FLAGS_BLOCK_END, 0, nullptr}},
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 4), 1, X86InstInfo{"JMP", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_SETS_RIP | FLAGS_MODRM | FLAGS_BLOCK_END , 0, nullptr}},
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 5), 1, X86InstInfo{"JMPF", TYPE_INST, FLAGS_SETS_RIP | FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_SF_MOD_MEM_ONLY | FLAGS_BLOCK_END, 0, nullptr}},
{OPD(TYPE_GROUP_5, OpToIndex(0xFF), 6), 1, X86InstInfo{"PUSH", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_DEBUG_MEM_ACCESS | FLAGS_MODRM, 0, nullptr}},
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1",
"RBX": "0xe0000fe8",
"RSP": "0xe0000ff0"
}
}
%endif
mov rsp, 0xe000_1000
mov ax, cs
lea edi, [rel .success]
sub rsp, 16
mov [rsp], edi
mov [rsp+4], cs
mov rax, 0
call far dword [esp]
hlt
.success:
mov rax, 1
mov rbx, rsp
o32 retf
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1",
"RBX": "0xe0000fe8",
"RSP": "0xe0002224"
}
}
%endif
mov rsp, 0xe000_1000
mov ax, cs
lea edi, [rel .success]
sub rsp, 16
mov [rsp], edi
mov [rsp+4], cs
mov rax, 0
call far dword [esp]
hlt
.success:
mov rax, 1
mov rbx, rsp
o32 retf 0x1234
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1",
"RBX": "0xe0000fe0",
"RSP": "0xe0000ff0"
}
}
%endif
mov rsp, 0xe000_1000
mov ax, cs
lea edi, [rel .success]
sub rsp, 16
mov [rsp], edi
mov [rsp+4], cs
mov rax, 0
o64 call far [rsp]
hlt
.success:
mov rax, 1
mov rbx, rsp
o64 retf
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "1",
"RBX": "0xe0000fe0",
"RSP": "0xe00090f0"
}
}
%endif
mov rsp, 0xe000_1000
mov ax, cs
lea edi, [rel .success]
sub rsp, 16
mov [rsp], edi
mov [rsp+4], cs
mov rax, 0
o64 call far [rsp]
hlt
.success:
mov rax, 1
mov rbx, rsp
o64 retf 0x8100
+39
View File
@@ -4473,6 +4473,45 @@
"bfxil x4, x20, #0, #8"
]
},
"retf 0x1234": {
"ExpectedInstructionCount": 15,
"Comment": "0xca",
"ExpectedArm64ASM": [
"mov x20, x8",
"ldp w21, w22, [x20], #8",
"mov w23, #0x1234",
"add x8, x20, x23",
"strh w22, [x28, #930]",
"ubfx w20, w22, #2, #1",
"and w22, w22, #0xfff8",
"add x0, x28, x20, lsl #3",
"ldr x20, [x0, #1168]",
"ldr x20, [x20, w22, uxtw]",
"lsr x22, x20, #32",
"and w23, w22, #0xff000000",
"orr w20, w23, w20, lsr #16",
"bfi w20, w22, #16, #8",
"str w20, [x28, #948]"
]
},
"retf": {
"ExpectedInstructionCount": 12,
"Comment": "0xcb",
"ExpectedArm64ASM": [
"ldp w20, w21, [x8], #8",
"strh w21, [x28, #930]",
"ubfx w22, w21, #2, #1",
"and w21, w21, #0xfff8",
"add x0, x28, x22, lsl #3",
"ldr x22, [x0, #1168]",
"ldr x21, [x22, w21, uxtw]",
"lsr x22, x21, #32",
"and w23, w22, #0xff000000",
"orr w21, w23, w21, lsr #16",
"bfi w21, w22, #16, #8",
"str w21, [x28, #948]"
]
},
"cmc": {
"ExpectedInstructionCount": 3,
"Comment": "0xf5",
@@ -2973,6 +2973,29 @@
"strh w4, [x8, #-2]!"
]
},
"call far [rsp]": {
"ExpectedInstructionCount": 17,
"Comment": "GROUP5 0xff /3",
"ExpectedArm64ASM": [
"ldr w20, [x8]",
"ldrh w21, [x8, #4]",
"ldrh w22, [x28, #930]",
"mov w23, #0x4",
"movk w23, #0x1, lsl #16",
"stp x23, x22, [x8, #-16]!",
"strh w21, [x28, #930]",
"ubfx w22, w21, #2, #1",
"and w21, w21, #0xfff8",
"add x0, x28, x22, lsl #3",
"ldr x22, [x0, #1168]",
"ldr x21, [x22, w21, uxtw]",
"lsr x22, x21, #32",
"and w23, w22, #0xff000000",
"orr w21, w23, w21, lsr #16",
"bfi w21, w22, #16, #8",
"str w21, [x28, #948]"
]
},
"push rax": {
"ExpectedInstructionCount": 1,
"Comment": "GROUP4 0xff /6",