fern_jit/
executable_memory.rs1use std::{io, ptr, slice};
4
5pub struct ExecutableMemory {
7 start: *mut u8,
8 length: usize,
9}
10
11impl ExecutableMemory {
12 pub fn of_size(length: usize) -> io::Result<ExecutableMemory> {
14 unsafe {
15 let page_size = {
16 let result = libc::sysconf(libc::_SC_PAGESIZE);
17 if result == -1 {
18 Err(io::Error::last_os_error())
19 } else {
20 Ok(result as usize)
21 }
22 }?;
23 let aligned_length = (length + page_size - 1) & !(page_size - 1);
24
25 #[cfg(target_os = "macos")]
26 let flags = libc::MAP_JIT | libc::MAP_ANON | libc::MAP_PRIVATE;
27
28 #[cfg(not(target_os = "macos"))]
29 let flags = libc::MAP_ANON | libc::MAP_PRIVATE;
30
31 let start = libc::mmap(
32 ptr::null_mut(),
33 aligned_length,
34 libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC,
35 flags,
36 -1,
37 0,
38 );
39 if start == libc::MAP_FAILED {
40 return Err(io::Error::last_os_error());
41 }
42 Ok(ExecutableMemory {
52 start: start as *mut u8,
53 length: aligned_length,
54 })
55 }
56 }
57
58 pub fn start(&mut self) -> *mut u8 {
59 self.start
60 }
61
62 pub fn length(&self) -> usize {
63 self.length
64 }
65
66 pub fn as_slice_mut(&mut self) -> &mut [u8] {
67 unsafe { slice::from_raw_parts_mut(self.start, self.length) }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use std::mem;
74
75 use super::ExecutableMemory;
76
77 #[cfg(target_arch = "x86_64")]
78 #[test]
79 fn simple_func() {
80 let mut jit_mem = ExecutableMemory::of_size(1024 * 1024)
81 .expect("failed to map memory");
82
83 for (i, byte) in [0xB8, 0x2A, 0x00, 0x00, 0x00, 0xC3].iter().enumerate()
86 {
87 jit_mem.as_slice_mut()[i] = *byte;
88 }
89
90 unsafe {
91 let ret_42: unsafe fn() -> i32 = mem::transmute(jit_mem.start());
92 assert_eq!(42, ret_42());
93 };
94 }
95}