//! Internal abstraction of the 8086 instructions. use crate::{ operands::{Byte, MemoryIndex, ModRmTarget, Pointer, Word}, register::{Register, SegmentRegister}, }; use core::fmt; #[derive(Debug, Clone)] #[allow(dead_code)] /// A single 'line' of executable ASM is called an Instruction, which /// contains the `Mnemonic` that will be executed, alongside its starting offset /// and the raw parsed bytes pub struct Instruction { pub start: usize, // location of the instruction start pub raw: Vec, // raw value of instruction pub opcode: Mnemonic, // actual instruction } impl Instruction { pub fn new() -> Self { Instruction { start: 0, raw: Vec::new(), opcode: Mnemonic::NOP(), } } } impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:04x}:\t", self.start).unwrap(); write!( f, "{:<16}", // length of longest possible instruction self.raw .iter() .map(|b| format!("{:02x}", b)) .collect::>() .join(" ") ) .unwrap(); write!(f, "\t{}", self.opcode) } } #[derive(Debug, Clone)] #[allow(dead_code, non_camel_case_types)] /// All possible mnemonic variantions. /// These are sorted by type and are not in hex-encoding order. // XXX: convert this copy and paste horror in a proc macro like // enum Opcode { // #[derive(default_variations)] // ADD, // ... // } // which then add all variants and also create the matching logic for // src/disasm.rs decode_instructions() pub enum Mnemonic { NOP(), // ADD ADD_FromReg(ModRmTarget, Register), // From Register into either Memory or Register ADD_ToReg(ModRmTarget, Register), // From either Memory or Register into Reigster ADD_Ib(ModRmTarget, Byte), // From Immediate into either Memory or Register ADD_Iv(ModRmTarget, Word), // From Immediate into either Memory or Register ADD_ALIb(Byte), ADD_AXIv(Word), // PUSH PUSH_R(Register), PUSH_S(SegmentRegister), PUSH_Mod(ModRmTarget), // POP POP_S(SegmentRegister), // POP to Segment Register POP_R(Register), // POP to Register POP_M(MemoryIndex), // POP to Memory // OR OR_FromReg(ModRmTarget, Register), OR_ToReg(ModRmTarget, Register), OR_Ib(ModRmTarget, Byte), OR_Iv(ModRmTarget, Word), OR_ALIb(Byte), OR_AXIv(Word), // ADC ADC_FromReg(ModRmTarget, Register), ADC_ToReg(ModRmTarget, Register), ADC_Ib(ModRmTarget, Byte), ADC_Iv(ModRmTarget, Word), ADC_ALIb(Byte), ADC_AXIv(Word), // SBB SBB_FromReg(ModRmTarget, Register), SBB_ToReg(ModRmTarget, Register), SBB_Ib(ModRmTarget, Byte), SBB_Iv(ModRmTarget, Word), SBB_ALIb(Byte), SBB_AXIv(Word), // AND AND_FromReg(ModRmTarget, Register), AND_ToReg(ModRmTarget, Register), AND_Ib(ModRmTarget, Byte), AND_Iv(ModRmTarget, Word), AND_ALIb(Byte), AND_AXIv(Word), // Override OVERRIDE(SegmentRegister), // Decimal Adjustment DAA, DAS, AAA, AAS, // SUB SUB_FromReg(ModRmTarget, Register), SUB_ToReg(ModRmTarget, Register), SUB_Ib(ModRmTarget, Byte), SUB_Iv(ModRmTarget, Word), SUB_ALIb(Byte), SUB_AXIv(Word), // XOR XOR_FromReg(ModRmTarget, Register), XOR_ToReg(ModRmTarget, Register), XOR_Ib(ModRmTarget, Byte), XOR_Iv(ModRmTarget, Word), XOR_ALIb(Byte), XOR_AXIv(Word), // CMP CMP_FromReg(ModRmTarget, Register), CMP_ToReg(ModRmTarget, Register), CMP_Ib(ModRmTarget, Byte), CMP_Iv(ModRmTarget, Word), CMP_ALIb(Byte), CMP_AXIv(Word), // INC INC_Reg(Register), INC_Mod(ModRmTarget), // DEC DEC_Reg(Register), DEC_Mod(ModRmTarget), // Jumps JO(isize), JNO(isize), JB(isize), JNB(isize), JZ(isize), JNZ(isize), JBE(isize), JA(isize), JS(isize), JNS(isize), JPE(isize), JPO(isize), JL(isize), JGE(isize), JLE(isize), JG(isize), LOOPNZ(isize), LOOPZ(isize), LOOP(isize), JCXZ(isize), // TEST TEST(ModRmTarget, Register), TEST_Ib(ModRmTarget, Byte), TEST_Iv(ModRmTarget, Word), TEST_ALIb(Byte), TEST_AXIv(Word), //XHCG XCHG(ModRmTarget, Register), XCHG_AX(Register), // from AX // MOV MOV_FromReg(ModRmTarget, Register), MOV_ToReg(ModRmTarget, Register), MOV_FromSReg(ModRmTarget, SegmentRegister), MOV_ToSReg(ModRmTarget, SegmentRegister), MOV_Ib(ModRmTarget, Byte), MOV_Iv(ModRmTarget, Word), MOV_AL0b(Byte), MOV_AX0v(Word), MOV_0bAL(Byte), MOV_0vAX(Word), MOV_ALIb(Byte), MOV_CLIb(Byte), MOV_DLIb(Byte), MOV_BLIb(Byte), MOV_AHIb(Byte), MOV_CHIb(Byte), MOV_DHIb(Byte), MOV_BHIb(Byte), MOV_AXIv(Word), MOV_CXIv(Word), MOV_DXIv(Word), MOV_BXIv(Word), MOV_SPIv(Word), MOV_BPIv(Word), MOV_SIIv(Word), MOV_DIIv(Word), // LEA LEA(ModRmTarget, Register), // Sign extensions CBW, CWD, // CALL CALL_p(Pointer), CALL_v(isize), CALL_Mod(ModRmTarget), // JUMP JMP_p(Pointer), JMP_b(isize), // parses IByte, but stores as isize JMP_v(isize), // parwses IWord, but stores as isize JMP_Mod(ModRmTarget), // WAIT WAIT, // Push/Pop Flags PUSHF, POPF, SAHF, LAHF, // String Byte Operations MOVSB, MOVSW, CMPSB, CMPSW, STOSB, STOSW, LODSB, LODSW, SCASB, SCASW, // RET RET_Iw(Word), RET, RETF_Iw(Word), RETF, IRET, // Load ES/DS Register LES(ModRmTarget), LDS(ModRmTarget), // NOT NOT(ModRmTarget), // NEG NEG(ModRmTarget), // MUL MUL(ModRmTarget), IMUL(ModRmTarget), // DIV DIV(ModRmTarget), IDIV(ModRmTarget), // HALT HLT, // Shift and Rotate ROL_b(ModRmTarget, Byte), ROR_b(ModRmTarget, Byte), RCL_b(ModRmTarget, Byte), RCR_b(ModRmTarget, Byte), SHL_b(ModRmTarget, Byte), SHR_b(ModRmTarget, Byte), SAR_b(ModRmTarget, Byte), ROL_fromReg(ModRmTarget, Register), ROR_fromReg(ModRmTarget, Register), RCL_fromReg(ModRmTarget, Register), RCR_fromReg(ModRmTarget, Register), SHL_fromReg(ModRmTarget, Register), SHR_fromReg(ModRmTarget, Register), SAR_fromReg(ModRmTarget, Register), // IN IN_AL(Byte), IN_AX(Byte), IN_ALDX, IN_AXDX, // OUT OUT_AL(Byte), OUT_AX(Byte), OUT_ALDX, OUT_AXDX, // INT INT(Byte), INTO, // Flag Manipulation CLC, STC, CLI, STI, CLD, STD, CMC, // Repeat prefix REPNZ, REPZ, // Adjust AAM(Byte), AAD(Byte), // MISC XLAT, } impl fmt::Display for Mnemonic { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::ADD_FromReg(target, reg) => write!(f, "add {target}, {reg}"), Self::ADD_ToReg(target, reg) => write!(f, "add {reg}, {target}"), Self::ADD_Ib(target, byte) => write!(f, "add byte ptr {target}, {byte:#04x}"), Self::ADD_Iv(target, word) => write!(f, "add word ptr {target}, {word:#04x}"), Self::ADD_ALIb(byte) => write!(f, "add {}, {byte:#04x}", Register::AL), Self::ADD_AXIv(word) => write!(f, "add {}, {word:#04x}", Register::AX), Self::PUSH_R(reg) => write!(f, "push {reg}"), Self::PUSH_S(reg) => write!(f, "push {reg}"), Self::PUSH_Mod(target) => write!(f, "push {target}"), Self::POP_R(reg) => write!(f, "pop {reg}"), Self::POP_S(reg) => write!(f, "pop {reg}"), Self::POP_M(mem) => write!(f, "pop {mem}"), Self::OR_FromReg(target, reg) => write!(f, "or {target}, {reg}"), Self::OR_ToReg(target, reg) => write!(f, "or {reg}, {target}"), Self::OR_Ib(target, byte) => write!(f, "or byte ptr {target}, {byte:#04x}"), Self::OR_Iv(target, word) => write!(f, "or word ptr {target}, {word:#04x}"), Self::OR_ALIb(byte) => write!(f, "or {}, {byte:#04x}", Register::AL), Self::OR_AXIv(word) => write!(f, "or {}, {word:#04x}", Register::AX), Self::ADC_FromReg(target, reg) => write!(f, "adc {target}, {reg}"), Self::ADC_ToReg(target, reg) => write!(f, "adc {reg}, {target}"), Self::ADC_Ib(target, byte) => write!(f, "adc byte ptr {target}, {byte:#04x}"), Self::ADC_Iv(target, word) => write!(f, "adc word ptr {target}, {word:#04x}"), Self::ADC_ALIb(byte) => write!(f, "adc {}, {byte:#04x}", Register::AL), Self::ADC_AXIv(word) => write!(f, "adc {}, {word:#04x}", Register::AX), Self::SBB_FromReg(target, reg) => write!(f, "sbb {target}, {reg}"), Self::SBB_ToReg(target, reg) => write!(f, "sbb {reg}, {target}"), Self::SBB_Ib(target, byte) => write!(f, "sbb byte ptr {target}, {byte:#04x}"), Self::SBB_Iv(target, word) => write!(f, "sbb word ptr {target}, {word:#04x}"), Self::SBB_ALIb(byte) => write!(f, "sbb {}, {byte:#04x}", Register::AL), Self::SBB_AXIv(word) => write!(f, "sbb {}, {word:#04x}", Register::AX), Self::AND_FromReg(target, reg) => write!(f, "and {target}, {reg}"), Self::AND_ToReg(target, reg) => write!(f, "and {reg}, {target}"), Self::AND_Ib(target, byte) => write!(f, "and byte ptr {target}, {byte:#04x}"), Self::AND_Iv(target, word) => write!(f, "and word ptr {target}, {word:#04x}"), Self::AND_ALIb(byte) => write!(f, "and {}, {byte:#04x}", Register::AL), Self::AND_AXIv(word) => write!(f, "and {}, {word:#04x}", Register::AX), Self::OVERRIDE(reg) => write!(f, "{reg}:"), Self::DAA => write!(f, "daa"), Self::DAS => write!(f, "das"), Self::AAA => write!(f, "aaa"), Self::AAS => write!(f, "aas"), Self::SUB_FromReg(target, reg) => write!(f, "sub {target}, {reg}"), Self::SUB_ToReg(target, reg) => write!(f, "sub {reg}, {target}"), Self::SUB_Ib(target, byte) => write!(f, "sub byte ptr {target}, {byte:#04x}"), Self::SUB_Iv(target, word) => write!(f, "sub word ptr {target}, {word:#04x}"), Self::SUB_ALIb(byte) => write!(f, "sub {}, {byte:#04x}", Register::AL), Self::SUB_AXIv(word) => write!(f, "sub {}, {word:#04x}", Register::AX), Self::XOR_FromReg(target, reg) => write!(f, "xor {target}, {reg}"), Self::XOR_ToReg(target, reg) => write!(f, "xor {reg}, {target}"), Self::XOR_Ib(target, byte) => write!(f, "xor byte ptr {target}, {byte:#04x}"), Self::XOR_Iv(target, word) => write!(f, "xor word ptr {target}, {word:#04x}"), Self::XOR_ALIb(byte) => write!(f, "xor {}, {byte:#04x}", Register::AL), Self::XOR_AXIv(word) => write!(f, "xor {}, {word:#04x}", Register::AX), Self::CMP_FromReg(target, reg) => write!(f, "cmp {target}, {reg}"), Self::CMP_ToReg(target, reg) => write!(f, "cmp {reg}, {target}"), Self::CMP_Ib(target, byte) => write!(f, "cmp byte ptr {target}, {byte:#04x}"), Self::CMP_Iv(target, word) => write!(f, "cmp word ptr {target}, {word:#04x}"), Self::CMP_ALIb(byte) => write!(f, "cmp {}, {byte:#04x}", Register::AL), Self::CMP_AXIv(word) => write!(f, "cmp {}, {word:#04x}", Register::AX), Self::INC_Reg(reg) => write!(f, "inc {reg}"), Self::INC_Mod(target) => write!(f, "inc {target}"), Self::DEC_Reg(reg) => write!(f, "dec {reg}"), Self::DEC_Mod(target) => write!(f, "dec {target}"), Self::JO(ibyte) => write!(f, "jo {ibyte:#04x}"), Self::JNO(ibyte) => write!(f, "jno {ibyte:#04x}"), Self::JB(ibyte) => write!(f, "jb {ibyte:#04x}"), Self::JNB(ibyte) => write!(f, "jnb {ibyte:#04x}"), Self::JZ(ibyte) => write!(f, "jz {ibyte:#04x}"), Self::JNZ(ibyte) => write!(f, "jnz {ibyte:#04x}"), Self::JBE(ibyte) => write!(f, "jbe {ibyte:#04x}"), Self::JA(ibyte) => write!(f, "ja {ibyte:#04x}"), Self::JS(ibyte) => write!(f, "js {ibyte:#04x}"), Self::JNS(ibyte) => write!(f, "jns {ibyte:#04x}"), Self::JPE(ibyte) => write!(f, "jpe {ibyte:#04x}"), Self::JPO(ibyte) => write!(f, "jpo {ibyte:#04x}"), Self::JL(ibyte) => write!(f, "jl {ibyte:#04x}"), Self::JGE(ibyte) => write!(f, "jge {ibyte:#04x}"), Self::JLE(ibyte) => write!(f, "jle {ibyte:#04x}"), Self::JG(ibyte) => write!(f, "jg {ibyte:#04x}"), Self::LOOPNZ(ibyte) => write!(f, "loopnz {ibyte:#04x}"), Self::LOOPZ(ibyte) => write!(f, "loopz {ibyte:#04x}"), Self::LOOP(ibyte) => write!(f, "loop {ibyte:#04x}"), Self::JCXZ(ibyte) => write!(f, "jcxz {ibyte:#04x}"), Self::TEST(target, reg) => write!(f, "test {target}, {reg}"), Self::TEST_Ib(target, byte) => write!(f, "test byte ptr {target}, {byte:#04x}"), Self::TEST_Iv(target, word) => write!(f, "test word ptr {target}, {word:#04x}"), Self::TEST_ALIb(byte) => write!(f, "test {}, {byte:#04x}", Register::AL), Self::TEST_AXIv(word) => write!(f, "test {}, {word:#04x}", Register::AX), Self::XCHG(target, reg) => write!(f, "xchg {target}, {reg}"), Self::XCHG_AX(reg) => write!(f, "xchg, {reg}, {}", Register::AX), Self::MOV_FromReg(target, reg) => write!(f, "mov {target}, {reg}"), Self::MOV_ToReg(target, reg) => write!(f, "mov {reg}, {target}"), Self::MOV_FromSReg(target, reg) => write!(f, "mov {target}, {reg}"), Self::MOV_ToSReg(target, reg) => write!(f, "mov {reg}, {target}"), Self::MOV_Ib(target, byte) => write!(f, "mov byte {target}, {byte:#04x}"), Self::MOV_Iv(target, word) => write!(f, "mov word {target}, {word:#04x}"), Self::MOV_AL0b(byte) => write!(f, "mov {}, {byte:#04x}", Register::AL), Self::MOV_AX0v(word) => write!(f, "mov {}, {word:#04x}", Register::AX), Self::MOV_0bAL(byte) => write!(f, "mov {byte:#04x}, {}", Register::AL), Self::MOV_0vAX(word) => write!(f, "mov {word:#04x}, {}", Register::AX), Self::MOV_ALIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::AL), Self::MOV_CLIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::CL), Self::MOV_DLIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::DL), Self::MOV_BLIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::BL), Self::MOV_AHIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::AH), Self::MOV_CHIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::CH), Self::MOV_DHIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::DH), Self::MOV_BHIb(byte) => write!(f, "mov {}, {byte:#04x}", Register::BH), Self::MOV_AXIv(word) => write!(f, "mov {}, {word:#04x}", Register::AX), Self::MOV_CXIv(word) => write!(f, "mov {}, {word:#04x}", Register::CX), Self::MOV_DXIv(word) => write!(f, "mov {}, {word:#04x}", Register::DX), Self::MOV_BXIv(word) => write!(f, "mov {}, {word:#04x}", Register::BX), Self::MOV_SPIv(word) => write!(f, "mov {}, {word:#04x}", Register::SP), Self::MOV_BPIv(word) => write!(f, "mov {}, {word:#04x}", Register::BP), Self::MOV_SIIv(word) => write!(f, "mov {}, {word:#04x}", Register::SI), Self::MOV_DIIv(word) => write!(f, "mov {}, {word:#04x}", Register::DI), Self::LEA(mem, reg) => write!(f, "lea {}, {}", reg, mem), Self::CBW => write!(f, "cbw"), Self::CWD => write!(f, "cwd"), Self::CALL_p(ptr) => write!(f, "call {ptr}"), Self::CALL_v(word) => write!(f, "call {word:#04x}"), Self::CALL_Mod(target) => write!(f, "call {target}"), Self::JMP_p(ptr) => write!(f, "jmp {ptr}"), Self::JMP_b(byte) => write!(f, "jmp {byte:#04x}"), Self::JMP_v(word) => write!(f, "jmp {word:#04x}"), Self::JMP_Mod(target) => write!(f, "jmp {target}"), Self::WAIT => write!(f, "wait"), Self::PUSHF => write!(f, "pushf"), Self::POPF => write!(f, "popf"), Self::SAHF => write!(f, "sahf"), Self::LAHF => write!(f, "lahf"), Self::MOVSB => write!(f, "movsb"), Self::MOVSW => write!(f, "movsw"), Self::CMPSB => write!(f, "cmpsb"), Self::CMPSW => write!(f, "cmpsw"), Self::STOSB => write!(f, "stosb"), Self::STOSW => write!(f, "stosw"), Self::LODSB => write!(f, "lodsb"), Self::LODSW => write!(f, "lodsw"), Self::SCASB => write!(f, "scasb"), Self::SCASW => write!(f, "scasw"), Self::RET_Iw(word) => write!(f, "ret {word:#04x}"), Self::RET => write!(f, "ret"), Self::RETF_Iw(word) => write!(f, "retf {word:#04x}"), Self::RETF => write!(f, "retf"), Self::IRET => write!(f, "iret"), Self::LES(target) => write!(f, "les {target}"), Self::LDS(target) => write!(f, "lds {target}"), Self::NOT(target) => write!(f, "not {target}"), Self::NEG(target) => write!(f, "neg {target}"), Self::MUL(target) => write!(f, "mul {target}"), Self::IMUL(target) => write!(f, "imul {target}"), Self::DIV(target) => write!(f, "mdiv {target}"), Self::IDIV(target) => write!(f, "idiv {target}"), Self::HLT => write!(f, "hlt"), Self::ROL_b(target, byte) => write!(f, "rol byte {target}, {byte:#04x}"), Self::ROR_b(target, byte) => write!(f, "ror byte {target}, {byte:#04x}"), Self::RCL_b(target, byte) => write!(f, "rcl byte {target}, {byte:#04x}"), Self::RCR_b(target, byte) => write!(f, "rcr byte {target}, {byte:#04x}"), Self::SHL_b(target, byte) => write!(f, "shl byte {target}, {byte:#04x}"), Self::SHR_b(target, byte) => write!(f, "shr byte {target}, {byte:#04x}"), Self::SAR_b(target, byte) => write!(f, "sar byte {target}, {byte:#04x}"), Self::ROL_fromReg(target, reg) => write!(f, "rol {target}, {reg}"), Self::ROR_fromReg(target, reg) => write!(f, "ror {target}, {reg}"), Self::RCL_fromReg(target, reg) => write!(f, "rcl {target}, {reg}"), Self::RCR_fromReg(target, reg) => write!(f, "rcr {target}, {reg}"), Self::SHL_fromReg(target, reg) => write!(f, "shl {target}, {reg}"), Self::SHR_fromReg(target, reg) => write!(f, "shr {target}, {reg}"), Self::SAR_fromReg(target, reg) => write!(f, "sar {target}, {reg}"), Self::IN_AL(byte) => write!(f, "in byte {}, {byte:#04x}", Register::AL), Self::IN_AX(byte) => write!(f, "in byte {}, {byte:#04x}", Register::AX), Self::IN_ALDX => write!(f, "in {}, {}", Register::AL, Register::DX), Self::IN_AXDX => write!(f, "in {}, {}", Register::AX, Register::DX), Self::OUT_AL(byte) => write!(f, "out byte {}, {byte:#04x}", Register::AL), Self::OUT_AX(byte) => write!(f, "out byte {}, {byte:#04x}", Register::AX), Self::OUT_ALDX => write!(f, "out {}, {}", Register::AL, Register::DX), Self::OUT_AXDX => write!(f, "out {}, {}", Register::AX, Register::DX), Self::INT(byte) => write!(f, "int {byte:#04x}"), Self::INTO => write!(f, "into"), Self::CLC => write!(f, "clc"), Self::STC => write!(f, "stc"), Self::CLI => write!(f, "cli"), Self::STI => write!(f, "sti"), Self::CLD => write!(f, "cld"), Self::STD => write!(f, "std"), Self::CMC => write!(f, "cmc"), Self::REPNZ => write!(f, "repnz"), Self::REPZ => write!(f, "repz"), Self::AAM(byte) => write!(f, "aam {byte:#04x}"), Self::AAD(byte) => write!(f, "aad {byte:#04x}"), Self::XLAT => write!(f, "xlat"), _ => write!(f, "??? ??, ??"), } } }