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 dynamic label ID
587    pub fn new_dynamic_label(&mut self) -> DynamicLabel {
588        self.labels.new_dynamic_label()
589    }
590
591    /// Use an `UncommittedModifier` to alter uncommitted code.
592    /// This does not allow the user to change labels/relocations.
593    pub fn alter_uncommitted(&mut self) -> UncommittedModifier {
594        let offset = self.memory.committed();
595        UncommittedModifier::new(&mut self.ops, AssemblyOffset(offset))
596    }
597
598    /// Use a `Modifier` to alter committed code directly. While this is happening
599    /// no code can be executed as the relevant pages are remapped as writable.
600    /// This API supports defining new labels/relocations, and overwriting previously defined relocations.
601    pub fn alter<F, O>(&mut self, f: F) -> Result<O, DynasmError>
602    where F: FnOnce(&mut Modifier<R>) -> O {
603        self.commit()?;
604
605        // swap out a buffer from base
606        let mut lock = self.memory.write();
607        let buffer = mem::replace(&mut *lock, ExecutableBuffer::default());
608        let mut buffer = buffer.make_mut().expect("Could not swap buffer protection modes");
609
610        // construct the modifier
611        let mut modifier = Modifier {
612            asmoffset: 0,
613            previous_asmoffset: 0,
614            buffer: &mut buffer,
615
616            labels: &mut self.labels,
617            relocs: &mut self.relocs,
618            old_managed: &mut self.managed,
619            new_managed: ManagedRelocs::new(),
620
621            error: None
622        };
623
624        // execute the user code
625        let output = f(&mut modifier);
626
627        // flush any changes made by the user code to the buffer
628        modifier.encode_relocs()?;
629
630        // repack the buffer
631        let buffer = buffer.make_exec().expect("Could not swap buffer protection modes");
632        *lock = buffer;
633
634        // call it a day
635        Ok(output)
636    }
637
638    /// Commit code, flushing the temporary internal assembling buffer to the mapped executable memory.
639    /// This makes assembled code available for execution.
640    pub fn commit(&mut self) -> Result<(), DynasmError> {
641        self.encode_relocs()?;
642
643        let managed = &self.managed;
644        let error = &mut self.error;
645
646        self.memory.commit(&mut self.ops, |buffer, old_addr, new_addr| {
647            let change = new_addr.wrapping_sub(old_addr) as isize;
648
649            for reloc in managed.iter() {
650                let buf = &mut buffer[reloc.range(0)];
651                if reloc.adjust(buf, change).is_err() {
652                    *error = Some(DynasmError::ImpossibleRelocation(TargetKind::Managed))
653                }
654
655                // we don't need to inform the cache here that we changed something
656                // as the entire allocation is new.
657            }
658        });
659
660        if let Some(e) = self.error.take() {
661            return Err(e);
662        }
663        Ok(())
664    }
665
666    /// Finalize this assembler, returning the internal `ExecutableBuffer` if no `Executor` instances exist.
667    /// This panics if any uncommitted changes caused errors near the end. To handle these, call `commit()` explicitly beforehand.
668    pub fn finalize(mut self) -> Result<ExecutableBuffer, Self> {
669        self.commit().expect("Errors were encountered when committing before finalization");
670        match self.memory.finalize() {
671            Ok(execbuffer) => {
672                cache_control::prepare_for_execution(&execbuffer);
673                Ok(execbuffer)
674            },
675            Err(memory) => Err(Self {
676                memory,
677                ..self
678            })
679        }
680    }
681
682    /// Create an executor which can be used to execute code while still assembling code
683    pub fn reader(&self) -> Executor {
684        Executor {
685            execbuffer: self.memory.reader()
686        }
687    }
688
689    /// Provides access to the assemblers internal labels registry
690    pub fn labels(&self) -> &LabelRegistry {
691        &self.labels
692    }
693
694    /// Provides mutable access to the assemblers internal labels registry
695    pub fn labels_mut(&mut self) -> &mut LabelRegistry {
696        &mut self.labels
697    }
698
699    // encode uncommited relocations
700    fn encode_relocs(&mut self) -> Result<(), DynasmError> {
701        let buf_offset = self.memory.committed();
702        let buf_addr = self.memory.execbuffer_addr();
703        let buf = &mut self.ops;
704
705        // If we accrued any errors while assembling before, emit them now.
706        if let Some(e) = self.error.take() {
707            return Err(e);
708        }
709
710        // Resolve statics
711        for (loc, label) in self.relocs.take_statics() {
712            let target = self.labels.resolve_static(&label)?;
713            let buf = &mut buf[loc.range(buf_offset)];
714            if loc.patch(buf, buf_addr, target.0).is_err() {
715                return Err(DynasmError::ImpossibleRelocation(
716                    if label.is_global() {
717                        TargetKind::Global(label.get_name())
718                    } else {
719                        TargetKind::Local(label.get_name())
720                    }
721                ));
722            }
723            if loc.needs_adjustment() {
724                self.managed.add(loc)
725            }
726        }
727
728        // Resolve dynamics
729        for (loc, id) in self.relocs.take_dynamics() {
730            let target = self.labels.resolve_dynamic(id)?;
731            let buf = &mut buf[loc.range(buf_offset)];
732            if loc.patch(buf, buf_addr, target.0).is_err() {
733                return Err(DynasmError::ImpossibleRelocation(TargetKind::Dynamic(id)));
734            }
735            if loc.needs_adjustment() {
736                self.managed.add(loc)
737            }
738        }
739
740        Ok(())
741    }
742}
743
744impl<R: Relocation> Extend<u8> for Assembler<R> {
745    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
746        self.ops.extend(iter)
747    }
748}
749
750impl<'a, R: Relocation> Extend<&'a u8> for Assembler<R> {
751    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'a u8> {
752        self.ops.extend(iter)
753    }
754}
755
756impl<R: Relocation> DynasmApi for Assembler<R> {
757    fn offset(&self) -> AssemblyOffset {
758        AssemblyOffset(self.memory.committed() + self.ops.len())
759    }
760
761    fn push(&mut self, value: u8) {
762        self.ops.push(value);
763    }
764
765    fn align(&mut self, alignment: usize, with: u8) {
766        let misalign = self.offset().0 % alignment;
767        if misalign != 0 {
768            for _ in misalign .. alignment {
769                self.push(with);
770            }
771        }
772    }
773}
774
775impl<R: Relocation> DynasmLabelApi for Assembler<R> {
776    type Relocation = R;
777
778    fn local_label(&mut self, name: &'static str) {
779        let offset = self.offset();
780        self.labels.define_local(name, offset);
781    }
782    fn global_label( &mut self, name: &'static str) {
783        let offset = self.offset();
784        if let Err(e) = self.labels.define_global(name, offset) {
785            self.error = Some(e)
786        }
787    }
788    fn dynamic_label(&mut self, id: DynamicLabel) {
789        let offset = self.offset();
790        if let Err(e) = self.labels.define_dynamic(id, offset) {
791            self.error = Some(e)
792        }
793    }
794    fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
795        let location = self.offset();
796        let label = StaticLabel::global(name);
797        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
798    }
799    fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
800        let location = self.offset();
801        self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
802    }
803    fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
804        let location = self.offset();
805        let label = match self.labels.place_local_reference(name) {
806            Some(label) => label.next(),
807            None => StaticLabel::first(name),
808        };
809        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
810    }
811    fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
812        let location = self.offset();
813        let label = match self.labels.place_local_reference(name) {
814            Some(label) => label,
815            None => {
816                self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
817                return;
818            }
819        };
820        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
821    }
822    fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
823        let location = self.offset();
824        let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
825        let buf = &mut self.ops[loc.range(self.memory.committed())];
826        if loc.patch(buf, self.memory.execbuffer_addr(), target).is_err() {
827            self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)))
828        } else if loc.needs_adjustment() {
829            self.managed.add(loc)
830        }
831    }
832}
833
834
835/// Allows modification of already committed assembly code. Contains an internal cursor
836/// into the emitted assembly, initialized to the start, that can be moved around either with the
837/// `goto` function, or just by assembling new code into this `Modifier`.
838#[derive(Debug)]
839pub struct Modifier<'a, R: Relocation> {
840    asmoffset: usize,
841    previous_asmoffset: usize,
842    buffer: &'a mut [u8],
843
844    labels: &'a mut LabelRegistry,
845    relocs: &'a mut RelocRegistry<R>,
846    old_managed: &'a mut ManagedRelocs<R>,
847    new_managed: ManagedRelocs<R>,
848
849    error: Option<DynasmError>
850}
851
852impl<'a, R: Relocation> Modifier<'a, R> {
853    /// Move the modifier cursor to the selected location.
854    pub fn goto(&mut self, offset: AssemblyOffset) {
855        // resync the caches of anything we modified before
856        cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
857
858        // remove any old managed relocations from what we overwrote
859        self.old_managed.remove_between(self.previous_asmoffset, self.asmoffset);
860
861        // set the cursor position
862        self.asmoffset = offset.0;
863        self.previous_asmoffset = offset.0;
864    }
865
866    /// Check that the modifier cursor has not moved past the specified location.
867    pub fn check(&self, offset: AssemblyOffset) -> Result<(), DynasmError> {
868        if self.asmoffset > offset.0 {
869            Err(DynasmError::CheckFailed)
870        } else {
871            Ok(())
872        }
873    }
874
875    /// Check that the modifier cursor is exactly at the specified location.
876    pub fn check_exact(&self, offset: AssemblyOffset) -> Result<(), DynasmError> {
877        if self.asmoffset != offset.0 {
878            Err(DynasmError::CheckFailed)
879        } else {
880            Ok(())
881        }
882    }
883
884    // encode uncommited relocations. also, invalidate the icache
885    fn encode_relocs(&mut self) -> Result<(), DynasmError> {
886        let buf_addr = self.buffer.as_ptr() as usize;
887
888        // resync the caches of anything we modified before
889        cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
890
891        // If we accrued any errors while assembling before, emit them now.
892        if let Some(e) = self.error.take() {
893            return Err(e);
894        }
895
896        // Resolve statics
897        for (loc, label) in self.relocs.take_statics() {
898            let target = self.labels.resolve_static(&label)?;
899            let buf = &mut self.buffer[loc.range(0)];
900            if loc.patch(buf, buf_addr, target.0).is_err() {
901                return Err(DynasmError::ImpossibleRelocation(
902                    if label.is_global() {
903                        TargetKind::Global(label.get_name())
904                    } else {
905                        TargetKind::Local(label.get_name())
906                    }
907                ));
908            }
909
910            // resynchronize the cache of any relocation we just performed
911            cache_control::synchronize_icache(buf);
912
913            if loc.needs_adjustment() {
914                self.new_managed.add(loc);
915            }
916        }
917
918        // Resolve dynamics
919        for (loc, id) in self.relocs.take_dynamics() {
920            let target = self.labels.resolve_dynamic(id)?;
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(TargetKind::Dynamic(id)));
924            }
925
926            // resynchronize the cache of any relocation we just performed
927            cache_control::synchronize_icache(buf);
928
929            if loc.needs_adjustment() {
930                self.new_managed.add(loc);
931            }
932        }
933
934        self.old_managed.remove_between(self.previous_asmoffset, self.asmoffset);
935        self.previous_asmoffset = self.asmoffset;
936
937        self.old_managed.append(&mut self.new_managed);
938
939        Ok(())
940    }
941}
942
943impl<'a, R: Relocation> Extend<u8> for Modifier<'a,R> {
944    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
945        for (src, dst) in iter.into_iter().zip(self.buffer[self.asmoffset ..].iter_mut()) {
946            *dst = src;
947            self.asmoffset += 1;
948        }
949    }
950}
951
952impl<'a, 'b, R: Relocation> Extend<&'b u8> for Modifier<'a, R> {
953    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'b u8> {
954        for (src, dst) in iter.into_iter().zip(self.buffer[self.asmoffset ..].iter_mut()) {
955            *dst = *src;
956            self.asmoffset += 1;
957        }
958    }
959}
960
961impl<'a, R: Relocation> DynasmApi for Modifier<'a, R> {
962    fn offset(&self) -> AssemblyOffset {
963        AssemblyOffset(self.asmoffset)
964    }
965
966    fn push(&mut self, value: u8) {
967        self.buffer[self.asmoffset] = value;
968        self.asmoffset += 1
969    }
970
971    fn align(&mut self, alignment: usize, with: u8) {
972        let mismatch = self.asmoffset % alignment;
973        if mismatch != 0 {
974            for _ in mismatch .. alignment {
975                self.push(with)
976            }
977        }
978    }
979}
980
981impl<'a, R: Relocation> DynasmLabelApi for Modifier<'a, R> {
982    type Relocation = R;
983
984    fn local_label(&mut self, name: &'static str) {
985        let offset = self.offset();
986        self.labels.define_local(name, offset);
987    }
988    fn global_label( &mut self, name: &'static str) {
989        let offset = self.offset();
990        if let Err(e) = self.labels.define_global(name, offset) {
991            self.error = Some(e);
992        }
993    }
994    fn dynamic_label(&mut self, id: DynamicLabel) {
995        let offset = self.offset();
996        if let Err(e) = self.labels.define_dynamic(id, offset) {
997            self.error = Some(e);
998        }
999    }
1000    fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1001        let location = self.offset();
1002        let label = StaticLabel::global(name);
1003        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1004    }
1005    fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1006        let location = self.offset();
1007        self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1008    }
1009    fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1010        let location = self.offset();
1011        let label = match self.labels.place_local_reference(name) {
1012            Some(label) => label.next(),
1013            None => StaticLabel::first(name),
1014        };
1015        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1016    }
1017    fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
1018        let location = self.offset();
1019        let label = match self.labels.place_local_reference(name) {
1020            Some(label) => label,
1021            None => {
1022                self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
1023                return;
1024            }
1025        };
1026        self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
1027    }
1028    fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
1029        let location = self.offset();
1030        let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
1031            let buf_addr = self.buffer.as_ptr() as usize;
1032        let buf = &mut self.buffer[loc.range(0)];
1033        if loc.patch(buf, buf_addr, target).is_err() {
1034            self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)));
1035        } else if loc.needs_adjustment() {
1036            self.new_managed.add(loc)
1037        }
1038    }
1039}
1040
1041
1042/// This struct is a wrapper around an `Assembler` normally created using the
1043/// `Assembler.alter_uncommitted` method. It allows the user to edit parts
1044/// of the assembling buffer that cannot be determined easily or efficiently
1045/// in advance. Due to limitations of the label resolution algorithms, this
1046/// assembler does not allow labels to be used.
1047#[derive(Debug)]
1048pub struct UncommittedModifier<'a> {
1049    buffer: &'a mut Vec<u8>,
1050    base_offset: usize,
1051    offset: usize
1052}
1053
1054impl<'a> UncommittedModifier<'a> {
1055    /// create a new uncommittedmodifier
1056    pub fn new(buffer: &mut Vec<u8>, base_offset: AssemblyOffset) -> UncommittedModifier {
1057        UncommittedModifier {
1058            buffer,
1059            base_offset: base_offset.0,
1060            offset: base_offset.0
1061        }
1062    }
1063
1064    /// Sets the current modification offset to the given value
1065    pub fn goto(&mut self, offset: AssemblyOffset) {
1066        self.offset = offset.0;
1067    }
1068
1069    /// Checks that the current modification offset is not larger than the specified offset.
1070    pub fn check(&mut self, offset: AssemblyOffset) -> Result<(), DynasmError> {
1071        if self.offset > offset.0 {
1072            Err(DynasmError::CheckFailed)
1073        } else {
1074            Ok(())
1075        }
1076    }
1077
1078    /// Checks that the current modification offset is exactly the specified offset.
1079    pub fn check_exact(&mut self, offset: AssemblyOffset) -> Result<(), DynasmError> {
1080        if self.offset != offset.0 {
1081            Err(DynasmError::CheckFailed)
1082        } else {
1083            Ok(())
1084        }
1085    }
1086}
1087
1088impl<'a> DynasmApi for UncommittedModifier<'a> {
1089    fn offset(&self) -> AssemblyOffset {
1090        AssemblyOffset(self.offset)
1091    }
1092
1093    fn push(&mut self, value: u8) {
1094        self.buffer[self.offset - self.base_offset] = value;
1095        self.offset += 1;
1096    }
1097
1098    fn align(&mut self, alignment: usize, with: u8) {
1099        let mismatch = self.offset % alignment;
1100        if mismatch != 0 {
1101            for _ in mismatch .. alignment {
1102                self.push(with)
1103            }
1104        }
1105    }
1106}
1107
1108impl<'a> Extend<u8> for UncommittedModifier<'a> {
1109    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
1110        for i in iter {
1111            self.push(i)
1112        }
1113    }
1114}
1115
1116impl<'a, 'b> Extend<&'b u8> for UncommittedModifier<'a> {
1117    fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'b u8> {
1118        self.extend(iter.into_iter().cloned())
1119    }
1120}
1121
1122/// A trait abstracting over architectural register families. This is usually implemented
1123/// over an enum of all available registers in each family. This allows for code that is generic
1124/// over register families.
1125pub trait Register: Debug + Clone + Copy + PartialEq + Eq + Hash {
1126    /// Returns the integer ID of the register. Usually equivalent to casting
1127    /// the enum to an u8, but allows you to be generic over the register family.
1128    fn code(&self) -> u8;
1129}