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}