use crate::*;
const DATA_ADDR: u64 = 0x7000;
#[test]
fn test_add_rsp_8() {
let code = [
0x48, 0x83, 0xc4, 0x08, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1008, "RSP incremented by 8");
}
#[test]
fn test_add_rsp_16() {
let code = [
0x48, 0x83, 0xc4, 0x10, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1010, "RSP incremented by 16");
}
#[test]
fn test_add_rsp_32() {
let code = [
0x48, 0x83, 0xc4, 0x20, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1020, "RSP incremented by 32");
}
#[test]
fn test_add_rsp_large() {
let code = [
0x48, 0x81, 0xc4, 0x00, 0x10, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000, "RSP incremented by 4096");
}
#[test]
fn test_add_rsp_cleanup_params() {
let code = [
0x6a, 0x01, 0x6a, 0x02, 0x6a, 0x03, 0x48, 0x83, 0xc4, 0x18, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "Stack cleaned up after parameter push");
}
#[test]
fn test_sub_rsp_8() {
let code = [
0x48, 0x83, 0xec, 0x08, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x0FF8, "RSP decremented by 8");
}
#[test]
fn test_sub_rsp_16() {
let code = [
0x48, 0x83, 0xec, 0x10, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x0FF0, "RSP decremented by 16");
}
#[test]
fn test_sub_rsp_32() {
let code = [
0x48, 0x83, 0xec, 0x20, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x0FE0, "RSP decremented by 32");
}
#[test]
fn test_sub_rsp_large_frame() {
let code = [
0x48, 0x81, 0xec, 0x00, 0x10, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x10000-(0x10000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x10000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0xF000, "Large stack frame allocated");
}
#[test]
fn test_sub_rsp_for_locals() {
let code = [
0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x20, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000 - 40, "Frame + locals allocated");
}
#[test]
fn test_mov_rsp_rax() {
let code = [
0x48, 0x89, 0xc4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rax = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000, "RSP set from RAX");
}
#[test]
fn test_mov_rsp_rbx() {
let code = [
0x48, 0x89, 0xdc, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rbx = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x3000, "RSP set from RBX");
}
#[test]
fn test_mov_rsp_rbp() {
let code = [
0x48, 0x89, 0xec, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000, "RSP set from RBP (like LEAVE part 1)");
}
#[test]
fn test_mov_rsp_r8() {
let code = [
0x4c, 0x89, 0xc4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().r8 = 0x4000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x4000, "RSP set from R8");
}
#[test]
fn test_mov_rax_rsp() {
let code = [
0x48, 0x89, 0xe0, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x1000, "RAX gets RSP value");
assert_eq!(emu.regs().rsp, 0x1000, "RSP unchanged");
}
#[test]
fn test_mov_rbx_rsp() {
let code = [
0x48, 0x89, 0xe3, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbx, 0x1000, "RBX gets RSP value");
}
#[test]
fn test_mov_rbp_rsp() {
let code = [
0x48, 0x89, 0xe5, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000, "RBP gets RSP value (prologue pattern)");
}
#[test]
fn test_save_restore_rsp() {
let code = [
0x48, 0x89, 0xe0, 0x48, 0x83, 0xec, 0x20, 0x48, 0x89, 0xc4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "RSP saved and restored");
}
#[test]
fn test_lea_rsp_rsp_plus_8() {
let code = [
0x48, 0x8d, 0x64, 0x24, 0x08, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1008, "RSP adjusted by LEA +8");
}
#[test]
fn test_lea_rsp_rsp_minus_8() {
let code = [
0x48, 0x8d, 0x64, 0x24, 0xf8, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x0FF8, "RSP adjusted by LEA -8");
}
#[test]
fn test_lea_rsp_rsp_plus_16() {
let code = [
0x48, 0x8d, 0x64, 0x24, 0x10, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1010, "RSP adjusted by LEA +16");
}
#[test]
fn test_lea_rsp_rbp_minus_offset() {
let code = [
0x48, 0x8d, 0x65, 0xf0, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1FF0, "RSP set via LEA from RBP");
}
#[test]
fn test_inc_rsp() {
let code = [
0x48, 0xff, 0xc4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1001, "RSP incremented by 1");
}
#[test]
fn test_dec_rsp() {
let code = [
0x48, 0xff, 0xcc, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x0FFF, "RSP decremented by 1");
}
#[test]
fn test_multiple_inc_rsp() {
let code = [
0x48, 0xff, 0xc4, 0x48, 0xff, 0xc4, 0x48, 0xff, 0xc4, 0x48, 0xff, 0xc4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1004, "RSP incremented 4 times");
}
#[test]
fn test_xchg_rsp_rax() {
let code = [
0x48, 0x94, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rax = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000, "RSP gets RAX value");
assert_eq!(emu.regs().rax, 0x1000, "RAX gets old RSP value");
}
#[test]
fn test_xchg_rsp_rbx() {
let code = [
0x48, 0x87, 0xdc, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rbx = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x3000, "RSP gets RBX value");
assert_eq!(emu.regs().rbx, 0x1000, "RBX gets old RSP value");
}
#[test]
fn test_rsp_alloc_dealloc_cycle() {
let code = [
0x48, 0x83, 0xec, 0x20, 0x48, 0x83, 0xc4, 0x20, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "RSP restored after alloc/dealloc");
}
#[test]
fn test_rsp_save_alloc_restore() {
let code = [
0x48, 0x89, 0xe3, 0x48, 0x83, 0xec, 0x40, 0x48, 0x89, 0xdc, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "RSP fully restored");
}
#[test]
fn test_rsp_with_stack_operations() {
let code = [
0x48, 0x83, 0xec, 0x10, 0x48, 0xc7, 0x04, 0x24, 0x42, 0x00, 0x00, 0x00, 0x48, 0x83, 0xc4, 0x10, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "RSP balanced");
let val = emu.maps.read_qword(0x0FF0).unwrap();
assert_eq!(val, 0x42, "Value written to allocated space");
}
#[test]
fn test_rsp_lea_cleanup() {
let code = [
0x6a, 0x01, 0x6a, 0x02, 0x6a, 0x03, 0x48, 0x8d, 0x64, 0x24, 0x18, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "Stack cleaned up via LEA");
}
#[test]
fn test_add_rsp_rax() {
let code = [
0x48, 0x01, 0xc4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rax = 0x100;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1100, "RSP += RAX");
}
#[test]
fn test_sub_rsp_rbx() {
let code = [
0x48, 0x29, 0xdc, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rbx = 0x50;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x0FB0, "RSP -= RBX");
}
#[test]
fn test_and_rsp_align() {
let code = [
0x48, 0x83, 0xe4, 0xf0, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1008-(0x1008 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1008;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "RSP aligned to 16 bytes");
}
#[test]
fn test_mov_rsp_from_memory() {
let code = [
0x48, 0x8b, 0x20, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.regs_mut().rax = DATA_ADDR;
emu.maps.write_qword(DATA_ADDR, 0x2000);
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000, "RSP loaded from memory");
}
#[test]
fn test_mov_memory_from_rsp() {
let code = [
0x48, 0x89, 0x20, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1234-(0x1234 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1234;
emu.regs_mut().rax = DATA_ADDR;
emu.run(None).unwrap();
let val = emu.maps.read_qword(DATA_ADDR).unwrap();
assert_eq!(val, 0x1234, "RSP stored to memory");
}
#[test]
fn test_rsp_zero() {
let code = [
0x48, 0x31, 0xe4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0, "RSP can be zeroed");
}
#[test]
fn test_rsp_max_value() {
let code = [
0x48, 0xc7, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0xFFFFFFFFFFFFFFFF, "RSP can be set to max value");
}
#[test]
fn test_rsp_wraparound_add() {
let code = [
0x48, 0x83, 0xc4, 0x10, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0xFFFFFFFFFFFFFFF0-(0xFFFFFFFFFFFFFFF0 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0xFFFFFFFFFFFFFFF0;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0, "RSP wraps around on overflow");
}
#[test]
fn test_rsp_complex_calculation() {
let code = [
0x48, 0x89, 0xe0, 0x48, 0x83, 0xec, 0x20, 0x48, 0x01, 0xc4, 0x48, 0x29, 0xc4, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x0FE0, "Complex RSP calculation");
}
#[test]
fn test_rsp_in_loop_simulation() {
let code = [
0x48, 0x83, 0xec, 0x08, 0x48, 0x83, 0xc4, 0x08, 0x48, 0x83, 0xec, 0x08, 0x48, 0x83, 0xc4, 0x08, 0x48, 0x83, 0xec, 0x08, 0x48, 0x83, 0xc4, 0x08, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x1000-(0x1000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x1000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000, "RSP balanced after loop simulation");
}