summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-12-08 19:18:12 -0500
committerMason Reed <35282038+emesare@users.noreply.github.com>2025-12-10 17:35:19 -0500
commit2c7ba495a6c1d8b3639b74334b0cdd1809af807e (patch)
treea83f47d51954ad4abf24c64f6d37465b1ebbc1ea /rust/src
parentbc195c1c21da0400a1a1dde1fcdde45d687e666f (diff)
[Rust] Remove `UnusedRegisterStackInfo` and update architecture documentation
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/architecture.rs284
-rw-r--r--rust/src/architecture/branches.rs2
-rw-r--r--rust/src/architecture/intrinsic.rs2
-rw-r--r--rust/src/architecture/register.rs142
4 files changed, 354 insertions, 76 deletions
diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs
index e893213b..d85faaca 100644
--- a/rust/src/architecture.rs
+++ b/rust/src/architecture.rs
@@ -94,22 +94,62 @@ macro_rules! new_id_type {
pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
type Handle: Borrow<Self> + Clone;
+ /// The [`RegisterInfo`] associated with this architecture.
type RegisterInfo: RegisterInfo<RegType = Self::Register>;
+
+ /// The [`Register`] associated with this architecture.
type Register: Register<InfoType = Self::RegisterInfo>;
+
+ /// The [`RegisterStackInfo`] associated with this architecture.
+ ///
+ /// You may only set this to [`UnusedRegisterStack`] if [`Self::RegisterStack`] is as well.
type RegisterStackInfo: RegisterStackInfo<
RegType = Self::Register,
RegInfoType = Self::RegisterInfo,
RegStackType = Self::RegisterStack,
>;
+
+ /// The [`RegisterStack`] associated with this architecture.
+ ///
+ /// If you do not override [`Architecture::register_stack_from_id`] and [`Architecture::register_stacks`],
+ /// you may set this to [`UnusedRegisterStack`].
type RegisterStack: RegisterStack<
InfoType = Self::RegisterStackInfo,
RegType = Self::Register,
RegInfoType = Self::RegisterInfo,
>;
+ /// The [`Flag`] associated with this architecture.
+ ///
+ /// If you do not override [`Architecture::flag_from_id`] and [`Architecture::flags`], you may
+ /// set this to [`UnusedFlag`].
type Flag: Flag<FlagClass = Self::FlagClass>;
+
+ /// The [`FlagWrite`] associated with this architecture.
+ ///
+ /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that
+ /// this points to a custom [`FlagWrite`] with the following functions defined:
+ ///
+ /// - [`Architecture::flag_write_types`]
+ /// - [`Architecture::flag_write_from_id`]
type FlagWrite: FlagWrite<FlagType = Self::Flag, FlagClass = Self::FlagClass>;
+
+ /// The [`FlagClass`] associated with this architecture.
+ ///
+ /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that
+ /// this points to a custom [`FlagClass`] with the following functions defined:
+ ///
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_class_from_id`]
type FlagClass: FlagClass;
+
+ /// The [`FlagGroup`] associated with this architecture.
+ ///
+ /// Can only be set to [`UnusedFlag`] if [`Self::Flag`] is as well. Otherwise, it is expected that
+ /// this points to a custom [`FlagGroup`] with the following functions defined:
+ ///
+ /// - [`Architecture::flag_groups`]
+ /// - [`Architecture::flag_group_from_id`]
type FlagGroup: FlagGroup<FlagType = Self::Flag, FlagClass = Self::FlagClass>;
type Intrinsic: Intrinsic;
@@ -118,10 +158,26 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
fn address_size(&self) -> usize;
fn default_integer_size(&self) -> usize;
fn instruction_alignment(&self) -> usize;
+
+ /// The maximum length of an instruction in bytes. This is used to determine the size of the buffer
+ /// given to callbacks such as [`Architecture::instruction_info`], [`Architecture::instruction_text`]
+ /// and [`Architecture::instruction_llil`].
+ ///
+ /// NOTE: The maximum **CANNOT** be greater than 256.
fn max_instr_len(&self) -> usize;
- fn opcode_display_len(&self) -> usize;
- fn associated_arch_by_addr(&self, addr: u64) -> CoreArchitecture;
+ /// How many bytes to display in the opcode space before displaying a `...`, typically set to
+ /// the [`Architecture::max_instr_len`], however, can be overridden to display a truncated opcode.
+ fn opcode_display_len(&self) -> usize {
+ self.max_instr_len()
+ }
+
+ /// In binaries with multiple architectures, you may wish to associate a specific architecture
+ /// with a given virtual address. This can be seen in armv7 where odd addresses are associated
+ /// with the thumb architecture.
+ fn associated_arch_by_addr(&self, _addr: u64) -> CoreArchitecture {
+ *self.as_ref()
+ }
/// Returns the [`InstructionInfo`] at the given virtual address with `data`.
///
@@ -129,6 +185,20 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
/// next instruction will likely be incorrect.
fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo>;
+ /// Disassembles a raw byte sequence into a human-readable list of text tokens.
+ ///
+ /// This function is responsible for the visual representation of assembly instructions.
+ /// It does *not* define semantics (use [`Architecture::instruction_llil`] for that);
+ /// it simply tells the UI how to print the instruction.
+ ///
+ /// # Returns
+ ///
+ /// An `Option` containing a tuple:
+ ///
+ /// * `usize`: The size of the decoded instruction in bytes. Is used to advance to the next instruction.
+ /// * `Vec<InstructionTextToken>`: A list of text tokens representing the instruction.
+ ///
+ /// Returns `None` if the bytes do not form a valid instruction.
fn instruction_text(
&self,
data: &[u8],
@@ -231,61 +301,179 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
}
fn registers_all(&self) -> Vec<Self::Register>;
+
+ fn register_from_id(&self, id: RegisterId) -> Option<Self::Register>;
+
fn registers_full_width(&self) -> Vec<Self::Register>;
+
+ // TODO: Document the difference between global and system registers.
fn registers_global(&self) -> Vec<Self::Register> {
Vec::new()
}
+
+ // TODO: Document the difference between global and system registers.
fn registers_system(&self) -> Vec<Self::Register> {
Vec::new()
}
+ /// List of concrete register stacks for this architecture.
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::register_stack_from_id`]
fn register_stacks(&self) -> Vec<Self::RegisterStack> {
Vec::new()
}
- fn flags(&self) -> Vec<Self::Flag> {
- Vec::new()
+ /// Get the [`Self::RegisterStack`] associated with the given [`RegisterStackId`].
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::register_stacks`]
+ fn register_stack_from_id(&self, _id: RegisterStackId) -> Option<Self::RegisterStack> {
+ None
}
- fn flag_write_types(&self) -> Vec<Self::FlagWrite> {
+
+ /// List of concrete flags for this architecture.
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flag_from_id`]
+ /// - [`Architecture::flag_write_types`]
+ /// - [`Architecture::flag_write_from_id`]
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_class_from_id`]
+ /// - [`Architecture::flag_groups`]
+ /// - [`Architecture::flag_group_from_id`]
+ fn flags(&self) -> Vec<Self::Flag> {
Vec::new()
}
- fn flag_classes(&self) -> Vec<Self::FlagClass> {
- Vec::new()
+
+ /// Get the [`Self::Flag`] associated with the given [`FlagId`].
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flags`]
+ /// - [`Architecture::flag_write_types`]
+ /// - [`Architecture::flag_write_from_id`]
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_class_from_id`]
+ /// - [`Architecture::flag_groups`]
+ /// - [`Architecture::flag_group_from_id`]
+ fn flag_from_id(&self, _id: FlagId) -> Option<Self::Flag> {
+ None
}
- fn flag_groups(&self) -> Vec<Self::FlagGroup> {
+
+ /// List of concrete flag write types for this architecture.
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flags`]
+ /// - [`Architecture::flag_from_id`]
+ /// - [`Architecture::flag_write_from_id`]
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_class_from_id`]
+ /// - [`Architecture::flag_groups`]
+ /// - [`Architecture::flag_group_from_id`]
+ fn flag_write_types(&self) -> Vec<Self::FlagWrite> {
Vec::new()
}
- fn stack_pointer_reg(&self) -> Option<Self::Register>;
- fn link_reg(&self) -> Option<Self::Register> {
+ /// Get the [`Self::FlagWrite`] associated with the given [`FlagWriteId`].
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flags`]
+ /// - [`Architecture::flag_from_id`]
+ /// - [`Architecture::flag_write_types`]
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_class_from_id`]
+ /// - [`Architecture::flag_groups`]
+ /// - [`Architecture::flag_group_from_id`]
+ fn flag_write_from_id(&self, _id: FlagWriteId) -> Option<Self::FlagWrite> {
None
}
- fn register_from_id(&self, id: RegisterId) -> Option<Self::Register>;
-
- fn register_stack_from_id(&self, _id: RegisterStackId) -> Option<Self::RegisterStack> {
- None
+ /// List of concrete flag classes for this architecture.
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flags`]
+ /// - [`Architecture::flag_from_id`]
+ /// - [`Architecture::flag_write_from_id`]
+ /// - [`Architecture::flag_class_from_id`]
+ /// - [`Architecture::flag_groups`]
+ /// - [`Architecture::flag_group_from_id`]
+ fn flag_classes(&self) -> Vec<Self::FlagClass> {
+ Vec::new()
}
- fn flag_from_id(&self, _id: FlagId) -> Option<Self::Flag> {
+ /// Get the [`Self::FlagClass`] associated with the given [`FlagClassId`].
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flags`]
+ /// - [`Architecture::flag_from_id`]
+ /// - [`Architecture::flag_write_from_id`]
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_groups`]
+ /// - [`Architecture::flag_group_from_id`]
+ fn flag_class_from_id(&self, _id: FlagClassId) -> Option<Self::FlagClass> {
None
}
- fn flag_write_from_id(&self, _id: FlagWriteId) -> Option<Self::FlagWrite> {
- None
+
+ /// List of concrete flag groups for this architecture.
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flags`]
+ /// - [`Architecture::flag_from_id`]
+ /// - [`Architecture::flag_write_from_id`]
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_class_from_id`]
+ /// - [`Architecture::flag_group_from_id`]
+ fn flag_groups(&self) -> Vec<Self::FlagGroup> {
+ Vec::new()
}
- fn flag_class_from_id(&self, _id: FlagClassId) -> Option<Self::FlagClass> {
+
+ /// Get the [`Self::FlagGroup`] associated with the given [`FlagGroupId`].
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::flags`]
+ /// - [`Architecture::flag_from_id`]
+ /// - [`Architecture::flag_write_from_id`]
+ /// - [`Architecture::flag_classes`]
+ /// - [`Architecture::flag_class_from_id`]
+ /// - [`Architecture::flag_groups`]
+ fn flag_group_from_id(&self, _id: FlagGroupId) -> Option<Self::FlagGroup> {
None
}
- fn flag_group_from_id(&self, _id: FlagGroupId) -> Option<Self::FlagGroup> {
+
+ fn stack_pointer_reg(&self) -> Option<Self::Register>;
+
+ fn link_reg(&self) -> Option<Self::Register> {
None
}
+ /// List of concrete intrinsics for this architecture.
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::intrinsic_from_id`]
fn intrinsics(&self) -> Vec<Self::Intrinsic> {
Vec::new()
}
+
fn intrinsic_class(&self, _id: IntrinsicId) -> BNIntrinsicClass {
BNIntrinsicClass::GeneralIntrinsicClass
}
+
+ /// Get the [`Self::Intrinsic`] associated with the given [`IntrinsicId`].
+ ///
+ /// You **must** override the following functions as well:
+ ///
+ /// - [`Architecture::intrinsics`]
fn intrinsic_from_id(&self, _id: IntrinsicId) -> Option<Self::Intrinsic> {
None
}
@@ -293,6 +481,7 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
fn can_assemble(&self) -> bool {
false
}
+
fn assemble(&self, _code: &str, _addr: u64) -> Result<Vec<u8>, String> {
Err("Assemble unsupported".into())
}
@@ -300,15 +489,19 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
fn is_never_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
false
}
+
fn is_always_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
false
}
+
fn is_invert_branch_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
false
}
+
fn is_skip_and_return_zero_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
false
}
+
fn is_skip_and_return_value_patch_available(&self, _data: &[u8], _addr: u64) -> bool {
false
}
@@ -587,6 +780,10 @@ impl Architecture for CoreArchitecture {
}
}
+ fn register_from_id(&self, id: RegisterId) -> Option<CoreRegister> {
+ CoreRegister::new(*self, id)
+ }
+
fn registers_full_width(&self) -> Vec<CoreRegister> {
unsafe {
let mut count: usize = 0;
@@ -655,6 +852,10 @@ impl Architecture for CoreArchitecture {
}
}
+ fn register_stack_from_id(&self, id: RegisterStackId) -> Option<CoreRegisterStack> {
+ CoreRegisterStack::new(*self, id)
+ }
+
fn flags(&self) -> Vec<CoreFlag> {
unsafe {
let mut count: usize = 0;
@@ -672,6 +873,10 @@ impl Architecture for CoreArchitecture {
}
}
+ fn flag_from_id(&self, id: FlagId) -> Option<CoreFlag> {
+ CoreFlag::new(*self, id)
+ }
+
fn flag_write_types(&self) -> Vec<CoreFlagWrite> {
unsafe {
let mut count: usize = 0;
@@ -689,6 +894,10 @@ impl Architecture for CoreArchitecture {
}
}
+ fn flag_write_from_id(&self, id: FlagWriteId) -> Option<CoreFlagWrite> {
+ CoreFlagWrite::new(*self, id)
+ }
+
fn flag_classes(&self) -> Vec<CoreFlagClass> {
unsafe {
let mut count: usize = 0;
@@ -706,6 +915,10 @@ impl Architecture for CoreArchitecture {
}
}
+ fn flag_class_from_id(&self, id: FlagClassId) -> Option<CoreFlagClass> {
+ CoreFlagClass::new(*self, id)
+ }
+
fn flag_groups(&self) -> Vec<CoreFlagGroup> {
unsafe {
let mut count: usize = 0;
@@ -723,6 +936,10 @@ impl Architecture for CoreArchitecture {
}
}
+ fn flag_group_from_id(&self, id: FlagGroupId) -> Option<CoreFlagGroup> {
+ CoreFlagGroup::new(*self, id)
+ }
+
fn stack_pointer_reg(&self) -> Option<CoreRegister> {
match unsafe { BNGetArchitectureStackPointerRegister(self.handle) } {
0xffff_ffff => None,
@@ -737,30 +954,6 @@ impl Architecture for CoreArchitecture {
}
}
- fn register_from_id(&self, id: RegisterId) -> Option<CoreRegister> {
- CoreRegister::new(*self, id)
- }
-
- fn register_stack_from_id(&self, id: RegisterStackId) -> Option<CoreRegisterStack> {
- CoreRegisterStack::new(*self, id)
- }
-
- fn flag_from_id(&self, id: FlagId) -> Option<CoreFlag> {
- CoreFlag::new(*self, id)
- }
-
- fn flag_write_from_id(&self, id: FlagWriteId) -> Option<CoreFlagWrite> {
- CoreFlagWrite::new(*self, id)
- }
-
- fn flag_class_from_id(&self, id: FlagClassId) -> Option<CoreFlagClass> {
- CoreFlagClass::new(*self, id)
- }
-
- fn flag_group_from_id(&self, id: FlagGroupId) -> Option<CoreFlagGroup> {
- CoreFlagGroup::new(*self, id)
- }
-
fn intrinsics(&self) -> Vec<CoreIntrinsic> {
unsafe {
let mut count: usize = 0;
@@ -889,10 +1082,7 @@ impl Debug for CoreArchitecture {
.field("name", &self.name())
.field("endianness", &self.endianness())
.field("address_size", &self.address_size())
- .field("default_integer_size", &self.default_integer_size())
.field("instruction_alignment", &self.instruction_alignment())
- .field("max_instr_len", &self.max_instr_len())
- .field("opcode_display_len", &self.opcode_display_len())
.finish()
}
}
@@ -1717,7 +1907,7 @@ where
result.offset = info.offset();
result.size = info.size();
- result.extend = info.implicit_extend();
+ result.extend = info.implicit_extend().into();
}
}
diff --git a/rust/src/architecture/branches.rs b/rust/src/architecture/branches.rs
index 80baa1b6..a6810b34 100644
--- a/rust/src/architecture/branches.rs
+++ b/rust/src/architecture/branches.rs
@@ -22,7 +22,7 @@ pub enum BranchKind {
#[derive(Default, Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct BranchInfo {
- /// If `None` the target architecture is the same as the branch instruction.
+ /// If `None`, the target architecture is the same as the branching instruction.
pub arch: Option<CoreArchitecture>,
pub kind: BranchKind,
}
diff --git a/rust/src/architecture/intrinsic.rs b/rust/src/architecture/intrinsic.rs
index 4ad5ee2a..5d9827a1 100644
--- a/rust/src/architecture/intrinsic.rs
+++ b/rust/src/architecture/intrinsic.rs
@@ -32,7 +32,7 @@ pub trait Intrinsic: Debug + Sized + Clone + Copy {
fn outputs(&self) -> Vec<Conf<Ref<Type>>>;
}
-/// Type for architrectures that do not use intrinsics. Will panic if accessed as an intrinsic.
+/// Type for architectures that do not use intrinsics. Will panic if accessed as an intrinsic.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UnusedIntrinsic;
diff --git a/rust/src/architecture/register.rs b/rust/src/architecture/register.rs
index 50bb38ba..1f17c785 100644
--- a/rust/src/architecture/register.rs
+++ b/rust/src/architecture/register.rs
@@ -6,8 +6,6 @@ use std::ffi::CStr;
use std::fmt::{Debug, Formatter};
use std::hash::Hash;
-pub use binaryninjacore_sys::BNImplicitRegisterExtend as ImplicitRegisterExtend;
-
crate::new_id_type!(RegisterId, u32);
impl RegisterId {
@@ -18,59 +16,133 @@ impl RegisterId {
crate::new_id_type!(RegisterStackId, u32);
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum ImplicitRegisterExtend {
+ /// The upper bits of the parent register are preserved (untouched).
+ ///
+ /// # Example (x86-64)
+ ///
+ /// Executing `inc al` only modifies the lowest 8 bits of `rax`. The upper 56 bits of `rax` remain
+ /// completely unchanged.
+ NoExtend = 0,
+ /// The upper bits of the parent register are zeroed out.
+ ///
+ /// # Example (x86-64)
+ ///
+ /// Executing `mov eax, 1` writes `1` to the lower 32 bits of `rax`, but implicitly **clears** the
+ /// upper 32 bits of `rax` to zero.
+ ZeroExtendToFullWidth,
+ /// The upper bits of the parent register are filled with the sign bit (MSB) of the value written.
+ SignExtendToFullWidth,
+}
+
+impl From<BNImplicitRegisterExtend> for ImplicitRegisterExtend {
+ fn from(value: BNImplicitRegisterExtend) -> Self {
+ match value {
+ BNImplicitRegisterExtend::NoExtend => Self::NoExtend,
+ BNImplicitRegisterExtend::ZeroExtendToFullWidth => Self::ZeroExtendToFullWidth,
+ BNImplicitRegisterExtend::SignExtendToFullWidth => Self::SignExtendToFullWidth,
+ }
+ }
+}
+
+impl From<ImplicitRegisterExtend> for BNImplicitRegisterExtend {
+ fn from(value: ImplicitRegisterExtend) -> Self {
+ match value {
+ ImplicitRegisterExtend::NoExtend => Self::NoExtend,
+ ImplicitRegisterExtend::ZeroExtendToFullWidth => Self::ZeroExtendToFullWidth,
+ ImplicitRegisterExtend::SignExtendToFullWidth => Self::SignExtendToFullWidth,
+ }
+ }
+}
+
+/// Information about a register.
pub trait RegisterInfo: Sized {
type RegType: Register<InfoType = Self>;
+ /// The register that this register is an alias of.
+ ///
+ /// # Example (x86-64)
+ ///
+ /// The register `rax` is a parent of the register `eax`.
fn parent(&self) -> Option<Self::RegType>;
+
+ /// Size of the register in bytes.
fn size(&self) -> usize;
+
+ /// Offset of the register in bytes from the start of the containing [`RegisterInfo::parent`].
fn offset(&self) -> usize;
+
+ /// Used when this register aliases a logical register to determine what happens to the upper bits.
fn implicit_extend(&self) -> ImplicitRegisterExtend;
}
pub trait Register: Debug + Sized + Clone + Copy + Hash + Eq {
type InfoType: RegisterInfo<RegType = Self>;
+ /// The displayed name of the register, such as "eax".
fn name(&self) -> Cow<'_, str>;
+
fn info(&self) -> Self::InfoType;
/// Unique identifier for this `Register`.
///
- /// *MUST* be in the range [0, 0x7fff_ffff]
+ /// NOTE: *MUST* be in the range [0, 0x7fff_ffff]
fn id(&self) -> RegisterId;
}
+/// Information about a register stack.
pub trait RegisterStackInfo: Sized {
type RegStackType: RegisterStack<InfoType = Self>;
type RegType: Register<InfoType = Self::RegInfoType>;
type RegInfoType: RegisterInfo<RegType = Self::RegType>;
+ // TODO: Return a list of the registers instead?
+ /// The sequence of physical registers that back this stack.
+ ///
+ /// This defines the absolute storage locations in the hardware, ignoring the current stack pointer.
+ ///
+ /// Return the start of the "fake" registers defined. The core requires that the id's be contiguous
+ /// as you only return the **first** storage register and the count.
+ ///
+ /// # Example (x87 FPU)
+ ///
+ /// [`RegisterStackInfo::top_relative_regs`] with (REG_ST0, 8) and then define here (REG_PHYSICAL_0, 8).
fn storage_regs(&self) -> (Self::RegType, usize);
- fn top_relative_regs(&self) -> Option<(Self::RegType, usize)>;
- fn stack_top_reg(&self) -> Self::RegType;
-}
-
-/// Type for architectures that do not use register stacks. Will panic if accessed as a register stack.
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct UnusedRegisterStackInfo<R: Register> {
- _reg: std::marker::PhantomData<R>,
-}
-impl<R: Register> RegisterStackInfo for UnusedRegisterStackInfo<R> {
- type RegStackType = UnusedRegisterStack<R>;
- type RegType = R;
- type RegInfoType = R::InfoType;
+ // TODO: Return a list of the registers instead?
+ /// The sequence of registers used to access the stack relative to the current top.
+ ///
+ /// Return the start of the relative registers defined. The core requires that the id's be contiguous
+ /// as you only return the **first** relative register and the count.
+ ///
+ /// # Example (x87 FPU)
+ ///
+ /// Returns (REG_ST0, 8), where the id's of all the later relative registers are contiguous.
+ fn top_relative_regs(&self) -> Option<(Self::RegType, usize)>;
- fn storage_regs(&self) -> (Self::RegType, usize) {
- unreachable!()
- }
- fn top_relative_regs(&self) -> Option<(Self::RegType, usize)> {
- unreachable!()
- }
- fn stack_top_reg(&self) -> Self::RegType {
- unreachable!()
- }
+ /// The specific register that holds the index of the current stack top.
+ ///
+ /// The value in this register determines which physical `storage_reg` corresponds
+ /// to the first `top_relative_reg`.
+ ///
+ /// # Example (x87 FPU)
+ ///
+ /// Returns the `TOP` as a fake register.
+ ///
+ /// * If `TOP` == 0: `top_relative_regs[0]` maps to `storage_regs[0]`.
+ /// * If `TOP` == 1: `top_relative_regs[0]` maps to `storage_regs[1]`.
+ fn stack_top_reg(&self) -> Self::RegType;
}
+/// Register stacks are used in architectures where registers are accessed relative to a
+/// dynamic stack pointer rather than by fixed names.
+///
+/// For more information see [`RegisterStackInfo`].
+///
+/// # Example
+/// The **x87 FPU** on x86 uses a register stack (`ST(0)` through `ST(7)`).
+/// Pushing a value decrements the stack top pointer; popping increments it.
pub trait RegisterStack: Debug + Sized + Clone + Copy {
type InfoType: RegisterStackInfo<
RegType = Self::RegType,
@@ -96,7 +168,7 @@ pub struct UnusedRegisterStack<R: Register> {
}
impl<R: Register> RegisterStack for UnusedRegisterStack<R> {
- type InfoType = UnusedRegisterStackInfo<R>;
+ type InfoType = Self;
type RegType = R;
type RegInfoType = R::InfoType;
@@ -111,6 +183,22 @@ impl<R: Register> RegisterStack for UnusedRegisterStack<R> {
}
}
+impl<R: Register> RegisterStackInfo for UnusedRegisterStack<R> {
+ type RegStackType = Self;
+ type RegType = R;
+ type RegInfoType = R::InfoType;
+
+ fn storage_regs(&self) -> (Self::RegType, usize) {
+ unreachable!()
+ }
+ fn top_relative_regs(&self) -> Option<(Self::RegType, usize)> {
+ unreachable!()
+ }
+ fn stack_top_reg(&self) -> Self::RegType {
+ unreachable!()
+ }
+}
+
#[derive(Debug, Copy, Clone)]
pub struct CoreRegisterInfo {
arch: CoreArchitecture,
@@ -147,7 +235,7 @@ impl RegisterInfo for CoreRegisterInfo {
}
fn implicit_extend(&self) -> ImplicitRegisterExtend {
- self.info.extend
+ self.info.extend.into()
}
}