1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
//! This module implements some wrappers around Mmap/MmapMut to also support a cheap "empty" variant.
// Unfortunately Memmap itself doesn't support a cheap zero-length variant
use std::ops::{Deref, DerefMut};
use std::io;
use memmap2::{Mmap, MmapMut};
use crate::AssemblyOffset;
/// A structure holding a buffer of executable memory. It also derefs to a `&[u8]`.
/// This structure does not allocate when its size is 0.
#[derive(Debug)]
pub struct ExecutableBuffer {
// length of the buffer that has actually been written to
length: usize,
// backing buffer
buffer: Option<Mmap>
}
/// ExecutableBuffer equivalent that holds a buffer of mutable memory instead of executable memory. It also derefs to a `&mut [u8]`.
/// This structure does not allocate when its size is 0.
#[derive(Debug)]
pub struct MutableBuffer {
// length of the buffer that has actually been written to
length: usize,
// backing buffer
buffer: Option<MmapMut>
}
impl ExecutableBuffer {
/// Obtain a pointer into the executable memory from an offset into it.
/// When an offset returned from `DynasmLabelApi::offset` is used, the resulting pointer
/// will point to the start of the first instruction after the offset call,
/// which can then be jumped or called to divert control flow into the executable
/// buffer. Note that if this buffer is accessed through an Executor, these pointers
/// will only be valid as long as its lock is held. When no locks are held,
/// The assembler is free to relocate the executable buffer when it requires
/// more memory than available.
pub fn ptr(&self, offset: AssemblyOffset) -> *const u8 {
&self[offset.0] as *const u8
}
/// Create a new executable buffer, backed by a buffer of size `size`.
/// It will start with an initialized length of 0.
pub fn new(size: usize) -> io::Result<ExecutableBuffer> {
let buffer = if size == 0 {
None
} else {
Some(MmapMut::map_anon(size)?.make_exec()?)
};
Ok(ExecutableBuffer {
length: 0,
buffer
})
}
/// Query the backing size of this executable buffer
pub fn size(&self) -> usize {
self.buffer.as_ref().map(|b| b.len()).unwrap_or(0) as usize
}
/// Change this executable buffer into a mutable buffer.
pub fn make_mut(self) -> io::Result<MutableBuffer> {
let buffer = if let Some(map) = self.buffer {
Some(map.make_mut()?)
} else {
None
};
Ok(MutableBuffer {
length: self.length,
buffer
})
}
}
impl MutableBuffer {
/// Create a new mutable buffer, backed by a buffer of size `size`.
/// It will start with an initialized length of 0.
pub fn new(size: usize) -> io::Result<MutableBuffer> {
let buffer = if size == 0 {
None
} else {
Some(MmapMut::map_anon(size)?)
};
Ok(MutableBuffer {
length: 0,
buffer
})
}
/// Query the backing size of this mutable buffer
pub fn size(&self) -> usize {
self.buffer.as_ref().map(|b| b.len()).unwrap_or(0) as usize
}
/// Set the length of the usable part of this mutable buffer. The length
/// should not be set larger than the allocated size, otherwise methods can panic.
pub fn set_len(&mut self, length: usize) {
self.length = length
}
/// Change this mutable buffer into an executable buffer.
pub fn make_exec(self) -> io::Result<ExecutableBuffer> {
let buffer = if let Some(map) = self.buffer {
Some(map.make_exec()?)
} else {
None
};
Ok(ExecutableBuffer {
length: self.length,
buffer
})
}
}
impl Default for ExecutableBuffer {
fn default() -> ExecutableBuffer {
ExecutableBuffer {
length: 0,
buffer: None
}
}
}
impl Default for MutableBuffer {
fn default() -> MutableBuffer {
MutableBuffer {
length: 0,
buffer: None
}
}
}
impl Deref for ExecutableBuffer {
type Target = [u8];
fn deref(&self) -> &[u8] {
if let Some(map) = &self.buffer {
&map[..self.length]
} else {
&[]
}
}
}
impl Deref for MutableBuffer {
type Target = [u8];
fn deref(&self) -> &[u8] {
if let Some(map) = &self.buffer {
&map[..self.length]
} else {
&[]
}
}
}
impl DerefMut for MutableBuffer {
fn deref_mut(&mut self) -> &mut [u8] {
if let Some(map) = &mut self.buffer {
&mut map[..self.length]
} else {
&mut []
}
}
}