#![warn(missing_docs)]
pub mod mmap;
pub mod components;
pub mod relocations;
pub mod cache_control;
macro_rules! reg_impls {
($r:ty) => {
impl $crate::Register for $r {
fn code(&self) -> u8 {
*self as u8
}
}
impl From<$r> for u8 {
fn from(rq: $r) -> u8 {
rq.code()
}
}
}
}
pub mod x64;
pub mod x86;
pub mod aarch64;
pub use crate::mmap::ExecutableBuffer;
pub use dynasm::{dynasm, dynasm_backwards};
use crate::components::{MemoryManager, LabelRegistry, RelocRegistry, ManagedRelocs, PatchLoc, StaticLabel};
use crate::relocations::Relocation;
use std::hash::Hash;
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::io;
use std::error;
use std::fmt::{self, Debug};
use std::mem;
#[macro_export]
macro_rules! Pointer {
($e:expr) => {$e as *const _ as _};
}
#[macro_export]
macro_rules! MutPointer {
($e:expr) => {$e as *mut _ as _};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AssemblyOffset(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DynamicLabel(usize);
impl DynamicLabel {
pub fn get_id(self) -> usize {
self.0
}
}
#[derive(Debug, Clone)]
pub struct Executor {
execbuffer: Arc<RwLock<ExecutableBuffer>>
}
impl Executor {
#[inline]
pub fn lock(&self) -> RwLockReadGuard<ExecutableBuffer> {
let guard = self.execbuffer.read().unwrap();
cache_control::prepare_for_execution();
guard
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LabelKind {
Local(&'static str),
Global(&'static str),
Dynamic(DynamicLabel)
}
impl fmt::Display for LabelKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Local(s) => write!(f, "label {}", s),
Self::Global(s) => write!(f, "label ->{}", s),
Self::Dynamic(id) => write!(f, "label =>{}", id.get_id())
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TargetKind {
Local(&'static str),
Global(&'static str),
Dynamic(DynamicLabel),
Extern(usize),
Managed,
}
impl fmt::Display for TargetKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Local(s) => write!(f, "target [><]{}", s),
Self::Global(s) => write!(f, "target ->{}", s),
Self::Dynamic(id) => write!(f, "target =>{}", id.get_id()),
Self::Extern(value) => write!(f, "target extern {}", value),
Self::Managed => write!(f, "while adjusting managed relocation"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DynasmError {
CheckFailed,
DuplicateLabel(LabelKind),
UnknownLabel(LabelKind),
ImpossibleRelocation(TargetKind),
}
impl fmt::Display for DynasmError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DynasmError::CheckFailed => write!(f, "An assembly modification check failed"),
DynasmError::DuplicateLabel(l) => write!(f, "Duplicate label defined: '{}'", l),
DynasmError::UnknownLabel(l) => write!(f, "Unknown label: '{}'", l),
DynasmError::ImpossibleRelocation(s) => write!(f, "Impossible relocation: '{}'", s),
}
}
}
impl error::Error for DynasmError {
fn description(&self) -> &str {
match self {
DynasmError::CheckFailed => "An assembly modification offset check failed",
DynasmError::DuplicateLabel(_) => "Duplicate label defined",
DynasmError::UnknownLabel(_) => "Unknown label",
DynasmError::ImpossibleRelocation(_) => "Impossible relocation",
}
}
}
pub trait DynasmApi: Extend<u8> + for<'a> Extend<&'a u8> {
fn offset(&self) -> AssemblyOffset;
fn push(&mut self, byte: u8);
fn align(&mut self, alignment: usize, with: u8);
#[inline]
fn push_i8(&mut self, value: i8) {
self.push(value as u8);
}
#[inline]
fn push_i16(&mut self, value: i16) {
self.extend(&value.to_le_bytes());
}
#[inline]
fn push_i32(&mut self, value: i32) {
self.extend(&value.to_le_bytes());
}
#[inline]
fn push_i64(&mut self, value: i64) {
self.extend(&value.to_le_bytes());
}
#[inline]
fn push_u16(&mut self, value: u16) {
self.extend(&value.to_le_bytes());
}
#[inline]
fn push_u32(&mut self, value: u32) {
self.extend(&value.to_le_bytes());
}
#[inline]
fn push_u64(&mut self, value: u64) {
self.extend(&value.to_le_bytes());
}
#[inline]
fn runtime_error(&self, msg: &'static str) -> ! {
panic!("{}", msg);
}
}
pub trait DynasmLabelApi : DynasmApi {
type Relocation: Relocation;
fn local_label( &mut self, name: &'static str);
fn global_label( &mut self, name: &'static str);
fn dynamic_label(&mut self, id: DynamicLabel);
fn forward_reloc( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
self.forward_relocation(name, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
}
fn backward_reloc(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
self.backward_relocation(name, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
}
fn global_reloc( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
self.global_relocation(name, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
}
fn dynamic_reloc( &mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
self.dynamic_relocation(id, target_offset, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
}
fn bare_reloc(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: <Self::Relocation as Relocation>::Encoding) {
self.bare_relocation(target, field_offset, ref_offset, Self::Relocation::from_encoding(kind))
}
fn forward_relocation( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
fn global_relocation( &mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
fn dynamic_relocation( &mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: Self::Relocation);
}
#[derive(Debug, Clone)]
pub struct SimpleAssembler {
pub ops: Vec<u8>
}
impl SimpleAssembler {
pub fn new() -> SimpleAssembler {
SimpleAssembler {
ops: Vec::new()
}
}
pub fn alter(&mut self) -> UncommittedModifier {
UncommittedModifier::new(&mut self.ops, AssemblyOffset(0))
}
pub fn finalize(self) -> Vec<u8> {
self.ops
}
}
impl Extend<u8> for SimpleAssembler {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
self.ops.extend(iter)
}
}
impl<'a> Extend<&'a u8> for SimpleAssembler {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'a u8> {
self.ops.extend(iter)
}
}
impl DynasmApi for SimpleAssembler {
fn offset(&self) -> AssemblyOffset {
AssemblyOffset(self.ops.len())
}
fn push(&mut self, byte: u8) {
self.ops.push(byte);
}
fn align(&mut self, alignment: usize, with: u8) {
let offset = self.offset().0 % alignment;
if offset != 0 {
for _ in offset .. alignment {
self.push(with);
}
}
}
}
#[derive(Debug)]
pub struct VecAssembler<R: Relocation> {
ops: Vec<u8>,
baseaddr: usize,
labels: LabelRegistry,
relocs: RelocRegistry<R>,
error: Option<DynasmError>,
}
impl<R: Relocation> VecAssembler<R> {
pub fn new(baseaddr: usize) -> VecAssembler<R> {
VecAssembler {
ops: Vec::new(),
baseaddr,
labels: LabelRegistry::new(),
relocs: RelocRegistry::new(),
error: None
}
}
pub fn new_with_capacity(baseaddr: usize, ops_capacity: usize,
local_labels: usize, global_labels: usize, dynamic_labels: usize,
static_references: usize, dynamic_references: usize) -> VecAssembler<R> {
VecAssembler {
ops: Vec::with_capacity(ops_capacity),
baseaddr,
labels: LabelRegistry::with_capacity(local_labels, global_labels, dynamic_labels),
relocs: RelocRegistry::with_capacity(static_references, dynamic_references),
error: None
}
}
pub fn reserve_ops(&mut self, additional: usize) {
self.ops.reserve(additional);
}
pub fn new_dynamic_label(&mut self) -> DynamicLabel {
self.labels.new_dynamic_label()
}
pub fn commit(&mut self) -> Result<(), DynasmError> {
if let Some(e) = self.error.take() {
return Err(e);
}
for (loc, label) in self.relocs.take_statics() {
let target = self.labels.resolve_static(&label)?;
let buf = &mut self.ops[loc.range(0)];
if loc.patch(buf, self.baseaddr, target.0).is_err() {
return Err(DynasmError::ImpossibleRelocation(
if label.is_global() {
TargetKind::Global(label.get_name())
} else {
TargetKind::Local(label.get_name())
}
));
}
}
for (loc, id) in self.relocs.take_dynamics() {
let target = self.labels.resolve_dynamic(id)?;
let buf = &mut self.ops[loc.range(0)];
if loc.patch(buf, self.baseaddr, target.0).is_err() {
return Err(DynasmError::ImpossibleRelocation(TargetKind::Dynamic(id)));
}
}
Ok(())
}
pub fn alter(&mut self) -> UncommittedModifier {
UncommittedModifier::new(&mut self.ops, AssemblyOffset(0))
}
pub fn labels(&self) -> &LabelRegistry {
&self.labels
}
pub fn labels_mut(&mut self) -> &mut LabelRegistry {
&mut self.labels
}
pub fn finalize(mut self) -> Result<Vec<u8>, DynasmError> {
self.commit()?;
Ok(self.ops)
}
pub fn take(&mut self) -> Result<Vec<u8>, DynasmError> {
self.commit()?;
self.labels.clear();
Ok(std::mem::take(&mut self.ops))
}
pub fn drain<'a>(&'a mut self) -> Result<impl Iterator<Item=u8> + 'a, DynasmError> {
self.commit()?;
self.labels.clear();
Ok(self.ops.drain(..))
}
}
impl<R: Relocation> Extend<u8> for VecAssembler<R> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
self.ops.extend(iter)
}
}
impl<'a, R: Relocation> Extend<&'a u8> for VecAssembler<R> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'a u8> {
self.ops.extend(iter)
}
}
impl<R: Relocation> DynasmApi for VecAssembler<R> {
fn offset(&self) -> AssemblyOffset {
AssemblyOffset(self.ops.len())
}
fn push(&mut self, byte: u8) {
self.ops.push(byte);
}
fn align(&mut self, alignment: usize, with: u8) {
let offset = self.offset().0 % alignment;
if offset != 0 {
for _ in offset .. alignment {
self.push(with);
}
}
}
}
impl<R: Relocation> DynasmLabelApi for VecAssembler<R> {
type Relocation = R;
fn local_label(&mut self, name: &'static str) {
let offset = self.offset();
self.labels.define_local(name, offset);
}
fn global_label( &mut self, name: &'static str) {
let offset = self.offset();
if let Err(e) = self.labels.define_global(name, offset) {
self.error = Some(e)
}
}
fn dynamic_label(&mut self, id: DynamicLabel) {
let offset = self.offset();
if let Err(e) = self.labels.define_dynamic(id, offset) {
self.error = Some(e)
}
}
fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = StaticLabel::global(name);
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = match self.labels.place_local_reference(name) {
Some(label) => label.next(),
None => StaticLabel::first(name),
};
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = match self.labels.place_local_reference(name) {
Some(label) => label,
None => {
self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
return;
}
};
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
let buf = &mut self.ops[loc.range(0)];
if loc.patch(buf, self.baseaddr, target).is_err() {
self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)))
}
}
}
#[derive(Debug)]
pub struct Assembler<R: Relocation> {
ops: Vec<u8>,
memory: MemoryManager,
labels: LabelRegistry,
relocs: RelocRegistry<R>,
managed: ManagedRelocs<R>,
error: Option<DynasmError>,
}
impl<R: Relocation> Assembler<R> {
pub fn new() -> io::Result<Self> {
Ok(Self {
ops: Vec::new(),
memory: MemoryManager::new(R::page_size())?,
labels: LabelRegistry::new(),
relocs: RelocRegistry::new(),
managed: ManagedRelocs::new(),
error: None
})
}
pub fn new_dynamic_label(&mut self) -> DynamicLabel {
self.labels.new_dynamic_label()
}
pub fn alter_uncommitted(&mut self) -> UncommittedModifier {
let offset = self.memory.committed();
UncommittedModifier::new(&mut self.ops, AssemblyOffset(offset))
}
pub fn alter<F, O>(&mut self, f: F) -> Result<O, DynasmError>
where F: FnOnce(&mut Modifier<R>) -> O {
self.commit()?;
let mut lock = self.memory.write();
let buffer = mem::replace(&mut *lock, ExecutableBuffer::default());
let mut buffer = buffer.make_mut().expect("Could not swap buffer protection modes");
let mut modifier = Modifier {
asmoffset: 0,
previous_asmoffset: 0,
buffer: &mut *buffer,
labels: &mut self.labels,
relocs: &mut self.relocs,
old_managed: &mut self.managed,
new_managed: ManagedRelocs::new(),
error: None
};
let output = f(&mut modifier);
modifier.encode_relocs()?;
let buffer = buffer.make_exec().expect("Could not swap buffer protection modes");
*lock = buffer;
Ok(output)
}
pub fn commit(&mut self) -> Result<(), DynasmError> {
self.encode_relocs()?;
let managed = &self.managed;
let error = &mut self.error;
self.memory.commit(&mut self.ops, |buffer, old_addr, new_addr| {
let change = new_addr.wrapping_sub(old_addr) as isize;
for reloc in managed.iter() {
let buf = &mut buffer[reloc.range(0)];
if reloc.adjust(buf, change).is_err() {
*error = Some(DynasmError::ImpossibleRelocation(TargetKind::Managed))
}
}
});
if let Some(e) = self.error.take() {
return Err(e);
}
Ok(())
}
pub fn finalize(mut self) -> Result<ExecutableBuffer, Self> {
self.commit().expect("Errors were encountered when committing before finalization");
match self.memory.finalize() {
Ok(execbuffer) => {
cache_control::prepare_for_execution();
Ok(execbuffer)
},
Err(memory) => Err(Self {
memory,
..self
})
}
}
pub fn reader(&self) -> Executor {
Executor {
execbuffer: self.memory.reader()
}
}
pub fn labels(&self) -> &LabelRegistry {
&self.labels
}
pub fn labels_mut(&mut self) -> &mut LabelRegistry {
&mut self.labels
}
fn encode_relocs(&mut self) -> Result<(), DynasmError> {
let buf_offset = self.memory.committed();
let buf_addr = self.memory.execbuffer_addr();
let buf = &mut self.ops;
if let Some(e) = self.error.take() {
return Err(e);
}
for (loc, label) in self.relocs.take_statics() {
let target = self.labels.resolve_static(&label)?;
let buf = &mut buf[loc.range(buf_offset)];
if loc.patch(buf, buf_addr, target.0).is_err() {
return Err(DynasmError::ImpossibleRelocation(
if label.is_global() {
TargetKind::Global(label.get_name())
} else {
TargetKind::Local(label.get_name())
}
));
}
if loc.needs_adjustment() {
self.managed.add(loc)
}
}
for (loc, id) in self.relocs.take_dynamics() {
let target = self.labels.resolve_dynamic(id)?;
let buf = &mut buf[loc.range(buf_offset)];
if loc.patch(buf, buf_addr, target.0).is_err() {
return Err(DynasmError::ImpossibleRelocation(TargetKind::Dynamic(id)));
}
if loc.needs_adjustment() {
self.managed.add(loc)
}
}
Ok(())
}
}
impl<R: Relocation> Extend<u8> for Assembler<R> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
self.ops.extend(iter)
}
}
impl<'a, R: Relocation> Extend<&'a u8> for Assembler<R> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'a u8> {
self.ops.extend(iter)
}
}
impl<R: Relocation> DynasmApi for Assembler<R> {
fn offset(&self) -> AssemblyOffset {
AssemblyOffset(self.memory.committed() + self.ops.len())
}
fn push(&mut self, value: u8) {
self.ops.push(value);
}
fn align(&mut self, alignment: usize, with: u8) {
let misalign = self.offset().0 % alignment;
if misalign != 0 {
for _ in misalign .. alignment {
self.push(with);
}
}
}
}
impl<R: Relocation> DynasmLabelApi for Assembler<R> {
type Relocation = R;
fn local_label(&mut self, name: &'static str) {
let offset = self.offset();
self.labels.define_local(name, offset);
}
fn global_label( &mut self, name: &'static str) {
let offset = self.offset();
if let Err(e) = self.labels.define_global(name, offset) {
self.error = Some(e)
}
}
fn dynamic_label(&mut self, id: DynamicLabel) {
let offset = self.offset();
if let Err(e) = self.labels.define_dynamic(id, offset) {
self.error = Some(e)
}
}
fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = StaticLabel::global(name);
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = match self.labels.place_local_reference(name) {
Some(label) => label.next(),
None => StaticLabel::first(name),
};
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = match self.labels.place_local_reference(name) {
Some(label) => label,
None => {
self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
return;
}
};
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
let buf = &mut self.ops[loc.range(self.memory.committed())];
if loc.patch(buf, self.memory.execbuffer_addr(), target).is_err() {
self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)))
} else if loc.needs_adjustment() {
self.managed.add(loc)
}
}
}
#[derive(Debug)]
pub struct Modifier<'a, R: Relocation> {
asmoffset: usize,
previous_asmoffset: usize,
buffer: &'a mut [u8],
labels: &'a mut LabelRegistry,
relocs: &'a mut RelocRegistry<R>,
old_managed: &'a mut ManagedRelocs<R>,
new_managed: ManagedRelocs<R>,
error: Option<DynasmError>
}
impl<'a, R: Relocation> Modifier<'a, R> {
pub fn goto(&mut self, offset: AssemblyOffset) {
cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
self.old_managed.remove_between(self.previous_asmoffset, self.asmoffset);
self.asmoffset = offset.0;
self.previous_asmoffset = offset.0;
}
pub fn check(&self, offset: AssemblyOffset) -> Result<(), DynasmError> {
if self.asmoffset > offset.0 {
Err(DynasmError::CheckFailed)
} else {
Ok(())
}
}
pub fn check_exact(&self, offset: AssemblyOffset) -> Result<(), DynasmError> {
if self.asmoffset != offset.0 {
Err(DynasmError::CheckFailed)
} else {
Ok(())
}
}
fn encode_relocs(&mut self) -> Result<(), DynasmError> {
let buf_addr = self.buffer.as_ptr() as usize;
cache_control::synchronize_icache(&self.buffer[self.previous_asmoffset .. self.asmoffset]);
if let Some(e) = self.error.take() {
return Err(e);
}
for (loc, label) in self.relocs.take_statics() {
let target = self.labels.resolve_static(&label)?;
let buf = &mut self.buffer[loc.range(0)];
if loc.patch(buf, buf_addr, target.0).is_err() {
return Err(DynasmError::ImpossibleRelocation(
if label.is_global() {
TargetKind::Global(label.get_name())
} else {
TargetKind::Local(label.get_name())
}
));
}
cache_control::synchronize_icache(buf);
if loc.needs_adjustment() {
self.new_managed.add(loc);
}
}
for (loc, id) in self.relocs.take_dynamics() {
let target = self.labels.resolve_dynamic(id)?;
let buf = &mut self.buffer[loc.range(0)];
if loc.patch(buf, buf_addr, target.0).is_err() {
return Err(DynasmError::ImpossibleRelocation(TargetKind::Dynamic(id)));
}
cache_control::synchronize_icache(buf);
if loc.needs_adjustment() {
self.new_managed.add(loc);
}
}
self.old_managed.remove_between(self.previous_asmoffset, self.asmoffset);
self.previous_asmoffset = self.asmoffset;
self.old_managed.append(&mut self.new_managed);
Ok(())
}
}
impl<'a, R: Relocation> Extend<u8> for Modifier<'a,R> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
for (src, dst) in iter.into_iter().zip(self.buffer[self.asmoffset ..].iter_mut()) {
*dst = src;
self.asmoffset += 1;
}
}
}
impl<'a, 'b, R: Relocation> Extend<&'b u8> for Modifier<'a, R> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'b u8> {
for (src, dst) in iter.into_iter().zip(self.buffer[self.asmoffset ..].iter_mut()) {
*dst = *src;
self.asmoffset += 1;
}
}
}
impl<'a, R: Relocation> DynasmApi for Modifier<'a, R> {
fn offset(&self) -> AssemblyOffset {
AssemblyOffset(self.asmoffset)
}
fn push(&mut self, value: u8) {
self.buffer[self.asmoffset] = value;
self.asmoffset += 1
}
fn align(&mut self, alignment: usize, with: u8) {
let mismatch = self.asmoffset % alignment;
if mismatch != 0 {
for _ in mismatch .. alignment {
self.push(with)
}
}
}
}
impl<'a, R: Relocation> DynasmLabelApi for Modifier<'a, R> {
type Relocation = R;
fn local_label(&mut self, name: &'static str) {
let offset = self.offset();
self.labels.define_local(name, offset);
}
fn global_label( &mut self, name: &'static str) {
let offset = self.offset();
if let Err(e) = self.labels.define_global(name, offset) {
self.error = Some(e);
}
}
fn dynamic_label(&mut self, id: DynamicLabel) {
let offset = self.offset();
if let Err(e) = self.labels.define_dynamic(id, offset) {
self.error = Some(e);
}
}
fn global_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = StaticLabel::global(name);
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn dynamic_relocation(&mut self, id: DynamicLabel, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
self.relocs.add_dynamic(id, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn forward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = match self.labels.place_local_reference(name) {
Some(label) => label.next(),
None => StaticLabel::first(name),
};
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn backward_relocation(&mut self, name: &'static str, target_offset: isize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let label = match self.labels.place_local_reference(name) {
Some(label) => label,
None => {
self.error = Some(DynasmError::UnknownLabel(LabelKind::Local(name)));
return;
}
};
self.relocs.add_static(label, PatchLoc::new(location, target_offset, field_offset, ref_offset, kind));
}
fn bare_relocation(&mut self, target: usize, field_offset: u8, ref_offset: u8, kind: R) {
let location = self.offset();
let loc = PatchLoc::new(location, 0, field_offset, ref_offset, kind);
let buf_addr = self.buffer.as_ptr() as usize;
let buf = &mut self.buffer[loc.range(0)];
if loc.patch(buf, buf_addr, target).is_err() {
self.error = Some(DynasmError::ImpossibleRelocation(TargetKind::Extern(target)));
} else if loc.needs_adjustment() {
self.new_managed.add(loc)
}
}
}
#[derive(Debug)]
pub struct UncommittedModifier<'a> {
buffer: &'a mut Vec<u8>,
base_offset: usize,
offset: usize
}
impl<'a> UncommittedModifier<'a> {
pub fn new(buffer: &mut Vec<u8>, base_offset: AssemblyOffset) -> UncommittedModifier {
UncommittedModifier {
buffer,
base_offset: base_offset.0,
offset: base_offset.0
}
}
pub fn goto(&mut self, offset: AssemblyOffset) {
self.offset = offset.0;
}
pub fn check(&mut self, offset: AssemblyOffset) -> Result<(), DynasmError> {
if self.offset > offset.0 {
Err(DynasmError::CheckFailed)
} else {
Ok(())
}
}
pub fn check_exact(&mut self, offset: AssemblyOffset) -> Result<(), DynasmError> {
if self.offset != offset.0 {
Err(DynasmError::CheckFailed)
} else {
Ok(())
}
}
}
impl<'a> DynasmApi for UncommittedModifier<'a> {
fn offset(&self) -> AssemblyOffset {
AssemblyOffset(self.offset)
}
fn push(&mut self, value: u8) {
self.buffer[self.offset - self.base_offset] = value;
self.offset += 1;
}
fn align(&mut self, alignment: usize, with: u8) {
let mismatch = self.offset % alignment;
if mismatch != 0 {
for _ in mismatch .. alignment {
self.push(with)
}
}
}
}
impl<'a> Extend<u8> for UncommittedModifier<'a> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=u8> {
for i in iter {
self.push(i)
}
}
}
impl<'a, 'b> Extend<&'b u8> for UncommittedModifier<'a> {
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item=&'b u8> {
self.extend(iter.into_iter().cloned())
}
}
pub trait Register: Debug + Clone + Copy + PartialEq + Eq + Hash {
fn code(&self) -> u8;
}