Skip to content

Commit 0593101

Browse files
committed
cmpxchg_tests
1 parent 561d7d1 commit 0593101

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use crate::tests::helpers;
2+
use crate::*;
3+
use crate::maps::mem64::Permission;
4+
5+
#[test]
6+
pub fn test_cmpxchg8b_equal() {
7+
helpers::setup();
8+
let mut emu = emu32();
9+
10+
// Code: cmpxchg8b [0x1000]
11+
// 0F C7 0D 00 10 00 00 (ModRM: 00 001 101 -> disp32)
12+
// But wait, 32-bit addressing.
13+
// Let's use a simpler addressing mode or ensure we map 0x1000.
14+
// 0F C7 0D 00 10 00 00 -> cmpxchg8b [0x1000]
15+
let code: [u8; 7] = [0x0f, 0xc7, 0x0d, 0x00, 0x10, 0x00, 0x00];
16+
17+
// Map data at 0x1000
18+
emu.maps.create_map("data", 0x1000, 0x1000, Permission::READ_WRITE).expect("failed to map data");
19+
20+
// Setup memory: [0x1000] = 0x1122334455667788
21+
let mem_val: u64 = 0x1122334455667788;
22+
emu.maps.write_qword(0x1000, mem_val);
23+
24+
// Setup EDX:EAX = 0x1122334455667788
25+
emu.regs_mut().set_edx(0x11223344);
26+
emu.regs_mut().set_eax(0x55667788);
27+
28+
// Setup ECX:EBX = 0xAABBCCDDEEFF0011
29+
emu.regs_mut().set_ecx(0xAABBCCDD);
30+
emu.regs_mut().set_ebx(0xEEFF0011);
31+
32+
emu.load_code_bytes(&code);
33+
emu.step();
34+
35+
// Check ZF = 1
36+
assert_eq!(emu.flags().f_zf, true, "ZF should be set");
37+
38+
// Check memory = ECX:EBX
39+
let new_mem_val = emu.maps.read_qword(0x1000).expect("failed to read memory");
40+
assert_eq!(new_mem_val, 0xAABBCCDDEEFF0011, "Memory should be updated");
41+
}
42+
43+
#[test]
44+
pub fn test_cmpxchg8b_not_equal() {
45+
helpers::setup();
46+
let mut emu = emu32();
47+
48+
// Code: cmpxchg8b [0x1000]
49+
let code: [u8; 7] = [0x0f, 0xc7, 0x0d, 0x00, 0x10, 0x00, 0x00];
50+
51+
emu.maps.create_map("data", 0x1000, 0x1000, Permission::READ_WRITE).expect("failed to map data");
52+
53+
// Setup memory: [0x1000] = 0x9988776655443322
54+
let mem_val: u64 = 0x9988776655443322;
55+
emu.maps.write_qword(0x1000, mem_val);
56+
57+
// Setup EDX:EAX = 0x1122334455667788 (Different)
58+
emu.regs_mut().set_edx(0x11223344);
59+
emu.regs_mut().set_eax(0x55667788);
60+
61+
emu.load_code_bytes(&code);
62+
emu.step();
63+
64+
// Check ZF = 0
65+
assert_eq!(emu.flags().f_zf, false, "ZF should be clear");
66+
67+
// Check EDX:EAX = Memory
68+
assert_eq!(emu.regs().get_edx(), 0x99887766, "EDX should be loaded from memory high");
69+
assert_eq!(emu.regs().get_eax(), 0x55443322, "EAX should be loaded from memory low");
70+
71+
// Check memory unchanged
72+
let check_mem = emu.maps.read_qword(0x1000).expect("failed to read memory");
73+
assert_eq!(check_mem, 0x9988776655443322, "Memory should be unchanged");
74+
}
75+
76+
#[test]
77+
pub fn test_cmpxchg16b_equal() {
78+
helpers::setup();
79+
let mut emu = emu64();
80+
81+
// Code: cmpxchg16b [0x1000]
82+
// REX.W + 0F C7 /1
83+
// 48 0F C7 0C 25 00 10 00 00 (ModRM: 00 001 100 -> SIB, SIB: 00 100 101 -> disp32)
84+
// Or simpler: 48 0F C7 0D 00 10 00 00 (RIP-relative? No, absolute in 64-bit is tricky, usually RIP-relative)
85+
// Let's use register indirect: cmpxchg16b [rsi]
86+
// RSI = 0x1000
87+
// 48 0F C7 0E (ModRM: 00 001 110 -> [RSI])
88+
let code: [u8; 4] = [0x48, 0x0f, 0xc7, 0x0e];
89+
90+
emu.maps.create_map("data", 0x1000, 0x1000, Permission::READ_WRITE).expect("failed to map data");
91+
92+
// Setup RSI
93+
emu.regs_mut().rsi = 0x1000;
94+
95+
// Setup memory: [0x1000] = 0x112233445566778899AABBCCDDEEFF00
96+
let mem_val: u128 = 0x112233445566778899AABBCCDDEEFF00;
97+
emu.maps.write_bytes(0x1000, mem_val.to_le_bytes().to_vec());
98+
99+
// Setup RDX:RAX = 0x112233445566778899AABBCCDDEEFF00
100+
emu.regs_mut().rdx = 0x1122334455667788;
101+
emu.regs_mut().rax = 0x99AABBCCDDEEFF00;
102+
103+
// Setup RCX:RBX = 0xFFEEDDCCBBAA99887766554433221100
104+
emu.regs_mut().rcx = 0xFFEEDDCCBBAA9988;
105+
emu.regs_mut().rbx = 0x7766554433221100;
106+
107+
emu.load_code_bytes(&code);
108+
emu.step();
109+
110+
// Check ZF = 1
111+
assert_eq!(emu.flags().f_zf, true, "ZF should be set");
112+
113+
// Check memory = RCX:RBX
114+
let new_mem_val = emu.maps.read_128bits_le(0x1000).expect("failed to read memory");
115+
assert_eq!(new_mem_val, 0xFFEEDDCCBBAA99887766554433221100, "Memory should be updated");
116+
}
117+
118+
#[test]
119+
pub fn test_cmpxchg16b_not_equal() {
120+
helpers::setup();
121+
let mut emu = emu64();
122+
123+
// Code: cmpxchg16b [rsi]
124+
let code: [u8; 4] = [0x48, 0x0f, 0xc7, 0x0e];
125+
126+
emu.maps.create_map("data", 0x1000, 0x1000, Permission::READ_WRITE).expect("failed to map data");
127+
128+
// Setup RSI
129+
emu.regs_mut().rsi = 0x1000;
130+
131+
// Setup memory: [0x1000] = 0x1234567890ABCDEF1234567890ABCDEF
132+
let mem_val: u128 = 0x1234567890ABCDEF1234567890ABCDEF;
133+
emu.maps.write_bytes(0x1000, mem_val.to_le_bytes().to_vec());
134+
135+
// Setup RDX:RAX = Different
136+
emu.regs_mut().rdx = 0x0;
137+
emu.regs_mut().rax = 0x0;
138+
139+
emu.load_code_bytes(&code);
140+
emu.step();
141+
142+
// Check ZF = 0
143+
assert_eq!(emu.flags().f_zf, false, "ZF should be clear");
144+
145+
// Check RDX:RAX = Memory
146+
assert_eq!(emu.regs().rdx, 0x1234567890ABCDEF, "RDX should be loaded from memory high");
147+
assert_eq!(emu.regs().rax, 0x1234567890ABCDEF, "RAX should be loaded from memory low");
148+
149+
// Check memory unchanged
150+
let check_mem = emu.maps.read_128bits_le(0x1000).expect("failed to read memory");
151+
assert_eq!(check_mem, 0x1234567890ABCDEF1234567890ABCDEF, "Memory should be unchanged");
152+
}

crates/libmwemu/src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ mod call32;
4949
mod call64;
5050
mod linux_call64;
5151
mod sc64win_strgen;
52+
mod cmpxchg_tests;

0 commit comments

Comments
 (0)