1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +00:00

Clarify, unify and correct decoding and encoding of [CALL/RET/JMP][near/far/relative/absolute].

This commit is contained in:
Thomas Harte 2022-03-09 16:48:06 -05:00
parent 381fd5dbe4
commit bbf925a27e
3 changed files with 61 additions and 44 deletions

View File

@ -292,7 +292,7 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
case 0x98: Complete(CBW, eAX, AH, DataSize::Byte); break;
case 0x99: Complete(CWD, eAX, eDX, data_size_); break;
case 0x9a: Far(CALLF); break;
case 0x9a: Far(CALLfar); break;
case 0x9b: Complete(WAIT, None, None, DataSize::None); break;
case 0x9c: Complete(PUSHF, None, None, data_size_); break;
case 0x9d: Complete(POPF, None, None, data_size_); break;
@ -340,8 +340,8 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
source_ = Source::Immediate;
operand_size_ = DataSize::Byte;
break;
case 0xc2: RegData(RETN, None, data_size_); break;
case 0xc3: Complete(RETN, None, None, DataSize::None); break;
case 0xc2: RegData(RETnear, None, data_size_); break;
case 0xc3: Complete(RETnear, None, None, DataSize::None); break;
case 0xc4: MemRegReg(LES, Reg_MemReg, data_size_); break;
case 0xc5: MemRegReg(LDS, Reg_MemReg, data_size_); break;
case 0xc6: MemRegReg(MOV, MemRegMOV, DataSize::Byte); break;
@ -356,8 +356,8 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
Complete(LEAVE, None, None, DataSize::None);
break;
case 0xca: RegData(RETF, None, data_size_); break;
case 0xcb: Complete(RETF, None, None, DataSize::DWord); break;
case 0xca: RegData(RETfar, None, data_size_); break;
case 0xcb: Complete(RETfar, None, None, DataSize::DWord); break;
case 0xcc: Complete(INT3, None, None, DataSize::None); break;
case 0xcd: RegData(INT, None, DataSize::Byte); break;
@ -397,10 +397,10 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
case 0xe6: AddrReg(OUT, eAX, DataSize::Byte, DataSize::Byte); break;
case 0xe7: AddrReg(OUT, eAX, data_size_, DataSize::Byte); break;
case 0xe8: RegData(CALLD, None, data_size_); break;
case 0xe9: RegData(JMPN, None, data_size_); break;
case 0xea: Far(JMPF); break;
case 0xeb: Displacement(JMPN, DataSize::Byte); break;
case 0xe8: Displacement(CALLrel, data_size_); break;
case 0xe9: Displacement(JMPrel, data_size_); break;
case 0xea: Far(JMPfar); break;
case 0xeb: Displacement(JMPrel, DataSize::Byte); break;
case 0xec: Complete(IN, eDX, eAX, DataSize::Byte); break;
case 0xed: Complete(IN, eDX, eAX, data_size_); break;
@ -741,18 +741,10 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
case 0: operation_ = Operation::INC; break;
case 1: operation_ = Operation::DEC; break;
case 2: operation_ = Operation::CALLN; break;
case 3:
operation_ = Operation::CALLF;
operand_size_ = DataSize::DWord;
source_ = Source::Immediate;
break;
case 4: operation_ = Operation::JMPN; break;
case 5:
operation_ = Operation::JMPF;
operand_size_ = DataSize::DWord;
source_ = Source::Immediate;
break;
case 2: operation_ = Operation::CALLabs; break;
case 3: operation_ = Operation::CALLfar; break;
case 4: operation_ = Operation::JMPabs; break;
case 5: operation_ = Operation::JMPfar; break;
case 6: operation_ = Operation::PUSH; break;
}
break;

View File

