pub mod asm_traits;
mod code_asm_methods;
mod fn_asm_impl;
mod fn_asm_pub;
mod mem;
mod op_state;
mod reg;
pub mod registers;
#[cfg(test)]
mod tests;
pub use crate::code_asm::mem::*;
pub use crate::code_asm::reg::*;
pub use crate::code_asm::registers::*;
pub use crate::IcedError;
use crate::{BlockEncoderResult, Instruction};
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};
struct PrefixFlags;
impl PrefixFlags {
const NONE: u8 = 0x00;
const LOCK: u8 = 0x01;
const REPE: u8 = 0x02;
const REPNE: u8 = 0x04;
const NOTRACK: u8 = 0x08;
const PREFER_VEX: u8 = 0x10;
const PREFER_EVEX: u8 = 0x20;
}
struct CodeAssemblerOptions;
impl CodeAssemblerOptions {
const PREFER_VEX: u8 = 0x01;
const PREFER_SHORT_BRANCH: u8 = 0x02;
}
#[allow(missing_debug_implementations)]
pub struct CodeAssembler {
bitness: u32,
instructions: Vec<Instruction>,
current_label_id: u64,
current_label: CodeLabel,
current_anon_label: CodeLabel,
next_anon_label: CodeLabel,
defined_anon_label: bool,
prefix_flags: u8,
options: u8,
}
#[derive(Debug, Default, Copy, Clone)]
pub struct CodeLabel {
id: u64,
instruction_index: usize,
}
impl Eq for CodeLabel {}
impl PartialEq for CodeLabel {
#[inline]
fn eq(&self, other: &CodeLabel) -> bool {
self.id == other.id
}
}
impl Hash for CodeLabel {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl CodeLabel {
#[must_use]
#[inline]
pub(crate) fn new(id: u64) -> Self {
Self { id, instruction_index: usize::MAX }
}
#[must_use]
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.id == 0
}
#[must_use]
#[inline]
pub(crate) fn has_instruction_index(&self) -> bool {
self.instruction_index != usize::MAX
}
#[must_use]
#[inline]
pub(crate) fn id(&self) -> u64 {
self.id
}
}
#[derive(Debug)]
#[cfg_attr(not(feature = "exhaustive_enums"), non_exhaustive)]
pub struct CodeAssemblerResult {
pub inner: BlockEncoderResult,
}
impl CodeAssemblerResult {
#[allow(clippy::missing_inline_in_public_items)]
pub fn label_ip(&self, label: &CodeLabel) -> Result<u64, IcedError> {
if label.is_empty() {
return Err(IcedError::new("Invalid label. Must be created via `CodeAssembler::create_label()`."));
}
if !label.has_instruction_index() {
return Err(IcedError::new(
"The label is not associated with an instruction index. It must be emitted via `CodeAssembler::set_label()`.",
));
}
let new_offset = if let Some(new_offset) = self.inner.new_instruction_offsets.get(label.instruction_index) {
*new_offset
} else {
return Err(IcedError::new(
"Invalid label instruction index or `BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS` option was not enabled when calling `assemble_options()`.",
));
};
if new_offset == u32::MAX {
Err(IcedError::new("The instruction was re-written to a longer instruction (eg. JE NEAR -> JE FAR) and there's no instruction offset. Consider using a `zero_bytes()` instruction as a label instead of a normal instruction or disable branch optimizations."))
} else {
Ok(self.inner.rip.wrapping_add(new_offset as u64))
}
}
}