use crate::*;
const DATA_ADDR: u64 = 0x7000;
#[test]
fn test_enter_basic_no_nesting() {
let code = [
0xc8, 0x00, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000 - 8, "RSP decremented by 8 (pushed RBP)");
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP = RSP after PUSH");
let saved_rbp = emu.maps.read_qword(0x1000 - 8).unwrap();
assert_eq!(saved_rbp, 0x2000, "Old RBP saved on stack");
}
#[test]
fn test_enter_allocate_8_bytes() {
let code = [
0xc8, 0x08, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set after pushing");
assert_eq!(emu.regs().rsp, 0x1000 - 16, "RSP = RBP - 8 (allocated space)");
let saved_rbp = emu.maps.read_qword(0x1000 - 8).unwrap();
assert_eq!(saved_rbp, 0x2000, "Old RBP saved");
}
#[test]
fn test_enter_allocate_16_bytes() {
let code = [
0xc8, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x1000 - 24, "RSP = RBP - 16");
let saved_rbp = emu.maps.read_qword(emu.regs().rbp).unwrap();
assert_eq!(saved_rbp, 0x2000, "Old RBP saved");
}
#[test]
fn test_enter_allocate_32_bytes() {
let code = [
0xc8, 0x20, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x1000 - 40, "RSP = RBP - 32");
}
#[test]
fn test_enter_allocate_64_bytes() {
let code = [
0xc8, 0x40, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x1000 - 72, "RSP = RBP - 64");
}
#[test]
fn test_enter_allocate_128_bytes() {
let code = [
0xc8, 0x80, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x1000 - 136, "RSP = RBP - 128");
}
#[test]
fn test_enter_allocate_256_bytes() {
let code = [
0xc8, 0x00, 0x01, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x1000 - 264, "RSP = RBP - 256");
}
#[test]
fn test_enter_allocate_1024_bytes() {
let code = [
0xc8, 0x00, 0x04, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x2000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x2000 - 1032, "RSP = RBP - 1024");
}
#[test]
fn test_enter_allocate_max_16bit() {
let code = [
0xc8, 0xff, 0xff, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x20000-(0x20000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x20000;
emu.regs_mut().rbp = 0x30000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x20000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x20000 - 8 - 65535, "RSP = RBP - 65535");
}
#[test]
fn test_enter_nesting_level_1_no_alloc() {
let code = [
0xc8, 0x00, 0x00, 0x01, 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, 0x1000 - 16, "RSP decremented by 16");
let first_push = emu.maps.read_qword(0x1000 - 8).unwrap();
assert_eq!(first_push, 0x2000, "First push is old RBP");
}
#[test]
fn test_enter_nesting_level_1_with_alloc() {
let code = [
0xc8, 0x10, 0x00, 0x01, 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, 0x1000 - 32, "RSP decremented by 32");
let saved_rbp = emu.maps.read_qword(0x1000 - 8).unwrap();
assert_eq!(saved_rbp, 0x2000, "Old RBP saved");
}
#[test]
fn test_enter_nesting_level_2() {
let code = [
0xc8, 0x00, 0x00, 0x02, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.maps.write_qword(0x3000, 0x4000);
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000 - 24, "RSP decremented by 24");
}
#[test]
fn test_enter_nesting_level_3() {
let code = [
0xc8, 0x08, 0x00, 0x03, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.maps.write_qword(0x3000, 0x4000);
emu.maps.write_qword(0x4000, 0x5000);
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000 - 40, "RSP decremented by 40");
}
#[test]
fn test_enter_nesting_level_4_with_alloc() {
let code = [
0xc8, 0x20, 0x00, 0x04, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000 - 72, "RSP decremented by 72");
}
#[test]
fn test_enter_nesting_level_5() {
let code = [
0xc8, 0x00, 0x00, 0x05, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x3000-(0x3000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x3000;
emu.regs_mut().rbp = 0x4000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x3000 - 48, "RSP decremented by 48");
}
#[test]
fn test_enter_preserves_other_registers() {
let code = [
0x48, 0xc7, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc3, 0x22, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc1, 0x33, 0x00, 0x00, 0x00, 0xc8, 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().rax, 0x11, "RAX unchanged");
assert_eq!(emu.regs().rbx, 0x22, "RBX unchanged");
assert_eq!(emu.regs().rcx, 0x33, "RCX unchanged");
}
#[test]
fn test_enter_preserves_flags() {
let code = [
0xf9, 0xc8, 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_ne!(emu.flags().dump() & 0x01, 0, "CF should be preserved");
}
#[test]
fn test_enter_leave_roundtrip() {
let code = [
0xc8, 0x10, 0x00, 0x00, 0xc9, 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, 0x1000, "RSP restored");
assert_eq!(emu.regs().rbp, 0x2000, "RBP restored");
}
#[test]
fn test_enter_leave_nested() {
let code = [
0xc8, 0x08, 0x00, 0x00, 0xc8, 0x10, 0x00, 0x00, 0xc9, 0xc9, 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, 0x1000, "RSP restored after nested ENTER/LEAVE");
assert_eq!(emu.regs().rbp, 0x2000, "RBP restored after nested ENTER/LEAVE");
}
#[test]
fn test_enter_high_stack_address() {
let code = [
0xc8, 0x20, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x100000-(0x100000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x100000;
emu.regs_mut().rbp = 0x200000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x100000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x100000 - 40, "RSP decremented");
let saved_rbp = emu.maps.read_qword(emu.regs().rbp).unwrap();
assert_eq!(saved_rbp, 0x200000, "Old RBP saved");
}
#[test]
fn test_enter_low_stack_address() {
let code = [
0xc8, 0x10, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x100-(0x100 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x100;
emu.regs_mut().rbp = 0x200;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x100 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x100 - 24, "RSP decremented");
let saved_rbp = emu.maps.read_qword(emu.regs().rbp).unwrap();
assert_eq!(saved_rbp, 0x200, "Old RBP saved");
}
#[test]
fn test_enter_multiple_calls() {
let code = [
0xc8, 0x08, 0x00, 0x00, 0xc8, 0x10, 0x00, 0x00, 0xc8, 0x20, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000 - 80, "RSP after three ENTERs");
}
#[test]
fn test_enter_with_odd_allocation() {
let code = [
0xc8, 0x11, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x1000 - 25, "RSP = RBP - 17");
}
#[test]
fn test_enter_allocation_alignment() {
let code = [
0xc8, 0x18, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP set");
assert_eq!(emu.regs().rsp, 0x1000 - 32, "RSP = RBP - 24");
}
#[test]
fn test_enter_frame_pointer_chain() {
let code = [
0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000 - 24, "Three frames created");
let frame3_rbp = emu.regs().rbp;
let frame2_rbp = emu.maps.read_qword(frame3_rbp).unwrap();
let frame1_rbp = emu.maps.read_qword(frame2_rbp).unwrap();
let original_rbp = emu.maps.read_qword(frame1_rbp).unwrap();
assert_eq!(original_rbp, 0x3000, "Original RBP at end of chain");
}
#[test]
fn test_enter_small_local_vars() {
let code = [
0xc8, 0x18, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "Frame pointer set");
assert_eq!(emu.regs().rsp, 0x1000 - 32, "Space for 3 local vars");
}
#[test]
fn test_enter_large_local_array() {
let code = [
0xc8, 0x00, 0x02, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x2000 - 8, "Frame pointer set");
assert_eq!(emu.regs().rsp, 0x2000 - 520, "Space for 512-byte buffer");
}
#[test]
fn test_enter_no_locals() {
let code = [
0xc8, 0x00, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "Frame pointer set");
assert_eq!(emu.regs().rsp, 0x1000 - 8, "No local space allocated");
}
#[test]
fn test_enter_then_push() {
let code = [
0xc8, 0x10, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x42, 0x00, 0x00, 0x00, 0x50, 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, 0x1000 - 32, "RSP after ENTER and PUSH");
let pushed_val = emu.maps.read_qword(emu.regs().rsp).unwrap();
assert_eq!(pushed_val, 0x42, "Pushed value on stack");
}
#[test]
fn test_enter_then_mov_to_local() {
let code = [
0xc8, 0x10, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0xaa, 0x00, 0x00, 0x00, 0x48, 0x89, 0x45, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
let local_var = emu.maps.read_qword(emu.regs().rbp - 8).unwrap();
assert_eq!(local_var, 0xAA, "Local variable set correctly");
}
#[test]
fn test_enter_with_parameter_access() {
let code = [
0x48, 0xc7, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x50, 0xc8, 0x08, 0x00, 0x00, 0x48, 0x8b, 0x5d, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_ne!(emu.regs().rbx, 0, "Parameter accessed through RBP");
}
#[test]
fn test_enter_nesting_level_10() {
let code = [
0xc8, 0x00, 0x00, 0x0a, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x3000-(0x3000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x3000;
emu.regs_mut().rbp = 0x4000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x3000 - 88, "RSP with nesting level 10");
}
#[test]
fn test_enter_nesting_level_16() {
let code = [
0xc8, 0x00, 0x00, 0x10, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x4000-(0x4000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x4000;
emu.regs_mut().rbp = 0x5000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x4000 - 136, "RSP with nesting level 16");
}
#[test]
fn test_enter_nesting_level_31() {
let code = [
0xc8, 0x00, 0x00, 0x1f, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x5000-(0x5000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x5000;
emu.regs_mut().rbp = 0x6000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x5000 - 256, "RSP with max nesting level 31");
}
#[test]
fn test_enter_zero_allocation_zero_nesting() {
let code = [
0xc8, 0x00, 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.regs_mut().rbp = 0x2000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x1000 - 8, "Only RBP pushed");
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP = RSP");
}
#[test]
fn test_enter_with_same_rbp_rsp() {
let code = [
0xc8, 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.regs_mut().rbp = 0x1000; emu.run(None).unwrap();
assert_eq!(emu.regs().rbp, 0x1000 - 8, "RBP updated");
let saved_rbp = emu.maps.read_qword(emu.regs().rbp).unwrap();
assert_eq!(saved_rbp, 0x1000, "Old RBP (which was RSP) saved");
}
#[test]
fn test_enter_consecutive_same_size() {
let code = [
0xc8, 0x20, 0x00, 0x00, 0xc8, 0x20, 0x00, 0x00, 0xc8, 0x20, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x2000-(0x2000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x2000;
emu.regs_mut().rbp = 0x3000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x2000 - 120, "Three identical ENTERs");
}
#[test]
fn test_enter_mixed_sizes() {
let code = [
0xc8, 0x08, 0x00, 0x00, 0xc8, 0x10, 0x00, 0x00, 0xc8, 0x20, 0x00, 0x00, 0xc8, 0x40, 0x00, 0x00, 0xf4, ];
let mut emu = emu64();
emu.load_code_bytes(&code);
emu.maps.create_map("stack_test", 0x3000-(0x3000 / 2), 0x1000, crate::maps::mem64::Permission::READ_WRITE_EXECUTE).unwrap();
emu.regs_mut().rsp = 0x3000;
emu.regs_mut().rbp = 0x4000;
emu.run(None).unwrap();
assert_eq!(emu.regs().rsp, 0x3000 - 152, "Mixed size allocations");
}