diff --git a/src/disassembler/parser.rs b/src/disassembler/parser.rs index 911d062..8122401 100644 --- a/src/disassembler/parser.rs +++ b/src/disassembler/parser.rs @@ -510,13 +510,13 @@ pub fn parse_instruction( let dest = u16::from_le_bytes([bytes[1], bytes[2]]); Ok(( IR::Ret { - dest: Some(Operand::LongImmediate(dest)), + src: Some(Operand::LongImmediate(dest)), }, 3, )) } // RET segment / intersegment - 0xC3 | 0xCB => Ok((IR::Ret { dest: None }, 1)), + 0xC3 | 0xCB => Ok((IR::Ret { src: None }, 1)), // LES 0xC4 => { let (dest, src, bytes_consumed) = parse_mod_reg_rm_bytes(&bytes[1..], true)?; diff --git a/src/disassembler/parser/parser_tests.rs b/src/disassembler/parser/parser_tests.rs index e514231..f2dd0f7 100644 --- a/src/disassembler/parser/parser_tests.rs +++ b/src/disassembler/parser/parser_tests.rs @@ -663,10 +663,10 @@ fn test_std() { #[test] fn test_ret() { // Within segment - assert_parse!([0xc3], IR::Ret { dest: None }); + assert_parse!([0xc3], IR::Ret { src: None }); // Intersegment - assert_parse!([0xcb], IR::Ret { dest: None }); + assert_parse!([0xcb], IR::Ret { src: None }); } #[test] diff --git a/src/interpreter/vm.rs b/src/interpreter/vm.rs index 28c2732..4b01d08 100644 --- a/src/interpreter/vm.rs +++ b/src/interpreter/vm.rs @@ -120,6 +120,9 @@ impl VmIrExecutable for VM { IR::Cmp { dest, src, byte: _ } => { self.cmp(dest, src); } + IR::Jmp { dest, short: _ } => { + self.jmp(dest); + } IR::Jnb { dest } => { self.jnb(dest); } @@ -129,15 +132,27 @@ impl VmIrExecutable for VM { IR::Je { dest } => { self.je(dest); } + IR::Jl { dest } => { + self.jl(dest); + } + IR::Jnl { dest } => { + self.jnl(dest); + } IR::Test { dest, src, byte: _ } => { self.test(dest, src); } IR::Push { src } => { self.push(src); } + IR::Pop { dest } => { + self.pop(dest); + } IR::Call { dest } => { self.call(dest); } + IR::Ret { src } => { + self.ret(src); + } IR::In { dest, src } => { self.in_(dest, src); } @@ -156,6 +171,9 @@ impl VmIrExecutable for VM { IR::Sub { dest, src } => { self.sub(dest, src); } + IR::Dec { dest } => { + self.dec(dest); + } _ => panic!("{}: Not implemented", ir), } } @@ -186,11 +204,12 @@ impl VmIrExecutable for VM { regs.push_str(&format!("{:04x} ", self.regs.get(reg))); } let mut flags = String::new(); - if self.flags.get(Flag::Parity) { - flags.push('P'); - } else { - flags.push('-'); - } + // if self.flags.get(Flag::Parity) { + // flags.push('P'); + // } else { + // flags.push('-'); + // } + flags.push('-'); // ? if self.flags.get(Flag::Sign) { flags.push('S'); } else { @@ -221,11 +240,11 @@ impl VmIrExecutable for VM { decoded_ir ); - self.execute(decoded_ir); - // Increment the instruction pointer (ip) appropriately self.ip += ir_len as u16; + self.execute(decoded_ir); + // Check cycle count cycle_count += 1; if cycle_count > 10000 { @@ -281,7 +300,11 @@ impl VM { trace!(";[{:04x}]{:04x}", ea, ev); ev } - Operand::Displacement(value) => self.ip.wrapping_add((*value).into()) as i16, + Operand::Displacement(value) => match value { + Displacement::Short(d) => *d as i16, + Displacement::Long(d) => *d, + }, + // DEBUG: `self.ip.wrapping_add((*value).into()) as i16``, if not this, then check disasm `call Displacement`, e.g. ir `e80500`, instead of `call Imm` } } diff --git a/src/interpreter/vm/opcodes.rs b/src/interpreter/vm/opcodes.rs index cd0c2c9..204d597 100644 --- a/src/interpreter/vm/opcodes.rs +++ b/src/interpreter/vm/opcodes.rs @@ -14,18 +14,24 @@ pub trait OpcodeExecutable { fn xor(&mut self, dest: Operand, src: Operand); fn lea(&mut self, dest: Operand, src: Operand); fn cmp(&mut self, dest: Operand, src: Operand); + fn jmp(&mut self, dest: Operand); fn jnb(&mut self, dest: Operand); fn jne(&mut self, dest: Operand); fn je(&mut self, dest: Operand); + fn jl(&mut self, dest: Operand); + fn jnl(&mut self, dest: Operand); fn test(&mut self, dest: Operand, src: Operand); fn push(&mut self, src: Operand); + fn pop(&mut self, dest: Operand); fn call(&mut self, dest: Operand); + fn ret(&mut self, src: Option); fn in_(&mut self, dest: Operand, src: Operand); fn loop_(&mut self, dest: Operand); fn loopz(&mut self, dest: Operand); fn loopnz(&mut self, dest: Operand); fn or(&mut self, dest: Operand, src: Operand); fn sub(&mut self, dest: Operand, src: Operand); + fn dec(&mut self, dest: Operand); } impl OpcodeExecutable for VM { @@ -61,6 +67,10 @@ impl OpcodeExecutable for VM { content_ea, content_len ); + // set AX to 0 + self.regs.set(Register::AX, 0); + // Return nb of bytes written + self.data.write_word(message_struct_ea + 2, content_len); let content = self.data.read_bytes(content_ea, content_len as usize); print!("{}", String::from_utf8_lossy(content)); @@ -73,16 +83,16 @@ impl OpcodeExecutable for VM { } fn add(&mut self, dest: Operand, src: Operand) { let src_value = self.read_value(&src); - let target_value = self.read_value(&dest); - let (result, overflow) = target_value.overflowing_add(src_value); + let dest_value = self.read_value(&dest); + let (result, overflow) = dest_value.overflowing_add(src_value); self.write_value(&dest, result as u16); self.flags.set(Flag::Overflow, overflow); - self.flags.set(Flag::Carry, result < src_value); + self.flags.set(Flag::Carry, result < dest_value); self.flags.set_szp(result); self.flags - .set(Flag::Aux, (target_value & 0xf) + (src_value & 0xf) > 0xf); + .set(Flag::Aux, (dest_value & 0xf) + (src_value & 0xf) > 0xf); } fn xor(&mut self, dest: Operand, src: Operand) { let src_value = self.read_value(&src); @@ -121,6 +131,9 @@ impl OpcodeExecutable for VM { self.flags .set(Flag::Aux, (dest_value & 0xf) < (src_value & 0xf)); } + fn jmp(&mut self, dest: Operand) { + self.ip = self.read_value(&dest) as u16; + } fn jnb(&mut self, dest: Operand) { if !self.flags.get(Flag::Carry) { self.ip = self.read_value(&dest) as u16; @@ -136,6 +149,16 @@ impl OpcodeExecutable for VM { self.ip = self.read_value(&dest) as u16; } } + fn jl(&mut self, dest: Operand) { + if self.flags.get(Flag::Sign) != self.flags.get(Flag::Overflow) { + self.ip = self.read_value(&dest) as u16; + } + } + fn jnl(&mut self, dest: Operand) { + if self.flags.get(Flag::Sign) == self.flags.get(Flag::Overflow) { + self.ip = self.read_value(&dest) as u16; + } + } fn test(&mut self, dest: Operand, src: Operand) { let src_value = self.read_value(&src); let dest_value = self.read_value(&dest); @@ -150,13 +173,13 @@ impl OpcodeExecutable for VM { fn sub(&mut self, dest: Operand, src: Operand) { let src_value = self.read_value(&src); let dest_value = self.read_value(&dest); - let result = dest_value & src_value; + let (result, overflow) = dest_value.overflowing_sub(src_value); self.write_value(&dest, result as u16); - // Clear - self.flags.clear(Flag::Carry); - self.flags.clear(Flag::Overflow); + // OF, CF + self.flags.set(Flag::Overflow, overflow); + self.flags.set(Flag::Carry, dest_value > src_value); // SF, ZF, PF self.flags.set_szp(result); } @@ -164,7 +187,16 @@ impl OpcodeExecutable for VM { let value = self.read_value(&src) as u16; let ea = self.regs.get(Register::SP).wrapping_sub(2) as u16; self.data.write_word(ea, value as u16); - // todo + self.regs.set(Register::SP, ea); + } + fn pop(&mut self, dest: Operand) { + let ea = self.regs.get(Register::SP) as u16; + let value = self.data.read_word(ea); + self.regs.set(Register::SP, ea.wrapping_add(2)); + match dest { + Operand::Register(reg) => self.regs.set(reg, value), + _ => unimplemented!(), + } } fn call(&mut self, dest: Operand) { let value = self.read_value(&dest) as u16; @@ -173,6 +205,20 @@ impl OpcodeExecutable for VM { self.regs.set(Register::SP, ea); self.ip = value; } + fn ret(&mut self, src: Option) { + let ea = self.regs.get(Register::SP) as u16; + let value = self.data.read_word(ea); + let released_bytes = match src { + Some(src) => match src { + Operand::Immediate(value) => value as u16, + _ => panic!("Invalid operand"), + }, + None => 0, + }; + self.regs + .set(Register::SP, ea.wrapping_add(2 + released_bytes)); + self.ip = value; + } fn in_(&mut self, dest: Operand, src: Operand) { let _port = self.read_value(&src) as u16; let value = 0x42; @@ -218,4 +264,15 @@ impl OpcodeExecutable for VM { // SF, ZF and PF based on result self.flags.set_szp(result); } + fn dec(&mut self, dest: Operand) { + let dest_value = self.read_value(&dest); + let result = dest_value.wrapping_sub(1); + + self.write_value(&dest, result as u16); + + // Clear + self.flags.clear(Flag::Overflow); + // SF, ZF and PF based on result + self.flags.set_szp(result); + } } diff --git a/src/main.rs b/src/main.rs index 8a018ff..b983115 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,8 +8,8 @@ fn main() { .format_timestamp(None) .format_module_path(false) .format_target(false) - // .filter_level(log::LevelFilter::Trace) - .filter_level(log::LevelFilter::Info) + .filter_level(log::LevelFilter::Trace) + // .filter_level(log::LevelFilter::Info) .init(); let args: Vec = std::env::args().collect(); diff --git a/src/x86/instruction.rs b/src/x86/instruction.rs index 03e27cc..6307960 100644 --- a/src/x86/instruction.rs +++ b/src/x86/instruction.rs @@ -168,7 +168,7 @@ pub enum IR { short: bool, }, Ret { - dest: Option, + src: Option, }, Je { dest: Operand, @@ -405,8 +405,8 @@ impl std::fmt::Display for IR { IR::Jmp { dest, short } => { write!(f, "jmp {}{}", if *short { "short " } else { "" }, dest) } - IR::Ret { dest } => match dest { - Some(dest) => write!(f, "ret {}", dest), + IR::Ret { src } => match src { + Some(src) => write!(f, "ret {}", src), None => write!(f, "ret"), }, IR::Je { dest } => write!(f, "je {}", dest),