dynasmrt/
mmap.rs

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