1#![warn(missing_docs)]
2
3pub mod mmap;
8pub mod components;
9pub mod relocations;
10pub mod cache_control;
11
12macro_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#[macro_export]
50macro_rules! Pointer {
51 ($e:expr) => {$e as *const _ as _};
52}
53
54#[macro_export]
56macro_rules! MutPointer {
57 ($e:expr) => {$e as *mut _ as _};
58}
59
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
64pub struct AssemblyOffset(pub usize);
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68pub struct DynamicLabel(usize);
69
70
71impl DynamicLabel {
72 pub fn get_id(self) -> usize {
74 self.0
75 }
76}
77
78
79#[derive(Debug, Clone)]
82pub struct Executor {
83 execbuffer: Arc<RwLock<ExecutableBuffer>>
84}
85
86impl Executor {
89 #[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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
104pub enum LabelKind {
105 Local(&'static str),
107 Global(&'static str),
109 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126pub enum TargetKind {
127 Local(&'static str),
129 Global(&'static str),
131 Dynamic(DynamicLabel),
133 Extern(usize),
135 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#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum DynasmError {
155 CheckFailed,
157 DuplicateLabel(LabelKind),
159 UnknownLabel(LabelKind),
161 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
188pub trait DynasmApi: Extend<u8> + for<'a> Extend<&'a u8> {
191 fn offset(&self) -> AssemblyOffset;
193 fn push(&mut self, byte: u8);
195 fn align(&mut self, alignment: usize, with: u8);
197
198 #[inline]
199 fn push_i8(&mut self, value: i8) {
201 self.push(value as u8);
202 }
203 #[inline]
205 fn push_i16(&mut self, value: i16) {
206 self.extend(&value.to_le_bytes());
207 }
208 #[inline]
210 fn push_i32(&mut self, value: i32) {
211 self.extend(&value.to_le_bytes());
212 }
213 #[inline]
215 fn push_i64(&mut self, value: i64) {
216 self.extend(&value.to_le_bytes());
217 }
218 #[inline]
220 fn push_u16(&mut self, value: u16) {
221 self.extend(&value.to_le_bytes());
222 }
223 #[inline]
225 fn push_u32(&mut self, value: u32) {
226 self.extend(&value.to_le_bytes());
227 }
228 #[inline]
230 fn push_u64(&mut self, value: u64) {
231 self.extend(&value.to_le_bytes());
232 }
233 #[inline]
235 fn runtime_error(&self, msg: &'static str) -> ! {
236 panic!("{}", msg);
237 }
238}
239
240pub trait DynasmLabelApi : DynasmApi {
245 type Relocation: Relocation;
247
248 fn local_label( &mut self, name: &'static str);
250 fn global_label( &mut self, name: &'static str);
252 fn dynamic_label(&mut self, id: DynamicLabel);
254
255 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 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 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 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 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 fn forward_relocation( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
278 fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
280 fn global_relocation( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
282 fn dynamic_relocation( &mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
284 fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
286}
287
288
289#[derive(Debug, Clone)]
292pub struct SimpleAssembler {
293 pub ops: Vec<u8>
295}
296
297impl SimpleAssembler {
298 pub fn new() -> SimpleAssembler {
300 SimpleAssembler {
301 ops: Vec::new()
302 }
303 }
304
305 pub fn alter(&mut self) -> UncommittedModifier {
307 UncommittedModifier::new(&mut self.ops, AssemblyOffset(0))
308 }
309
310 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#[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 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 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 pub fn reserve_ops(&mut self, additional: usize) {
392 self.ops.reserve(additional);
393 }
394
395 pub fn new_dynamic_label(&mut self) -> DynamicLabel {
397 self.labels.new_dynamic_label()
398 }
399
400 pub fn commit(&mut self) -> Result<(), DynasmError> {
403 if let Some(e) = self.error.take() {
405 return Err(e);
406 }
407
408 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 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 pub fn alter(&mut self) -> UncommittedModifier {
438 UncommittedModifier::new(&mut self.ops, AssemblyOffset(0))
439 }
440
441 pub fn labels(&self) -> &LabelRegistry {
443 &self.labels
444 }
445
446 pub fn labels_mut(&mut self) -> &mut LabelRegistry {
448 &mut self.labels
449 }
450
451 pub fn finalize(mut self) -> Result<Vec<u8>, DynasmError> {
454 self.commit()?;
455 Ok(self.ops)
456 }
457
458 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 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#[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 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 pub fn new_dynamic_label(&mut self) -> DynamicLabel {
588 self.labels.new_dynamic_label()
589 }
590
591 pub fn alter_uncommitted(&mut self) -> UncommittedModifier {
594 let offset = self.memory.committed();
595 UncommittedModifier::new(&mut self.ops, AssemblyOffset(offset))
596 }
597
598 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 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 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 let output = f(&mut modifier);
626
627 modifier.encode_relocs()?;
629
630 let buffer = buffer.make_exec().expect("Could not swap buffer protection modes");
632 *lock = buffer;
633
634 Ok(output)
636 }
637
638 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 }
658 });
659
660 if let Some(e) = self.error.take() {
661 return Err(e);
662 }
663 Ok(())
664 }
665
666 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 pub fn reader(&self) -> Executor {
684 Executor {
685 execbuffer: self.memory.reader()
686 }
687 }
688
689 pub fn labels(&self) -> &LabelRegistry {
691 &self.labels
692 }
693
694 pub fn labels_mut(&mut self) -> &mut LabelRegistry {
696 &mut self.labels
697 }
698
699 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 let Some(e) = self.error.take() {
707 return Err(e);
708 }
709
710 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 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#[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 pub fn goto(&mut self, offset: AssemblyOffset) {
855 cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
857
858 self.old_managed.remove_between(self.previous_asmoffset, self.asmoffset);
860
861 self.asmoffset = offset.0;
863 self.previous_asmoffset = offset.0;
864 }
865
866 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 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 fn encode_relocs(&mut self) -> Result<(), DynasmError> {
886 let buf_addr = self.buffer.as_ptr() as usize;
887
888 cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
890
891 if let Some(e) = self.error.take() {
893 return Err(e);
894 }
895
896 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 cache_control::synchronize_icache(buf);
912
913 if loc.needs_adjustment() {
914 self.new_managed.add(loc);
915 }
916 }
917
918 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 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#[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 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 pub fn goto(&mut self, offset: AssemblyOffset) {
1066 self.offset = offset.0;
1067 }
1068
1069 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 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
1122pub trait Register: Debug + Clone + Copy + PartialEq + Eq + Hash {
1126 fn code(&self) -> u8;
1129}