use crate::maps::mem64::Permission;
use crate::tests::helpers;
use crate::*;
use std::convert::TryInto;
#[test]
fn test_sse_floats() {
helpers::setup();
let mut emu = emu64();
let code_addr = 0x400000;
emu.maps
.create_map("code", code_addr, 0x1000, Permission::READ_WRITE_EXECUTE);
let mut code: Vec<u8> = vec![
0x0f, 0x28, 0x05, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x28, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x0f,
0x58, 0xc1, 0xc3,
];
while code.len() < 0x10 + 7 {
code.push(0x90);
}
let data1_addr = code_addr + 0x40;
let data2_addr = code_addr + 0x50;
let mut code_builder: Vec<u8> = Vec::new();
code_builder.extend_from_slice(&[0x48, 0xb8]);
code_builder.extend_from_slice(&data1_addr.to_le_bytes());
code_builder.extend_from_slice(&[0xf3, 0x0f, 0x6f, 0x00]);
code_builder.extend_from_slice(&[0x48, 0xb8]);
code_builder.extend_from_slice(&data2_addr.to_le_bytes());
code_builder.extend_from_slice(&[0xf3, 0x0f, 0x6f, 0x08]);
code_builder.push(0xc3);
emu.maps.write_bytes(code_addr, &code_builder);
let floats1: Vec<f32> = vec![1.0, 2.0, 3.0, 4.0];
let bytes1: Vec<u8> = floats1.iter().flat_map(|f| f.to_le_bytes()).collect();
emu.maps.write_bytes(data1_addr, &bytes1);
let floats2: Vec<f32> = vec![0.5, 0.5, 0.5, 0.5];
let bytes2: Vec<u8> = floats2.iter().flat_map(|f| f.to_le_bytes()).collect();
emu.maps.write_bytes(data2_addr, &bytes2);
emu.regs_mut().rip = code_addr;
emu.regs_mut().rsp = 0x7000; emu.maps
.create_map("stack", 0x0, 0x10000, Permission::READ_WRITE);
let ret_addr = 0x1000;
emu.maps.create_map(
"ret_guard",
ret_addr,
0x1000,
Permission::READ_WRITE_EXECUTE,
);
emu.maps.write_byte(ret_addr, 0x90);
emu.stack_push64(ret_addr);
let _ = emu.run(Some(ret_addr)).unwrap();
let xmm0 = emu.regs().xmm0;
let result_bytes = xmm0.to_le_bytes();
let f1 = f32::from_le_bytes(result_bytes[0..4].try_into().unwrap());
let f2 = f32::from_le_bytes(result_bytes[4..8].try_into().unwrap());
let f3 = f32::from_le_bytes(result_bytes[8..12].try_into().unwrap());
let f4 = f32::from_le_bytes(result_bytes[12..16].try_into().unwrap());
assert_eq!(f1, 1.0);
assert_eq!(f2, 2.0);
assert_eq!(f3, 3.0);
assert_eq!(f4, 4.0);
}
#[test]
fn test_sse_integers() {
helpers::setup();
let mut emu = emu64();
let code_addr = 0x400000;
emu.maps
.create_map("code", code_addr, 0x1000, Permission::READ_WRITE_EXECUTE);
let data1_addr = code_addr + 0x100;
let data2_addr = code_addr + 0x110;
let mut code_builder: Vec<u8> = Vec::new();
code_builder.extend_from_slice(&[0x48, 0xb8]);
code_builder.extend_from_slice(&data1_addr.to_le_bytes());
code_builder.extend_from_slice(&[0xf3, 0x0f, 0x6f, 0x00]);
code_builder.extend_from_slice(&[0x48, 0xb8]);
code_builder.extend_from_slice(&data2_addr.to_le_bytes());
code_builder.extend_from_slice(&[0xf3, 0x0f, 0x6f, 0x08]);
code_builder.push(0xc3);
emu.maps.write_bytes(code_addr, &code_builder);
let ints1: Vec<u32> = vec![10, 20, 30, 40];
let bytes1: Vec<u8> = ints1.iter().flat_map(|i| i.to_le_bytes()).collect();
emu.maps.write_bytes(data1_addr, &bytes1);
let ints2: Vec<u32> = vec![1, 2, 3, 4];
let bytes2: Vec<u8> = ints2.iter().flat_map(|i| i.to_le_bytes()).collect();
emu.maps.write_bytes(data2_addr, &bytes2);
emu.regs_mut().rip = code_addr;
emu.regs_mut().rsp = 0x7000;
emu.maps
.create_map("stack", 0x0, 0x10000, Permission::READ_WRITE);
let ret_addr = 0x1000;
emu.maps.create_map(
"ret_guard",
ret_addr,
0x1000,
Permission::READ_WRITE_EXECUTE,
);
emu.maps.write_byte(ret_addr, 0x90);
emu.stack_push64(ret_addr);
let _ = emu.run(Some(ret_addr)).unwrap();
let xmm0 = emu.regs().xmm0;
let result_bytes = xmm0.to_le_bytes();
let i1 = u32::from_le_bytes(result_bytes[0..4].try_into().unwrap());
let i2 = u32::from_le_bytes(result_bytes[4..8].try_into().unwrap());
let i3 = u32::from_le_bytes(result_bytes[8..12].try_into().unwrap());
let i4 = u32::from_le_bytes(result_bytes[12..16].try_into().unwrap());
assert_eq!(i1, 10);
assert_eq!(i2, 20);
assert_eq!(i3, 30);
assert_eq!(i4, 40);
}