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:
parent
381fd5dbe4
commit
bbf925a27e
@ -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 0x98: Complete(CBW, eAX, AH, DataSize::Byte); break;
|
||||||
case 0x99: Complete(CWD, eAX, eDX, data_size_); 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 0x9b: Complete(WAIT, None, None, DataSize::None); break;
|
||||||
case 0x9c: Complete(PUSHF, None, None, data_size_); break;
|
case 0x9c: Complete(PUSHF, None, None, data_size_); break;
|
||||||
case 0x9d: Complete(POPF, None, None, data_size_); break;
|
case 0x9d: Complete(POPF, None, None, data_size_); break;
|
||||||
@ -340,12 +340,12 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
|
|||||||
source_ = Source::Immediate;
|
source_ = Source::Immediate;
|
||||||
operand_size_ = DataSize::Byte;
|
operand_size_ = DataSize::Byte;
|
||||||
break;
|
break;
|
||||||
case 0xc2: RegData(RETN, None, data_size_); break;
|
case 0xc2: RegData(RETnear, None, data_size_); break;
|
||||||
case 0xc3: Complete(RETN, None, None, DataSize::None); break;
|
case 0xc3: Complete(RETnear, None, None, DataSize::None); break;
|
||||||
case 0xc4: MemRegReg(LES, Reg_MemReg, data_size_); break;
|
case 0xc4: MemRegReg(LES, Reg_MemReg, data_size_); break;
|
||||||
case 0xc5: MemRegReg(LDS, Reg_MemReg, data_size_); break;
|
case 0xc5: MemRegReg(LDS, Reg_MemReg, data_size_); break;
|
||||||
case 0xc6: MemRegReg(MOV, MemRegMOV, DataSize::Byte); break;
|
case 0xc6: MemRegReg(MOV, MemRegMOV, DataSize::Byte); break;
|
||||||
case 0xc7: MemRegReg(MOV, MemRegMOV, data_size_); break;
|
case 0xc7: MemRegReg(MOV, MemRegMOV, data_size_); break;
|
||||||
|
|
||||||
case 0xc8:
|
case 0xc8:
|
||||||
RequiresMin(i80186);
|
RequiresMin(i80186);
|
||||||
@ -356,8 +356,8 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
|
|||||||
Complete(LEAVE, None, None, DataSize::None);
|
Complete(LEAVE, None, None, DataSize::None);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xca: RegData(RETF, None, data_size_); break;
|
case 0xca: RegData(RETfar, None, data_size_); break;
|
||||||
case 0xcb: Complete(RETF, None, None, DataSize::DWord); break;
|
case 0xcb: Complete(RETfar, None, None, DataSize::DWord); break;
|
||||||
|
|
||||||
case 0xcc: Complete(INT3, None, None, DataSize::None); break;
|
case 0xcc: Complete(INT3, None, None, DataSize::None); break;
|
||||||
case 0xcd: RegData(INT, None, DataSize::Byte); 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 0xe6: AddrReg(OUT, eAX, DataSize::Byte, DataSize::Byte); break;
|
||||||
case 0xe7: AddrReg(OUT, eAX, data_size_, DataSize::Byte); break;
|
case 0xe7: AddrReg(OUT, eAX, data_size_, DataSize::Byte); break;
|
||||||
|
|
||||||
case 0xe8: RegData(CALLD, None, data_size_); break;
|
case 0xe8: Displacement(CALLrel, data_size_); break;
|
||||||
case 0xe9: RegData(JMPN, None, data_size_); break;
|
case 0xe9: Displacement(JMPrel, data_size_); break;
|
||||||
case 0xea: Far(JMPF); break;
|
case 0xea: Far(JMPfar); break;
|
||||||
case 0xeb: Displacement(JMPN, DataSize::Byte); break;
|
case 0xeb: Displacement(JMPrel, DataSize::Byte); break;
|
||||||
|
|
||||||
case 0xec: Complete(IN, eDX, eAX, DataSize::Byte); break;
|
case 0xec: Complete(IN, eDX, eAX, DataSize::Byte); break;
|
||||||
case 0xed: Complete(IN, eDX, eAX, data_size_); break;
|
case 0xed: Complete(IN, eDX, eAX, data_size_); break;
|
||||||
@ -739,20 +739,12 @@ std::pair<int, typename Decoder<model>::InstructionT> Decoder<model>::decode(con
|
|||||||
switch(reg) {
|
switch(reg) {
|
||||||
default: undefined();
|
default: undefined();
|
||||||
|
|
||||||
case 0: operation_ = Operation::INC; break;
|
case 0: operation_ = Operation::INC; break;
|
||||||
case 1: operation_ = Operation::DEC; break;
|
case 1: operation_ = Operation::DEC; break;
|
||||||
case 2: operation_ = Operation::CALLN; break;
|
case 2: operation_ = Operation::CALLabs; break;
|
||||||
case 3:
|
case 3: operation_ = Operation::CALLfar; break;
|
||||||
operation_ = Operation::CALLF;
|
case 4: operation_ = Operation::JMPabs; break;
|
||||||
operand_size_ = DataSize::DWord;
|
case 5: operation_ = Operation::JMPfar; break;
|
||||||
source_ = Source::Immediate;
|
|
||||||
break;
|
|
||||||
case 4: operation_ = Operation::JMPN; break;
|
|
||||||
case 5:
|
|
||||||
operation_ = Operation::JMPF;
|
|
||||||
operand_size_ = DataSize::DWord;
|
|
||||||
source_ = Source::Immediate;
|
|
||||||
break;
|
|
||||||
case 6: operation_ = Operation::PUSH; break;
|
case 6: operation_ = Operation::PUSH; break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -87,21 +87,23 @@ enum class Operation: uint8_t {
|
|||||||
JS, JNS, JP, JNP, JL, JNL, JLE, JNLE,
|
JS, JNS, JP, JNP, JL, JNL, JLE, JNLE,
|
||||||
|
|
||||||
/// Far call; see the segment() and offset() fields.
|
/// Far call; see the segment() and offset() fields.
|
||||||
CALLF,
|
CALLfar,
|
||||||
/// Displacement call; followed by a 16-bit operand providing a call offset.
|
/// Displacement call; followed by a 16-bit operand providing a call offset.
|
||||||
CALLD,
|
CALLrel,
|
||||||
/// Near call.
|
/// Near call.
|
||||||
CALLN,
|
CALLabs,
|
||||||
/// Return from interrupt.
|
/// Return from interrupt.
|
||||||
IRET,
|
IRET,
|
||||||
/// Near return; if source is not ::None then it will be an ::Immediate indicating how many additional bytes to remove from the stack.
|
/// 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.
|
/// Far return; if source is not ::None then it will be an ::Immediate indicating how many additional bytes to remove from the stack.
|
||||||
RETN,
|
RETnear,
|
||||||
/// Near jump; if an operand is not ::None then it gives an absolute destination; otherwise see the displacement.
|
/// Near jump with an absolute destination.
|
||||||
JMPN,
|
JMPabs,
|
||||||
|
/// Near jump with a relative destination.
|
||||||
|
JMPrel,
|
||||||
/// Far jump to the indicated segment and offset.
|
/// Far jump to the indicated segment and offset.
|
||||||
JMPF,
|
JMPfar,
|
||||||
/// Relative jump performed only if CX = 0; see the displacement.
|
/// Relative jump performed only if CX = 0; see the displacement.
|
||||||
JPCX,
|
JPCX,
|
||||||
/// Generates a software interrupt of the level stated in the operand.
|
/// Generates a software interrupt of the level stated in the operand.
|
||||||
|
@ -146,10 +146,10 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
|
|||||||
// [[ omitted: gs insw (%dx),%es:(%di) ]]
|
// [[ omitted: gs insw (%dx),%es:(%di) ]]
|
||||||
// jnp 0xffffffaf
|
// jnp 0xffffffaf
|
||||||
// ret $0x4265
|
// ret $0x4265
|
||||||
test(instructions[4], Operation::RETN);
|
test(instructions[4], Operation::RETnear);
|
||||||
test(instructions[5], Operation::RETF, 0x4826);
|
test(instructions[5], Operation::RETfar, 0x4826);
|
||||||
test(instructions[6], Operation::JNP, std::nullopt, 0xff9f);
|
test(instructions[6], Operation::JNP, std::nullopt, 0xff9f);
|
||||||
test(instructions[7], Operation::RETN, 0x4265);
|
test(instructions[7], Operation::RETnear, 0x4265);
|
||||||
|
|
||||||
// dec %si
|
// dec %si
|
||||||
// out %ax,(%dx)
|
// out %ax,(%dx)
|
||||||
@ -215,7 +215,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
|
|||||||
// fwait
|
// fwait
|
||||||
// out %al,$0xd3
|
// out %al,$0xd3
|
||||||
test(instructions[30], DataSize::Word, Operation::XCHG, Source::eAX, Source::eDI);
|
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[32], Operation::WAIT);
|
||||||
test(instructions[33], DataSize::Byte, Operation::OUT, Source::eAX, Source::DirectAddress, 0xd3);
|
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
|
// dec %dx
|
||||||
// mov $0x9e,%al
|
// mov $0x9e,%al
|
||||||
// stc
|
// 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[51], DataSize::Word, Operation::DEC, Source::eDX, Source::eDX);
|
||||||
test(instructions[52], DataSize::Byte, Operation::MOV, Source::Immediate, Source::eAX, 0x9e);
|
test(instructions[52], DataSize::Byte, Operation::MOV, Source::Immediate, Source::eAX, 0x9e);
|
||||||
test(instructions[53], Operation::STC);
|
test(instructions[53], Operation::STC);
|
||||||
@ -307,7 +307,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
|
|||||||
});
|
});
|
||||||
|
|
||||||
XCTAssertEqual(instructions.size(), 1);
|
XCTAssertEqual(instructions.size(), 1);
|
||||||
test_far(instructions[0], Operation::CALLF, 0x7856, 0x3412);
|
test_far(instructions[0], Operation::CALLfar, 0x7856, 0x3412);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testLDSLESEtc {
|
- (void)testLDSLESEtc {
|
||||||
@ -349,6 +349,30 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
|
|||||||
XCTAssertEqual(instructions[1].address_size(), AddressSize::b16);
|
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 {
|
- (void)test32bitSequence {
|
||||||
const auto instructions = decode<Model::i80386>({
|
const auto instructions = decode<Model::i80386>({
|
||||||
0x2e, 0x42, 0x0c, 0x09, 0x81, 0x47, 0xbe, 0xa9, 0x3a, 0x68, 0x9f, 0xf0, 0x7a, 0xe2, 0x3e, 0xb4,
|
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
|
// or DWORD PTR [esi+0x1a],eax
|
||||||
// rcr BYTE PTR [ebp-0x78],0x34
|
// rcr BYTE PTR [ebp-0x78],0x34
|
||||||
// movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
|
// movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
|
||||||
test(instructions[32], Operation::JMPN, 0x29cf120d - 0x53);
|
test(instructions[32], Operation::JMPrel, 0, 0x29cf120d - 0x53);
|
||||||
// XCTAssertEqual(instructions[32].source(), Source::None);
|
|
||||||
test(instructions[33], DataSize::DWord, Operation::OR, Source::eAX, ScaleIndexBase(Source::eSI), 0, 0x1a);
|
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[34], DataSize::Byte, Operation::RCR, Source::Immediate, ScaleIndexBase(Source::eBP), 0x34, -0x78);
|
||||||
test(instructions[35], DataSize::DWord, Operation::MOVS);
|
test(instructions[35], DataSize::DWord, Operation::MOVS);
|
||||||
@ -512,7 +535,7 @@ std::vector<typename InstructionSet::x86::Decoder<model>::InstructionT> decode(c
|
|||||||
// fs pusha
|
// fs pusha
|
||||||
// mov al,0xcf
|
// mov al,0xcf
|
||||||
// jecxz 0x000000d4 (from 0x9d)
|
// 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[61], Operation::PUSHA);
|
||||||
test(instructions[62], DataSize::Byte, Operation::MOV, Source::Immediate, Source::eAX, 0xcf);
|
test(instructions[62], DataSize::Byte, Operation::MOV, Source::Immediate, Source::eAX, 0xcf);
|
||||||
test(instructions[63], Operation::JPCX, 0, 0xd4 - 0x9d);
|
test(instructions[63], Operation::JPCX, 0, 0xd4 - 0x9d);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user