Skip to content
This repository has been archived by the owner on Aug 30, 2024. It is now read-only.

Commit

Permalink
feat: 1.c.out
Browse files Browse the repository at this point in the history
  • Loading branch information
julio4 committed Jul 15, 2024
1 parent a354535 commit 1398328
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/disassembler/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
4 changes: 2 additions & 2 deletions src/disassembler/parser/parser_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
39 changes: 31 additions & 8 deletions src/interpreter/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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),
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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`
}
}

Expand Down
75 changes: 66 additions & 9 deletions src/interpreter/vm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Operand>);
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 {
Expand Down Expand Up @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -150,21 +173,30 @@ 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);
}
fn push(&mut self, src: Operand) {
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;
Expand All @@ -173,6 +205,20 @@ impl OpcodeExecutable for VM {
self.regs.set(Register::SP, ea);
self.ip = value;
}
fn ret(&mut self, src: Option<Operand>) {
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;
Expand Down Expand Up @@ -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);
}
}
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> = std::env::args().collect();
Expand Down
6 changes: 3 additions & 3 deletions src/x86/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ pub enum IR {
short: bool,
},
Ret {
dest: Option<Operand>,
src: Option<Operand>,
},
Je {
dest: Operand,
Expand Down Expand Up @@ -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),
Expand Down

0 comments on commit 1398328

Please sign in to comment.