@ -87,21 +87,23 @@ enum class Operation: uint8_t {
JS, JNS, JP, JNP, JL, JNL, JLE, JNLE,
/// Far call; see the segment() and offset() fields.
CALLF,
CALLfar,
/// Displacement call; followed by a 16-bit operand providing a call offset.
CALLD,
CALLrel,
/// Near call.
CALLN,
CALLabs,
/// Return from interrupt.
IRET,
/// Near return; if source is not ::None then it will be an ::Immediate indicating how many additional bytes to remove from the stack.
RETF,
RETfar,
/// Far return; if source is not ::None then it will be an ::Immediate indicating how many additional bytes to remove from the stack.
RETN,
/// Near jump; if an operand is not ::None then it gives an absolute destination; otherwise see the displacement.
JMPN,
RETnear,
/// Near jump with an absolute destination.
JMPabs,
/// Near jump with a relative destination.
JMPrel,
/// Far jump to the indicated segment and offset.
JMPF,
JMPfar,
/// Relative jump performed only if CX = 0; see the displacement.
JPCX,
/// Generates a software interrupt of the level stated in the operand.

View File

@ -146,10 +146,10 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
// [[ omitted: gs insw (%dx),%es:(%di) ]]
// jnp 0xffffffaf
// ret $0x4265
test(instructions[4], Operation::RETN);
test(instructions[5], Operation::RETF, 0x4826);
test(instructions[4], Operation::RETnear);
test(instructions[5], Operation::RETfar, 0x4826);
test(instructions[6], Operation::JNP, std::nullopt, 0xff9f);
test(instructions[7], Operation::RETN, 0x4265);
test(instructions[7], Operation::RETnear, 0x4265);
// dec %si
// out %ax,(%dx)
@ -215,7 +215,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
// fwait
// out %al,$0xd3
test(instructions[30], DataSize::Word, Operation::XCHG, Source::eAX, Source::eDI);
test(instructions[31], Operation::RETN);
test(instructions[31], Operation::RETnear);
test(instructions[32], Operation::WAIT);
test(instructions[33], DataSize::Byte, Operation::OUT, Source::eAX, Source::DirectAddress, 0xd3);
@ -261,7 +261,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
// dec %dx
// mov $0x9e,%al
// stc
test(instructions[50], Operation::CALLD, uint16_t(0x16c8));
test(instructions[50], Operation::CALLrel, 0, 0x16c8);
test(instructions[51], DataSize::Word, Operation::DEC, Source::eDX, Source::eDX);
test(instructions[52], DataSize::Byte, Operation::MOV, Source::Immediate, Source::eAX, 0x9e);
test(instructions[53], Operation::STC);
@ -307,7 +307,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
});
XCTAssertEqual(instructions.size(), 1);
test_far(instructions[0], Operation::CALLF, 0x7856, 0x3412);
test_far(instructions[0], Operation::CALLfar, 0x7856, 0x3412);
}
- (void)testLDSLESEtc {
@ -349,6 +349,30 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
XCTAssertEqual(instructions[1].address_size(), AddressSize::b16);
}
- (void)testJMP {
decltype(decode<Model::i80386>({0x00})) instructions;
instructions = decode<Model::i80386>({
// JMP +0x00efcdab
0xe9, 0xab, 0xcd, 0xef, 0x00,
// JMP 0xc389:0x67452301
0xea, 0x01, 0x23, 0x45, 0x67, 0x89, 0xc3,
// JMP -79
0xeb, 0xb1,
// JMP DWORD (edx)
0xff, 0x22,
// JMP FWORD (eax)
0xff, 0x28,
}, true);
XCTAssertEqual(instructions.size(), 5);
test(instructions[0], Operation::JMPrel, 0, 0xefcdab);
test_far(instructions[1], Operation::JMPfar, 0xc389, 0x67452301);
test(instructions[2], Operation::JMPrel, 0, -79);
test(instructions[3], DataSize::DWord, Operation::JMPabs, ScaleIndexBase(Source::eDX));
test(instructions[4], DataSize::DWord, Operation::JMPfar, ScaleIndexBase(Source::eAX));
}
- (void)test32bitSequence {
const auto instructions = decode<Model::i80386>({
0x2e, 0x42, 0x0c, 0x09, 0x81, 0x47, 0xbe, 0xa9, 0x3a, 0x68, 0x9f, 0xf0, 0x7a, 0xe2, 0x3e, 0xb4,
@ -448,8 +472,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
// or DWORD PTR [esi+0x1a],eax
// rcr BYTE PTR [ebp-0x78],0x34
// movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
test(instructions[32], Operation::JMPN, 0x29cf120d - 0x53);
// XCTAssertEqual(instructions[32].source(), Source::None);
test(instructions[32], Operation::JMPrel, 0, 0x29cf120d - 0x53);
test(instructions[33], DataSize::DWord, Operation::OR, Source::eAX, ScaleIndexBase(Source::eSI), 0, 0x1a);
test(instructions[34], DataSize::Byte, Operation::RCR, Source::Immediate, ScaleIndexBase(Source::eBP), 0x34, -0x78);
test(instructions[35], DataSize::DWord, Operation::MOVS);
@ -512,7 +535,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
// fs pusha
// mov al,0xcf
// jecxz 0x000000d4 (from 0x9d)
test_far(instructions[60], Operation::CALLF, 0xe21b, 0x97d0f58a);
test_far(instructions[60], Operation::CALLfar, 0xe21b, 0x97d0f58a);
test(instructions[61], Operation::PUSHA);
test(instructions[62], DataSize::Byte, Operation::MOV, Source::Immediate, Source::eAX, 0xcf);
test(instructions[63], Operation::JPCX, 0, 0xd4 - 0x9d);