diff options
| author | Mason Reed <mason@vector35.com> | 2025-12-08 19:18:12 -0500 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2025-12-10 17:35:19 -0500 |
| commit | 2c7ba495a6c1d8b3639b74334b0cdd1809af807e (patch) | |
| tree | a83f47d51954ad4abf24c64f6d37465b1ebbc1ea /rust/src | |
| parent | bc195c1c21da0400a1a1dde1fcdde45d687e666f (diff) | |
[Rust] Remove `UnusedRegisterStackInfo` and update architecture documentation
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/architecture.rs | 284 | ||||
| -rw-r--r-- | rust/src/architecture/branches.rs | 2 | ||||
| -rw-r--r-- | rust/src/architecture/intrinsic.rs | 2 | ||||
| -rw-r--r-- | rust/src/architecture/register.rs | 142 |
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() } } |
