use crate::{JumpEntry, code_manipulate::CodeManipulator};
#[doc(hidden)]
#[macro_export]
macro_rules! os_static_key_sec_name_attr {
() => {
"__DATA,__static_keys,regular,no_dead_strip"
};
}
unsafe extern "Rust" {
#[link_name = "\x01section$start$__DATA$__static_keys"]
pub static mut JUMP_ENTRY_START: JumpEntry;
#[link_name = "\x01section$end$__DATA$__static_keys"]
pub static mut JUMP_ENTRY_STOP: JumpEntry;
}
unsafe extern "C" {
fn sys_dcache_flush(start: *mut core::ffi::c_void, len: usize);
fn sys_icache_invalidate(start: *mut core::ffi::c_void, len: usize);
}
pub struct ArchCodeManipulator;
const VM_FLAGS_RETURN_DATA_ADDR: i32 = 0x00100000;
impl CodeManipulator for ArchCodeManipulator {
unsafe fn write_code<const L: usize>(addr: *mut core::ffi::c_void, data: &[u8; L]) {
let mut remap_addr = 0;
let mut cur_prot = 0;
let mut max_prot = 0;
let self_task = unsafe { mach2::traps::mach_task_self() };
let length = L as u64;
let ret = unsafe {
mach2::vm::mach_vm_remap(
self_task,
&mut remap_addr,
length,
0,
mach2::vm_statistics::VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR,
self_task,
addr as u64,
0,
&mut cur_prot,
&mut max_prot,
mach2::vm_inherit::VM_INHERIT_NONE,
)
};
if ret != mach2::kern_return::KERN_SUCCESS {
panic!("mach_vm_remap to new failed");
}
let ret = unsafe {
mach2::vm::mach_vm_protect(
self_task,
remap_addr,
length,
0,
mach2::vm_prot::VM_PROT_READ
| mach2::vm_prot::VM_PROT_WRITE
| mach2::vm_prot::VM_PROT_COPY,
)
};
if ret != mach2::kern_return::KERN_SUCCESS {
panic!("mach_vm_protect to write failed");
}
unsafe {
core::ptr::copy_nonoverlapping(data.as_ptr(), remap_addr as *mut _, L);
}
unsafe {
sys_dcache_flush(addr, L);
}
let ret = unsafe {
mach2::vm::mach_vm_protect(
self_task,
remap_addr,
length,
0,
mach2::vm_prot::VM_PROT_READ | mach2::vm_prot::VM_PROT_EXECUTE,
)
};
if ret != mach2::kern_return::KERN_SUCCESS {
panic!("mach_vm_protect to execute failed");
}
unsafe {
sys_icache_invalidate(addr, L);
}
let mut origin_addr = addr as u64;
let ret = unsafe {
mach2::vm::mach_vm_remap(
self_task,
&mut origin_addr,
length,
0,
mach2::vm_statistics::VM_FLAGS_OVERWRITE | VM_FLAGS_RETURN_DATA_ADDR,
self_task,
remap_addr,
0,
&mut cur_prot,
&mut max_prot,
mach2::vm_inherit::VM_INHERIT_NONE,
)
};
if ret != mach2::kern_return::KERN_SUCCESS {
panic!("mach_vm_remap to origin failed");
}
}
}