diff --git a/src/lib.rs b/src/lib.rs index 24b6d422..a6fc8682 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ use std::fmt; use std::fs::File; use std::io::{Error, ErrorKind, Result}; use std::ops::{Deref, DerefMut}; +use std::ptr; use std::slice; use std::usize; @@ -40,13 +41,25 @@ use std::usize; /// [`map_mut()`]: MmapOptions::map_mut() /// [`map_exec()`]: MmapOptions::map_exec() /// [`map_copy()`]: MmapOptions::map_copy() -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct MmapOptions { + address: *mut u8, offset: u64, len: Option, stack: bool, } +impl Default for MmapOptions { + fn default() -> Self { + MmapOptions { + address: ptr::null_mut(), + offset: u64::default(), + len: Option::default(), + stack: bool::default(), + } + } +} + impl MmapOptions { /// Creates a new set of options for configuring and creating a memory map. /// @@ -143,6 +156,12 @@ impl MmapOptions { }) } + /// Configures the starting address of the created memory mapped buffer. + pub fn address(&mut self, address: *mut u8) -> &mut Self { + self.address = address; + self + } + /// Configures the anonymous memory map to be suitable for a process or thread stack. /// /// This option corresponds to the `MAP_STACK` flag on Linux. @@ -193,7 +212,7 @@ impl MmapOptions { /// # } /// ``` pub unsafe fn map(&self, file: &File) -> Result { - MmapInner::map(self.get_len(file)?, file, self.offset).map(|inner| Mmap { inner: inner }) + MmapInner::map(self.address, self.get_len(file)?, file, self.offset).map(|inner| Mmap { inner: inner }) } /// Creates a readable and executable memory map backed by a file. @@ -203,7 +222,7 @@ impl MmapOptions { /// This method returns an error when the underlying system call fails, which can happen for a /// variety of reasons, such as when the file is not open with read permissions. pub unsafe fn map_exec(&self, file: &File) -> Result { - MmapInner::map_exec(self.get_len(file)?, file, self.offset) + MmapInner::map_exec(self.address, self.get_len(file)?, file, self.offset) .map(|inner| Mmap { inner: inner }) } @@ -241,7 +260,7 @@ impl MmapOptions { /// # } /// ``` pub unsafe fn map_mut(&self, file: &File) -> Result { - MmapInner::map_mut(self.get_len(file)?, file, self.offset) + MmapInner::map_mut(self.address, self.get_len(file)?, file, self.offset) .map(|inner| MmapMut { inner: inner }) } @@ -270,7 +289,7 @@ impl MmapOptions { /// # } /// ``` pub unsafe fn map_copy(&self, file: &File) -> Result { - MmapInner::map_copy(self.get_len(file)?, file, self.offset) + MmapInner::map_copy(self.address, self.get_len(file)?, file, self.offset) .map(|inner| MmapMut { inner: inner }) } @@ -283,7 +302,7 @@ impl MmapOptions { /// /// This method returns an error when the underlying system call fails. pub fn map_anon(&self) -> Result { - MmapInner::map_anon(self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner: inner }) + MmapInner::map_anon(self.address, self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner: inner }) } } diff --git a/src/unix.rs b/src/unix.rs index 4838e7e4..0e976344 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -28,9 +28,10 @@ impl MmapInner { /// /// This is a thin wrapper around the `mmap` sytem call. fn new( + address: *mut u8, len: usize, prot: libc::c_int, - flags: libc::c_int, + mut flags: libc::c_int, file: RawFd, offset: u64, ) -> io::Result { @@ -45,9 +46,13 @@ impl MmapInner { )); } + if address != ptr::null_mut() { + flags |= libc::MAP_FIXED + } + unsafe { let ptr = libc::mmap( - ptr::null_mut(), + address as *mut libc::c_void, aligned_len as libc::size_t, prot, flags, @@ -66,8 +71,9 @@ impl MmapInner { } } - pub fn map(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { MmapInner::new( + address, len, libc::PROT_READ, libc::MAP_SHARED, @@ -76,8 +82,9 @@ impl MmapInner { ) } - pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map_exec(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { MmapInner::new( + address, len, libc::PROT_READ | libc::PROT_EXEC, libc::MAP_SHARED, @@ -86,8 +93,9 @@ impl MmapInner { ) } - pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map_mut(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { MmapInner::new( + address, len, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_SHARED, @@ -96,8 +104,9 @@ impl MmapInner { ) } - pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map_copy(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { MmapInner::new( + address, len, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_PRIVATE, @@ -107,9 +116,10 @@ impl MmapInner { } /// Open an anonymous memory map. - pub fn map_anon(len: usize, stack: bool) -> io::Result { + pub fn map_anon(address: *mut u8, len: usize, stack: bool) -> io::Result { let stack = if stack { MAP_STACK } else { 0 }; MmapInner::new( + address, len, libc::PROT_READ | libc::PROT_WRITE, libc::MAP_SHARED | libc::MAP_ANON | stack, diff --git a/src/windows.rs b/src/windows.rs index d8aa99d2..9212e405 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -7,7 +7,7 @@ use winapi::shared::basetsd::SIZE_T; use winapi::shared::minwindef::DWORD; use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE}; use winapi::um::memoryapi::{ - CreateFileMappingW, FlushViewOfFile, MapViewOfFile, UnmapViewOfFile, VirtualProtect, + CreateFileMappingW, FlushViewOfFile, MapViewOfFileEx, UnmapViewOfFile, VirtualProtect, FILE_MAP_ALL_ACCESS, FILE_MAP_COPY, FILE_MAP_EXECUTE, FILE_MAP_READ, FILE_MAP_WRITE, }; use winapi::um::sysinfoapi::GetSystemInfo; @@ -26,8 +26,9 @@ pub struct MmapInner { impl MmapInner { /// Creates a new `MmapInner`. /// - /// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFile` system calls. + /// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFileEx` system calls. pub fn new( + address: *mut u8, file: &File, protect: DWORD, access: DWORD, @@ -52,12 +53,13 @@ impl MmapInner { return Err(io::Error::last_os_error()); } - let ptr = MapViewOfFile( + let ptr = MapViewOfFileEx( handle, access, (aligned_offset >> 16 >> 16) as DWORD, (aligned_offset & 0xffffffff) as DWORD, aligned_len as SIZE_T, + address as *mut c_void, ); CloseHandle(handle); @@ -74,7 +76,7 @@ impl MmapInner { } } - pub fn map(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE); let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ); let mut access = FILE_MAP_READ; @@ -94,14 +96,14 @@ impl MmapInner { (false, false) => PAGE_READONLY, }; - let mut inner = MmapInner::new(file, protection, access, offset, len, false)?; + let mut inner = MmapInner::new(address, file, protection, access, offset, len, false)?; if write || exec { inner.make_read_only()?; } Ok(inner) } - pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map_exec(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE); let mut access = FILE_MAP_READ | FILE_MAP_EXECUTE; let protection = if write { @@ -111,14 +113,14 @@ impl MmapInner { PAGE_EXECUTE_READ }; - let mut inner = MmapInner::new(file, protection, access, offset, len, false)?; + let mut inner = MmapInner::new(address, file, protection, access, offset, len, false)?; if write { inner.make_exec()?; } Ok(inner) } - pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map_mut(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ); let mut access = FILE_MAP_READ | FILE_MAP_WRITE; let protection = if exec { @@ -128,14 +130,14 @@ impl MmapInner { PAGE_READWRITE }; - let mut inner = MmapInner::new(file, protection, access, offset, len, false)?; + let mut inner = MmapInner::new(address, file, protection, access, offset, len, false)?; if exec { inner.make_mut()?; } Ok(inner) } - pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result { + pub fn map_copy(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result { let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READWRITE); let mut access = FILE_MAP_COPY; let protection = if exec { @@ -145,14 +147,14 @@ impl MmapInner { PAGE_WRITECOPY }; - let mut inner = MmapInner::new(file, protection, access, offset, len, true)?; + let mut inner = MmapInner::new(address, file, protection, access, offset, len, true)?; if exec { inner.make_mut()?; } Ok(inner) } - pub fn map_anon(len: usize, _stack: bool) -> io::Result { + pub fn map_anon(address: *mut u8, len: usize, _stack: bool) -> io::Result { unsafe { // Create a mapping and view with maximum access permissions, then use `VirtualProtect` // to set the actual `Protection`. This way, we can set more permissive protection later @@ -171,7 +173,7 @@ impl MmapInner { return Err(io::Error::last_os_error()); } let access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE; - let ptr = MapViewOfFile(handle, access, 0, 0, len as SIZE_T); + let ptr = MapViewOfFileEx(handle, access, 0, 0, len as SIZE_T, address as *mut c_void); CloseHandle(handle); if ptr == ptr::null_mut() {