dynasmrt/
lib.rs

1#![warn(missing_docs)]
2
3//! This crate provides runtime support for dynasm-rs. It contains traits that document the interface used by the dynasm proc_macro to generate code,
4//! Assemblers that implement these traits, and relocation models for the various supported architectures. Additionally, it also provides the tools
5//! to write your own Assemblers using these components.
6
7pub mod mmap;
8pub mod components;
9pub mod relocations;
10pub mod cache_control;
11
12/// Helper to implement common traits on register enums.
13macro_rules! reg_impls {
14    ($r:ty) => {
15        impl $crate::Register for $r {
16            fn code(&self) -> u8 {
17                *self as u8
18            }
19        }
20
21        impl From<$r> for u8 {
22            fn from(rq: $r) -> u8 {
23                rq.code()
24            }
25        }
26    }
27}
28
29pub mod x64;
30pub mod x86;
31pub mod aarch64;
32pub mod riscv;
33
34pub use crate::mmap::ExecutableBuffer;
35pub use dynasm::{dynasm, dynasm_backwards};
36
37use crate::components::{MemoryManager, LabelRegistry, RelocRegistry, ManagedRelocs, PatchLoc, StaticLabel};
38use crate::relocations::Relocation;
39
40use std::hash::Hash;
41use std::sync::{Arc, RwLock, RwLockReadGuard};
42use std::io;
43use std::error;
44use std::fmt::{self, Debug};
45use std::mem;
46
47/// This macro takes a *const pointer from the source operand, and then casts it to the desired return type.
48/// this allows it to be used as an easy shorthand for passing pointers as dynasm immediate arguments.
49#[macro_export]
50macro_rules! Pointer {
51    ($e:expr) => {$e as *const _ as _};
52}
53
54/// Preforms the same action as the `Pointer!` macro, but casts to a *mut pointer.
55#[macro_export]
56macro_rules! MutPointer {
57    ($e:expr) => {$e as *mut _ as _};
58}
59
60
61/// A struct representing an offset into the assembling buffer of a `DynasmLabelApi` struct.
62/// The wrapped `usize` is the offset from the start of the assembling buffer in bytes.
63#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
64pub struct AssemblyOffset(pub usize);
65
66/// A dynamic label
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68pub struct DynamicLabel(usize);
69
70
71impl DynamicLabel {
72    /// Get the internal ID of this dynamic label. This is only useful for debugging purposes.
73    pub fn get_id(self) -> usize {
74        self.0
75    }
76}
77
78
79/// A read-only shared reference to the executable buffer inside an `Assembler`. By
80/// locking it the internal `ExecutableBuffer` can be accessed and executed.
81#[derive(Debug, Clone)]
82pub struct Executor {
83    execbuffer: Arc<RwLock<ExecutableBuffer>>
84}
85
86/// A read-only lockable reference to the internal `ExecutableBuffer` of an `Assembler`.
87/// To gain access to this buffer, it must be locked.
88impl Executor {
89    /// Gain read-access to the internal `ExecutableBuffer`. While the returned guard
90    /// is alive, it can be used to read and execute from the `ExecutableBuffer`.
91    /// Any pointers created to the `ExecutableBuffer` should no longer be used when
92    /// the guard is dropped.
93    #[inline]
94    pub fn lock(&self) -> RwLockReadGuard<'_, ExecutableBuffer> {
95        let guard = self.execbuffer.read().unwrap();
96        cache_control::prepare_for_execution(&*guard);
97        guard
98    }
99}
100
101
102/// A description of a label. Used for error reporting.
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
104pub enum LabelKind {
105    /// A local label, like `label:`
106    Local(&'static str),
107    /// A global label, like `->label:`
108    Global(&'static str),
109    /// A dynamic label, like `=>value:`
110    Dynamic(DynamicLabel)
111}
112
113impl fmt::Display for LabelKind {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        match self {
116            Self::Local(s) => write!(f, "label {}", s),
117            Self::Global(s) => write!(f, "label ->{}", s),
118            Self::Dynamic(id) => write!(f, "label =>{}", id.get_id())
119        }
120    }
121}
122
123
124/// A description of a relocation target. Used for error reporting.
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126pub enum TargetKind {
127    /// This targets a local label with the specified name.
128    Local(&'static str),
129    /// This targets a global label with the specified name.
130    Global(&'static str),
131    /// This targets the specified dynamic label.
132    Dynamic(DynamicLabel),
133    /// This targets the specified address.
134    Extern(usize),
135    /// An already resolved relocation that needs to be adjusted when the buffer moves in memory.
136    Managed,
137}
138
139impl fmt::Display for TargetKind {
140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141        match self {
142            Self::Local(s) => write!(f, "target [><]{}", s),
143            Self::Global(s) => write!(f, "target ->{}", s),
144            Self::Dynamic(id) => write!(f, "target =>{}", id.get_id()),
145            Self::Extern(value) => write!(f, "target extern {}", value),
146            Self::Managed => write!(f, "while adjusting managed relocation"),
147        }
148    }
149}
150
151
152/// The various error types generated by dynasm functions.
153#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum DynasmError {
155    /// A check (like `Modifier::check` or `Modifier::check_exact`) that failed
156    CheckFailed,
157    /// A duplicate label dynamic/global label was defined
158    DuplicateLabel(LabelKind),
159    /// An unknown label
160    UnknownLabel(LabelKind),
161    /// The user tried to declare a relocation too far away from the label it targets
162    ImpossibleRelocation(TargetKind),
163}
164
165impl fmt::Display for DynasmError {
166    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167        match self {
168            DynasmError::CheckFailed => write!(f, "An assembly modification check failed"),
169            DynasmError::DuplicateLabel(l) => write!(f, "Duplicate label defined: '{}'", l),
170            DynasmError::UnknownLabel(l) => write!(f, "Unknown label: '{}'", l),
171            DynasmError::ImpossibleRelocation(s) => write!(f, "Impossible relocation: '{}'", s),
172        }
173    }
174}
175
176impl error::Error for DynasmError {
177    fn description(&self) -> &str {
178        match self {
179            DynasmError::CheckFailed => "An assembly modification offset check failed",
180            DynasmError::DuplicateLabel(_) => "Duplicate label defined",
181            DynasmError::UnknownLabel(_) => "Unknown label",
182            DynasmError::ImpossibleRelocation(_) => "Impossible relocation",
183        }
184    }
185}
186
187
188/// This trait represents the interface that must be implemented to allow
189/// the dynasm preprocessor to assemble into a datastructure.
190pub trait DynasmApi: Extend<u8> + for<'a> Extend<&'a u8> {
191    /// Report the current offset into the assembling target
192    fn offset(&self) -> AssemblyOffset;
193    /// Push a byte into the assembling target
194    fn push(&mut self, byte: u8);
195    /// Push filler until the assembling target end is aligned to the given alignment.
196    fn align(&mut self, alignment: usize, with: u8);
197
198    #[inline]
199    /// Push a signed byte into the assembling target
200    fn push_i8(&mut self, value: i8) {
201        self.push(value as u8);
202    }
203    /// Push a signed word into the assembling target
204    #[inline]
205    fn push_i16(&mut self, value: i16) {
206        self.extend(&value.to_le_bytes());
207    }
208    /// Push a signed doubleword into the assembling target
209    #[inline]
210    fn push_i32(&mut self, value: i32) {
211        self.extend(&value.to_le_bytes());
212    }
213    /// Push a signed quadword into the assembling target
214    #[inline]
215    fn push_i64(&mut self, value: i64) {
216        self.extend(&value.to_le_bytes());
217    }
218    /// Push an usigned word into the assembling target
219    #[inline]
220    fn push_u16(&mut self, value: u16) {
221        self.extend(&value.to_le_bytes());
222    }
223    /// Push an usigned doubleword into the assembling target
224    #[inline]
225    fn push_u32(&mut self, value: u32) {
226        self.extend(&value.to_le_bytes());
227    }
228    /// Push an usigned quadword into the assembling target
229    #[inline]
230    fn push_u64(&mut self, value: u64) {
231        self.extend(&value.to_le_bytes());
232    }
233    /// This function is called in when a runtime error has to be generated. It panics.
234    #[inline]
235    fn runtime_error(&self, msg: &'static str) -> ! {
236        panic!("{}", msg);
237    }
238}
239
240/// This trait extends DynasmApi to not only allow assembling, but also labels and various directives.
241///
242/// For information on the different kinds of label, consult the common language reference in the
243/// dynasm-rs docs.
244pub trait DynasmLabelApi : DynasmApi {
245    /// The relocation info type this assembler uses. 
246    type Relocation: Relocation;
247
248    /// Record the definition of a local label
249    fn local_label(  &mut self, name: &'static str);
250    /// Record the definition of a global label
251    fn global_label( &mut self, name: &'static str);
252    /// Record the definition of a dynamic label
253    fn dynamic_label(&mut self, id: DynamicLabel);
254
255    /// Record a relocation spot for a forward reference to a local label
256    fn forward_reloc( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
257        self.forward_relocation(name, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
258    }
259    /// Record a relocation spot for a backward reference to a local label
260    fn backward_reloc(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
261        self.backward_relocation(name, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
262    }
263    /// Record a relocation spot for a reference to a global label
264    fn global_reloc(  &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
265        self.global_relocation(name, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
266    }
267    /// Record a relocation spot for a reference to a dynamic label
268    fn dynamic_reloc( &mut self, id: DynamicLabel,   target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
269        self.dynamic_relocation(id, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
270    }
271    /// Record a relocation spot to an arbitrary target.
272    fn bare_reloc(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
273        self.bare_relocation(target, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
274    }
275
276    /// Equivalent of forward_reloc, but takes a non-encoded relocation
277    fn forward_relocation( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
278    /// Equivalent of backward_reloc, but takes a non-encoded relocation
279    fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
280    /// Equivalent of global_reloc, but takes a non-encoded relocation
281    fn global_relocation(  &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
282    /// Equivalent of dynamic_reloc, but takes a non-encoded relocation
283    fn dynamic_relocation( &mut self, id: DynamicLabel,   target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
284    /// Equivalent of bare_reloc, but takes a non-encoded relocation
285    fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
286}
287
288
289/// An assembler that is purely a `Vec<u8>`. It doesn't support labels or architecture-specific directives,
290/// but can be used to easily inspect generated code. It is intended to be used in testcases.
291#[derive(Debug, Clone)]
292pub struct SimpleAssembler {
293    /// The assembling buffer.
294    pub ops: Vec<u8>
295}
296
297impl SimpleAssembler {
298    /// Creates a new `SimpleAssembler`, containing an empty `Vec`.
299    pub fn new() -> SimpleAssembler {
300        SimpleAssembler {
301            ops: Vec::new()
302        }
303    }
304
305    /// Use an `UncommittedModifier` to alter uncommitted code.
306    pub fn alter(&mut self) -> UncommittedModifier<'_> {
307        UncommittedModifier::new(&mut self.ops, AssemblyOffset(0))
308    }
309
310    /// Destroys this assembler, returning the `Vec<u8>` contained within
311    pub fn finalize(self) -> Vec<u8> {
312        self.ops
313    }
314}
315
316impl Extend<u8> for SimpleAssembler {
317    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
318        self.ops.extend(iter)
319    }
320}
321
322impl<'a> Extend<&'a u8> for SimpleAssembler {
323    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'a u8> {
324        self.ops.extend(iter)
325    }
326}
327
328impl DynasmApi for SimpleAssembler {
329    fn offset(&self) -> AssemblyOffset {
330        AssemblyOffset(self.ops.len())
331    }
332    fn push(&mut self, byte: u8) {
333        self.ops.push(byte);
334    }
335    fn align(&mut self, alignment: usize, with: u8) {
336        let offset = self.offset().0 % alignment;
337        if offset != 0 {
338            for _ in offset .. alignment {
339                self.push(with);
340            }
341        }
342    }
343}
344
345
346/// An assembler that assembles into a `Vec<u8>`, while supporting labels. To support the different types of relocations
347/// it requires a base address of the to be assembled code to be specified.
348#[derive(Debug)]
349pub struct VecAssembler<R: Relocation> {
350    ops: Vec<u8>,
351    baseaddr: usize,
352    labels: LabelRegistry,
353    relocs: RelocRegistry<R>,
354    error: Option<DynasmError>,
355}
356
357impl<R: Relocation> VecAssembler<R> {
358    /// Creates a new VecAssembler, with the specified base address.
359    pub fn new(baseaddr: usize) -> VecAssembler<R> {
360        VecAssembler {
361            ops: Vec::new(),
362            baseaddr,
363            labels: LabelRegistry::new(),
364            relocs: RelocRegistry::new(),
365            error: None
366        }
367    }
368
369    /// Creates a new VecAssembler, with the specified base address.
370    /// Preallocates `vec_capacity` bytes to the internal vector, and `label_capacity` label locations of each type.
371    /// Allows the user to specify the initial capacity of the internal datastructures.
372    /// `ops_capacity` is the amount of bytes preallocated for the assembling buffer.
373    /// `local_labels` determines the preallocated space for local labels definitions.
374    /// `global_labels` determines the preallocated space for global labels definitions.
375    /// `dynamic_labels` determines the preallocated space for dynamic labels definitions.
376    /// `static_references` determines the preallocated space for references to local/global labels.
377    /// `dynamic_references` determines the preallocated space for references to dynamic labels.
378    pub fn new_with_capacity(baseaddr: usize, ops_capacity: usize,
379                             local_labels: usize, global_labels: usize, dynamic_labels: usize,
380                             static_references: usize, dynamic_references: usize) -> VecAssembler<R> {
381        VecAssembler {
382            ops: Vec::with_capacity(ops_capacity),
383            baseaddr,
384            labels: LabelRegistry::with_capacity(local_labels, global_labels, dynamic_labels),
385            relocs: RelocRegistry::with_capacity(static_references, dynamic_references),
386            error: None
387        }
388    }
389
390    /// Reserve capacity for at least `additional` instruction bytes to be inserted
391    pub fn reserve_ops(&mut self, additional: usize) {
392        self.ops.reserve(additional);
393    }
394
395    /// Create a new dynamic label ID
396    pub fn new_dynamic_label(&mut self) -> DynamicLabel {
397        self.labels.new_dynamic_label()
398    }
399
400    /// Resolves any relocations emitted to the assembler before this point.
401    /// If an impossible relocation was specified before this point, returns them here.
402    pub fn commit(&mut self) -> Result<(), DynasmError> {
403        // If we accrued any errors while assembling before, emit them now.
404        if let Some(e) = self.error.take() {
405            return Err(e);
406        }
407
408        // Resolve statics
409        for (loc, label) in self.relocs.take_statics() {
410            let target = self.labels.resolve_static(&label)?;
411            let buf = &mut self.ops[loc.range(0)];
412            if loc.patch(buf, self.baseaddr, target.0).is_err() {
413                return Err(DynasmError::ImpossibleRelocation(
414                    if label.is_global() {
415                        TargetKind::Global(label.get_name())
416                    } else {
417                        TargetKind::Local(label.get_name())
418                    }
419                ));
420            }
421        }
422
423        // Resolve dynamics
424        for (loc, id) in self.relocs.take_dynamics() {
425            let target = self.labels.resolve_dynamic(id)?;
426            let buf = &mut self.ops[loc.range(0)];
427            if loc.patch(buf, self.baseaddr, target.0).is_err() {
428                return Err(DynasmError::ImpossibleRelocation(TargetKind::Dynamic(id)));
429            }
430        }
431
432        Ok(())
433    }
434
435    /// Use an `UncommittedModifier` to alter uncommitted code.
436    /// This does not allow the user to change labels/relocations.
437    pub fn alter(&mut self) -> UncommittedModifier<'_> {
438        UncommittedModifier::new(&mut self.ops, AssemblyOffset(0))
439    }
440
441    /// Provides access to the assemblers internal labels registry
442    pub fn labels(&self) -> &LabelRegistry {
443        &self.labels
444    }
445
446    /// Provides mutable access to the assemblers internal labels registry
447    pub fn labels_mut(&mut self) -> &mut LabelRegistry {
448        &mut self.labels
449    }
450
451    /// Finalizes the `VecAssembler`, returning the resulting `Vec<u8>` containing all assembled data.
452    /// this implicitly commits any relocations beforehand and returns an error if required.
453    pub fn finalize(mut self) -> Result<Vec<u8>, DynasmError> {
454        self.commit()?;
455        Ok(self.ops)
456    }
457
458    /// Equivalent of finalize, but allows the VecAssembler's internal allocations to be reused for the next assembler.
459    pub fn take(&mut self) -> Result<Vec<u8>, DynasmError> {
460        self.commit()?;
461        self.labels.clear();
462        Ok(std::mem::take(&mut self.ops))
463    }
464
465    /// Equivalent of take, but instead of allocating a new vector it simply provides a draining iterator over the internal contents.
466    pub fn drain<'a>(&'a mut self) -> Result<impl Iterator<Item=u8> + 'a, DynasmError> {
467        self.commit()?;
468        self.labels.clear();
469        Ok(self.ops.drain(..))
470    }
471}
472
473impl<R: Relocation> Extend<u8> for VecAssembler<R> {
474    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
475        self.ops.extend(iter)
476    }
477}
478
479impl<'a, R: Relocation> Extend<&'a u8> for VecAssembler<R> {
480    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'a u8> {
481        self.ops.extend(iter)
482    }
483}
484
485impl<R: Relocation> DynasmApi for VecAssembler<R> {
486    fn offset(&self) -> AssemblyOffset {
487        AssemblyOffset(self.ops.len())
488    }
489    fn push(&mut self, byte: u8) {
490        self.ops.push(byte);
491    }
492    fn align(&mut self, alignment: usize, with: u8) {
493        let offset = self.offset().0 % alignment;
494        if offset != 0 {
495            for _ in offset .. alignment {
496                self.push(with);
497            }
498        }
499    }
500}
501
502impl<R: Relocation> DynasmLabelApi for VecAssembler<R> {
503    type Relocation = R;
504
505    fn local_label(&mut self, name: &'static str) {
506        let offset = self.offset();
507        self.labels.define_local(name, offset);
508    }
509    fn global_label( &mut self, name: &'static str) {
510        let offset = self.offset();
511        if let Err(e) = self.labels.define_global(name, offset) {
512            self.error = Some(e)
513        }
514    }
515    fn dynamic_label(&mut self, id: DynamicLabel) {
516        let offset = self.offset();
517        if let Err(e) = self.labels.define_dynamic(id, offset) {
518            self.error = Some(e)
519        }
520    }
521    fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
522        let location = self.offset();
523        let label = StaticLabel::global(name);
524        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
525    }
526    fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
527        let location = self.offset();
528        self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
529    }
530    fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
531        let location = self.offset();
532        let label = match self.labels.place_local_reference(name) {
533            Some(label) => label.next(),
534            None => StaticLabel::first(name),
535        };
536        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
537    }
538    fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
539        let location = self.offset();
540        let label = match self.labels.place_local_reference(name) {
541            Some(label) => label,
542            None => {
543                self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
544                return;
545            }
546        };
547        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
548    }
549    fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
550        let location = self.offset();
551        let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
552        let buf = &mut self.ops[loc.range(0)];
553        if loc.patch(buf, self.baseaddr, target).is_err() {
554            self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)))
555        }
556    }
557}
558
559
560/// A full assembler implementation. Supports labels, all types of relocations,
561/// incremental compilation and multithreaded execution with simultaneous compilation.
562/// Its implementation guarantees no memory is executable and writable at the same time.
563#[derive(Debug)]
564pub struct Assembler<R: Relocation> {
565    ops: Vec<u8>,
566    memory: MemoryManager,
567    labels: LabelRegistry,
568    relocs: RelocRegistry<R>,
569    managed: ManagedRelocs<R>,
570    error: Option<DynasmError>,
571}
572
573impl<R: Relocation> Assembler<R> {
574    /// Create a new, empty assembler, with initial allocation size `page_size`.
575    pub fn new() -> io::Result<Self> {
576        Ok(Self {
577            ops: Vec::new(),
578            memory: MemoryManager::new(R::page_size())?,
579            labels: LabelRegistry::new(),
580            relocs: RelocRegistry::new(),
581            managed: ManagedRelocs::new(),
582            error: None
583        })
584    }
585
586    /// Create a new, empty assembler, with a pre-allocated buffer of the specified capacity in bytes,
587    /// and an initial allocation of `capacity.next_multiple_of(page_size)`.
588    pub fn new_with_capacity(capacity: usize) -> io::Result<Self> {
589        // Avoid panic or wraps on overflow.
590        let memory_size =
591            capacity
592                .checked_next_multiple_of(R::page_size())
593                .ok_or(io::Error::new(
594                    io::ErrorKind::InvalidInput,
595                    "Capacity is too large",
596                ))?;
597
598        Ok(Self {
599            ops: Vec::with_capacity(capacity),
600            memory: MemoryManager::new(memory_size)?,
601            labels: LabelRegistry::new(),
602            relocs: RelocRegistry::new(),
603            managed: ManagedRelocs::new(),
604            error: None,
605        })
606    }
607
608    /// Create a new dynamic label ID
609    pub fn new_dynamic_label(&mut self) -> DynamicLabel {
610        self.labels.new_dynamic_label()
611    }
612
613    /// Use an `UncommittedModifier` to alter uncommitted code.
614    /// This does not allow the user to change labels/relocations.
615    pub fn alter_uncommitted(&mut self) -> UncommittedModifier<'_> {
616        let offset = self.memory.committed();
617        UncommittedModifier::new(&mut self.ops, AssemblyOffset(offset))
618    }
619
620    /// Use a `Modifier` to alter committed code directly. While this is happening
621    /// no code can be executed as the relevant pages are remapped as writable.
622    /// This API supports defining new labels/relocations, and overwriting previously defined relocations.
623    pub fn alter<F, O>(&mut self, f: F) -> Result<O, DynasmError>
624    where F: FnOnce(&mut Modifier<R>) -> O {
625        self.commit()?;
626
627        // swap out a buffer from base
628        let mut lock = self.memory.write();
629        let buffer = mem::replace(&mut *lock, ExecutableBuffer::default());
630        let mut buffer = buffer.make_mut().expect("Could not swap buffer protection modes");
631
632        // construct the modifier
633        let mut modifier = Modifier {
634            asmoffset: 0,
635            previous_asmoffset: 0,
636            buffer: &mut buffer,
637
638            labels: &mut self.labels,
639            relocs: &mut self.relocs,
640            old_managed: &mut self.managed,
641            new_managed: ManagedRelocs::new(),
642
643            error: None
644        };
645
646        // execute the user code
647        let output = f(&mut modifier);
648
649        // flush any changes made by the user code to the buffer
650        modifier.encode_relocs()?;
651
652        // repack the buffer
653        let buffer = buffer.make_exec().expect("Could not swap buffer protection modes");
654        *lock = buffer;
655
656        // call it a day
657        Ok(output)
658    }
659
660    /// Commit code, flushing the temporary internal assembling buffer to the mapped executable memory.
661    /// This makes assembled code available for execution.
662    pub fn commit(&mut self) -> Result<(), DynasmError> {
663        self.encode_relocs()?;
664
665        let managed = &self.managed;
666        let error = &mut self.error;
667
668        self.memory.commit(&mut self.ops, |buffer, old_addr, new_addr| {
669            let change = new_addr.wrapping_sub(old_addr) as isize;
670
671            for reloc in managed.iter() {
672                let buf = &mut buffer[reloc.range(0)];
673                if reloc.adjust(buf, change).is_err() {
674                    *error = Some(DynasmError::ImpossibleRelocation(TargetKind::Managed))
675                }
676
677                // we don't need to inform the cache here that we changed something
678                // as the entire allocation is new.
679            }
680        });
681
682        if let Some(e) = self.error.take() {
683            return Err(e);
684        }
685        Ok(())
686    }
687
688    /// Finalize this assembler, returning the internal `ExecutableBuffer` if no `Executor` instances exist.
689    /// This panics if any uncommitted changes caused errors near the end. To handle these, call `commit()` explicitly beforehand.
690    pub fn finalize(mut self) -> Result<ExecutableBuffer, Self> {
691        self.commit().expect("Errors were encountered when committing before finalization");
692        match self.memory.finalize() {
693            Ok(execbuffer) => {
694                cache_control::prepare_for_execution(&execbuffer);
695                Ok(execbuffer)
696            },
697            Err(memory) => Err(Self {
698                memory,
699                ..self
700            })
701        }
702    }
703
704    /// Create an executor which can be used to execute code while still assembling code
705    pub fn reader(&self) -> Executor {
706        Executor {
707            execbuffer: self.memory.reader()
708        }
709    }
710
711    /// Provides access to the assemblers internal labels registry
712    pub fn labels(&self) -> &LabelRegistry {
713        &self.labels
714    }
715
716    /// Provides mutable access to the assemblers internal labels registry
717    pub fn labels_mut(&mut self) -> &mut LabelRegistry {
718        &mut self.labels
719    }
720
721    // encode uncommited relocations
722    fn encode_relocs(&mut self) -> Result<(), DynasmError> {
723        let buf_offset = self.memory.committed();
724        let buf_addr = self.memory.execbuffer_addr();
725        let buf = &mut self.ops;
726
727        // If we accrued any errors while assembling before, emit them now.
728        if let Some(e) = self.error.take() {
729            return Err(e);
730        }
731
732        // Resolve statics
733        for (loc, label) in self.relocs.take_statics() {
734            let target = self.labels.resolve_static(&label)?;
735            let buf = &mut buf[loc.range(buf_offset)];
736            if loc.patch(buf, buf_addr, target.0).is_err() {
737                return Err(DynasmError::ImpossibleRelocation(
738                    if label.is_global() {
739                        TargetKind::Global(label.get_name())
740                    } else {
741                        TargetKind::Local(label.get_name())
742                    }
743                ));
744            }
745            if loc.needs_adjustment() {
746                self.managed.add(loc)
747            }
748        }
749
750        // Resolve dynamics
751        for (loc, id) in self.relocs.take_dynamics() {
752            let target = self.labels.resolve_dynamic(id)?;
753            let buf = &mut buf[loc.range(buf_offset)];
754            if loc.patch(buf, buf_addr, target.0).is_err() {
755                return Err(DynasmError::ImpossibleRelocation(TargetKind::Dynamic(id)));
756            }
757            if loc.needs_adjustment() {
758                self.managed.add(loc)
759            }
760        }
761
762        Ok(())
763    }
764}
765
766impl<R: Relocation> Extend<u8> for Assembler<R> {
767    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
768        self.ops.extend(iter)
769    }
770}
771
772impl<'a, R: Relocation> Extend<&'a u8> for Assembler<R> {
773    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'a u8> {
774        self.ops.extend(iter)
775    }
776}
777
778impl<R: Relocation> DynasmApi for Assembler<R> {
779    fn offset(&self) -> AssemblyOffset {
780        AssemblyOffset(self.memory.committed() + self.ops.len())
781    }
782
783    fn push(&mut self, value: u8) {
784        self.ops.push(value);
785    }
786
787    fn align(&mut self, alignment: usize, with: u8) {
788        let misalign = self.offset().0 % alignment;
789        if misalign != 0 {
790            for _ in misalign .. alignment {
791                self.push(with);
792            }
793        }
794    }
795}
796
797impl<R: Relocation> DynasmLabelApi for Assembler<R> {
798    type Relocation = R;
799
800    fn local_label(&mut self, name: &'static str) {
801        let offset = self.offset();
802        self.labels.define_local(name, offset);
803    }
804    fn global_label( &mut self, name: &'static str) {
805        let offset = self.offset();
806        if let Err(e) = self.labels.define_global(name, offset) {
807            self.error = Some(e)
808        }
809    }
810    fn dynamic_label(&mut self, id: DynamicLabel) {
811        let offset = self.offset();
812        if let Err(e) = self.labels.define_dynamic(id, offset) {
813            self.error = Some(e)
814        }
815    }
816    fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
817        let location = self.offset();
818        let label = StaticLabel::global(name);
819        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
820    }
821    fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
822        let location = self.offset();
823        self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
824    }
825    fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
826        let location = self.offset();
827        let label = match self.labels.place_local_reference(name) {
828            Some(label) => label.next(),
829            None => StaticLabel::first(name),
830        };
831        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
832    }
833    fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
834        let location = self.offset();
835        let label = match self.labels.place_local_reference(name) {
836            Some(label) => label,
837            None => {
838                self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
839                return;
840            }
841        };
842        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
843    }
844    fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
845        let location = self.offset();
846        let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
847        let buf = &mut self.ops[loc.range(self.memory.committed())];
848        if loc.patch(buf, self.memory.execbuffer_addr(), target).is_err() {
849            self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)))
850        } else if loc.needs_adjustment() {
851            self.managed.add(loc)
852        }
853    }
854}
855
856
857/// Allows modification of already committed assembly code. Contains an internal cursor
858/// into the emitted assembly, initialized to the start, that can be moved around either with the
859/// `goto` function, or just by assembling new code into this `Modifier`.
860#[derive(Debug)]
861pub struct Modifier<'a, R: Relocation> {
862    asmoffset: usize,
863    previous_asmoffset: usize,
864    buffer: &'a mut [u8],
865
866    labels: &'a mut LabelRegistry,
867    relocs: &'a mut RelocRegistry<R>,
868    old_managed: &'a mut ManagedRelocs<R>,
869    new_managed: ManagedRelocs<R>,
870
871    error: Option<DynasmError>
872}
873
874impl<'a, R: Relocation> Modifier<'a, R> {
875    /// Move the modifier cursor to the selected location.
876    pub fn goto(&mut self, offset: AssemblyOffset) {
877        // resync the caches of anything we modified before
878        cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
879
880        // remove any old managed relocations from what we overwrote
881        self.old_managed.remove_between(self.previous_asmoffset, self.asmoffset);
882
883        // set the cursor position
884        self.asmoffset = offset.0;
885        self.previous_asmoffset = offset.0;
886    }
887
888    /// Check that the modifier cursor has not moved past the specified location.
889    pub fn check(&self, offset: AssemblyOffset) -> Result<(), DynasmError> {
890        if self.asmoffset > offset.0 {
891            Err(DynasmError::CheckFailed)
892        } else {
893            Ok(())
894        }
895    }
896
897    /// Check that the modifier cursor is exactly at the specified location.
898    pub fn check_exact(&self, offset: AssemblyOffset) -> Result<(), DynasmError> {
899        if self.asmoffset != offset.0 {
900            Err(DynasmError::CheckFailed)
901        } else {
902            Ok(())
903        }
904    }
905
906    // encode uncommited relocations. also, invalidate the icache
907    fn encode_relocs(&mut self) -> Result<(), DynasmError> {
908        let buf_addr = self.buffer.as_ptr() as usize;
909
910        // resync the caches of anything we modified before
911        cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
912
913        // If we accrued any errors while assembling before, emit them now.
914        if let Some(e) = self.error.take() {
915            return Err(e);
916        }
917
918        // Resolve statics
919        for (loc, label) in self.relocs.take_statics() {
920            let target = self.labels.resolve_static(&label)?;
921            let buf = &mut self.buffer[loc.range(0)];
922            if loc.patch(buf, buf_addr, target.0).is_err() {
923                return Err(DynasmError::ImpossibleRelocation(
924                    if label.is_global() {
925                        TargetKind::Global(label.get_name())
926                    } else {
927                        TargetKind::Local(label.get_name())
928                    }
929                ));
930            }
931
932            // resynchronize the cache of any relocation we just performed
933            cache_control::synchronize_icache(buf);
934
935            if loc.needs_adjustment() {
936                self.new_managed.add(loc);
937            }
938        }
939
940        // Resolve dynamics
941        for (loc, id) in self.relocs.take_dynamics() {
942            let target = self.labels.resolve_dynamic(id)?;
943            let buf = &mut self.buffer[loc.range(0)];
944            if loc.patch(buf, buf_addr, target.0).is_err() {
945                return Err(DynasmError::ImpossibleRelocation(TargetKind::Dynamic(id)));
946            }
947
948            // resynchronize the cache of any relocation we just performed
949            cache_control::synchronize_icache(buf);
950
951            if loc.needs_adjustment() {
952                self.new_managed.add(loc);
953            }
954        }
955
956        self.old_managed.remove_between(self.previous_asmoffset, self.asmoffset);
957        self.previous_asmoffset = self.asmoffset;
958
959        self.old_managed.append(&mut self.new_managed);
960
961        Ok(())
962    }
963}
964
965impl<'a, R: Relocation> Extend<u8> for Modifier<'a,R> {
966    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
967        for (src, dst) in iter.into_iter().zip(self.buffer[self.asmoffset ..].iter_mut()) {
968            *dst = src;
969            self.asmoffset += 1;
970        }
971    }
972}
973
974impl<'a, 'b, R: Relocation> Extend<&'b u8> for Modifier<'a, R> {
975    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'b u8> {
976        for (src, dst) in iter.into_iter().zip(self.buffer[self.asmoffset ..].iter_mut()) {
977            *dst = *src;
978            self.asmoffset += 1;
979        }
980    }
981}
982
983impl<'a, R: Relocation> DynasmApi for Modifier<'a, R> {
984    fn offset(&self) -> AssemblyOffset {
985        AssemblyOffset(self.asmoffset)
986    }
987
988    fn push(&mut self, value: u8) {
989        self.buffer[self.asmoffset] = value;
990        self.asmoffset += 1
991    }
992
993    fn align(&mut self, alignment: usize, with: u8) {
994        let mismatch = self.asmoffset % alignment;
995        if mismatch != 0 {
996            for _ in mismatch .. alignment {
997                self.push(with)
998            }
999        }
1000    }
1001}
1002
1003impl<'a, R: Relocation> DynasmLabelApi for Modifier<'a, R> {
1004    type Relocation = R;
1005
1006    fn local_label(&mut self, name: &'static str) {
1007        let offset = self.offset();
1008        self.labels.define_local(name, offset);
1009    }
1010    fn global_label( &mut self, name: &'static str) {
1011        let offset = self.offset();
1012        if let Err(e) = self.labels.define_global(name, offset) {
1013            self.error = Some(e);
1014        }
1015    }
1016    fn dynamic_label(&mut self, id: DynamicLabel) {
1017        let offset = self.offset();
1018        if let Err(e) = self.labels.define_dynamic(id, offset) {
1019            self.error = Some(e);
1020        }
1021    }
1022    fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1023        let location = self.offset();
1024        let label = StaticLabel::global(name);
1025        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1026    }
1027    fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1028        let location = self.offset();
1029        self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1030    }
1031    fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1032        let location = self.offset();
1033        let label = match self.labels.place_local_reference(name) {
1034            Some(label) => label.next(),
1035            None => StaticLabel::first(name),
1036        };
1037        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1038    }
1039    fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1040        let location = self.offset();
1041        let label = match self.labels.place_local_reference(name) {
1042            Some(label) => label,
1043            None => {
1044                self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
1045                return;
1046            }
1047        };
1048        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1049    }
1050    fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
1051        let location = self.offset();
1052        let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
1053            let buf_addr = self.buffer.as_ptr() as usize;
1054        let buf = &mut self.buffer[loc.range(0)];
1055        if loc.patch(buf, buf_addr, target).is_err() {
1056            self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)));
1057        } else if loc.needs_adjustment() {
1058            self.new_managed.add(loc)
1059        }
1060    }
1061}
1062
1063
1064/// This struct is a wrapper around an `Assembler` normally created using the
1065/// `Assembler.alter_uncommitted` method. It allows the user to edit parts
1066/// of the assembling buffer that cannot be determined easily or efficiently
1067/// in advance. Due to limitations of the label resolution algorithms, this
1068/// assembler does not allow labels to be used.
1069#[derive(Debug)]
1070pub struct UncommittedModifier<'a> {
1071    buffer: &'a mut Vec<u8>,
1072    base_offset: usize,
1073    offset: usize
1074}
1075
1076impl<'a> UncommittedModifier<'a> {
1077    /// create a new uncommittedmodifier
1078    pub fn new(buffer: &mut Vec<u8>, base_offset: AssemblyOffset) -> UncommittedModifier<'_> {
1079        UncommittedModifier {
1080            buffer,
1081            base_offset: base_offset.0,
1082            offset: base_offset.0
1083        }
1084    }
1085
1086    /// Sets the current modification offset to the given value
1087    pub fn goto(&mut self, offset: AssemblyOffset) {
1088        self.offset = offset.0;
1089    }
1090
1091    /// Checks that the current modification offset is not larger than the specified offset.
1092    pub fn check(&mut self, offset: AssemblyOffset) -> Result<(), DynasmError> {
1093        if self.offset > offset.0 {
1094            Err(DynasmError::CheckFailed)
1095        } else {
1096            Ok(())
1097        }
1098    }
1099
1100    /// Checks that the current modification offset is exactly the specified offset.
1101    pub fn check_exact(&mut self, offset: AssemblyOffset) -> Result<(), DynasmError> {
1102        if self.offset != offset.0 {
1103            Err(DynasmError::CheckFailed)
1104        } else {
1105            Ok(())
1106        }
1107    }
1108}
1109
1110impl<'a> DynasmApi for UncommittedModifier<'a> {
1111    fn offset(&self) -> AssemblyOffset {
1112        AssemblyOffset(self.offset)
1113    }
1114
1115    fn push(&mut self, value: u8) {
1116        self.buffer[self.offset - self.base_offset] = value;
1117        self.offset += 1;
1118    }
1119
1120    fn align(&mut self, alignment: usize, with: u8) {
1121        let mismatch = self.offset % alignment;
1122        if mismatch != 0 {
1123            for _ in mismatch .. alignment {
1124                self.push(with)
1125            }
1126        }
1127    }
1128}
1129
1130impl<'a> Extend<u8> for UncommittedModifier<'a> {
1131    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
1132        for i in iter {
1133            self.push(i)
1134        }
1135    }
1136}
1137
1138impl<'a, 'b> Extend<&'b u8> for UncommittedModifier<'a> {
1139    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'b u8> {
1140        self.extend(iter.into_iter().cloned())
1141    }
1142}
1143
1144/// A trait abstracting over architectural register families. This is usually implemented
1145/// over an enum of all available registers in each family. This allows for code that is generic
1146/// over register families.
1147pub trait Register: Debug + Clone + Copy + PartialEq + Eq + Hash {
1148    /// Returns the integer ID of the register. Usually equivalent to casting
1149    /// the enum to an u8, but allows you to be generic over the register family.
1150    fn code(&self) -> u8;
1151}