1 //! Contains traits that a user of this assembler must implement. 2 3 use crate::gpr; 4 use crate::xmm; 5 use std::{num::NonZeroU8, ops::Index, vec::Vec}; 6 7 /// Describe how an instruction is emitted into a code buffer. 8 pub trait CodeSink { 9 /// Add 1 byte to the code section. 10 fn put1(&mut self, _: u8); 11 12 /// Add 2 bytes to the code section. 13 fn put2(&mut self, _: u16); 14 15 /// Add 4 bytes to the code section. 16 fn put4(&mut self, _: u32); 17 18 /// Add 8 bytes to the code section. 19 fn put8(&mut self, _: u64); 20 21 /// Inform the code buffer of a possible trap at the current location; 22 /// required for assembling memory accesses. 23 fn add_trap(&mut self, code: TrapCode); 24 25 /// Return the byte offset of the current location in the code buffer; 26 /// required for assembling RIP-relative memory accesses. 27 fn current_offset(&self) -> u32; 28 29 /// Inform the code buffer of a use of `label` at `offset`; required for 30 /// assembling RIP-relative memory accesses. 31 fn use_label_at_offset(&mut self, offset: u32, label: Label); 32 33 /// Return the label for a constant `id`; required for assembling 34 /// RIP-relative memory accesses of constants. 35 fn get_label_for_constant(&mut self, id: Constant) -> Label; 36 } 37 38 /// Provide a convenient implementation for testing. 39 impl CodeSink for Vec<u8> { 40 fn put1(&mut self, v: u8) { 41 self.extend_from_slice(&[v]); 42 } 43 44 fn put2(&mut self, v: u16) { 45 self.extend_from_slice(&v.to_le_bytes()); 46 } 47 48 fn put4(&mut self, v: u32) { 49 self.extend_from_slice(&v.to_le_bytes()); 50 } 51 52 fn put8(&mut self, v: u64) { 53 self.extend_from_slice(&v.to_le_bytes()); 54 } 55 56 fn add_trap(&mut self, _: TrapCode) {} 57 58 fn current_offset(&self) -> u32 { 59 self.len().try_into().unwrap() 60 } 61 62 fn use_label_at_offset(&mut self, _: u32, _: Label) {} 63 64 fn get_label_for_constant(&mut self, c: Constant) -> Label { 65 Label(c.0) 66 } 67 } 68 69 /// Wrap [`CodeSink`]-specific labels. 70 #[derive(Debug, Clone)] 71 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 72 pub struct Label(pub u32); 73 74 /// Wrap [`CodeSink`]-specific constant keys. 75 #[derive(Debug, Clone)] 76 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 77 pub struct Constant(pub u32); 78 79 /// Wrap [`CodeSink`]-specific trap codes. 80 #[derive(Debug, Clone, Copy)] 81 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 82 pub struct TrapCode(pub NonZeroU8); 83 84 /// A table mapping `KnownOffset` identifiers to their `i32` offset values. 85 /// 86 /// When encoding instructions, Cranelift may not know all of the information 87 /// needed to construct an immediate. Specifically, addressing modes that 88 /// require knowing the size of the tail arguments or outgoing arguments (see 89 /// `SyntheticAmode::finalize`) will not know these sizes until emission. 90 /// 91 /// This table allows up to do a "late" look up of these values by their 92 /// `KnownOffset`. 93 pub trait KnownOffsetTable: Index<KnownOffset, Output = i32> {} 94 impl KnownOffsetTable for Vec<i32> {} 95 /// Provide a convenient implementation for testing. 96 impl KnownOffsetTable for [i32; 2] {} 97 98 /// A `KnownOffset` is a unique identifier for a specific offset known only at 99 /// emission time. 100 pub type KnownOffset = usize; 101 102 /// A type set fixing the register types used in the assembler. 103 /// 104 /// This assembler is parameterizable over register types; this allows the 105 /// assembler users (e.g., Cranelift) to define their own register types 106 /// independent of this crate. 107 pub trait Registers { 108 /// An x64 general purpose register that may be read. 109 type ReadGpr: AsReg; 110 111 /// An x64 general purpose register that may be read and written. 112 type ReadWriteGpr: AsReg; 113 114 /// An x64 SSE register that may be read. 115 type ReadXmm: AsReg; 116 117 /// An x64 SSE register that may be read and written. 118 type ReadWriteXmm: AsReg; 119 } 120 121 /// Describe how to interact with an external register type. 122 pub trait AsReg: Clone + std::fmt::Debug { 123 /// Create a register from its hardware encoding. 124 /// 125 /// This is primarily useful for fuzzing, though it is also useful for 126 /// generating fixed registers. 127 fn new(enc: u8) -> Self; 128 129 /// Return the register's hardware encoding; e.g., `0` for `%rax`. 130 fn enc(&self) -> u8; 131 132 /// Return the register name. 133 fn to_string(&self, size: Option<gpr::Size>) -> String { 134 match size { 135 Some(size) => gpr::enc::to_string(self.enc(), size).into(), 136 None => xmm::enc::to_string(self.enc()).into(), 137 } 138 } 139 } 140 141 /// Provide a convenient implementation for testing. 142 impl AsReg for u8 { 143 fn new(enc: u8) -> Self { 144 enc 145 } 146 fn enc(&self) -> u8 { 147 *self 148 } 149 } 150 151 /// Describe a visitor for the register operands of an instruction. 152 /// 153 /// Due to how Cranelift's register allocation works, we allow the visitor to 154 /// modify the register operands in place. This allows Cranelift to convert 155 /// virtual registers (`[128..N)`) to physical registers (`[0..16)`) without 156 /// re-allocating the entire instruction object. 157 pub trait RegisterVisitor<R: Registers> { 158 /// Visit a read-only register. 159 fn read(&mut self, reg: &mut R::ReadGpr); 160 /// Visit a read-write register. 161 fn read_write(&mut self, reg: &mut R::ReadWriteGpr); 162 /// Visit a read-only fixed register; for safety, this register cannot be 163 /// modified in-place. 164 fn fixed_read(&mut self, reg: &R::ReadGpr); 165 /// Visit a read-write fixed register; for safety, this register cannot be 166 /// modified in-place. 167 fn fixed_read_write(&mut self, reg: &R::ReadWriteGpr); 168 /// Visit a read-only SSE register. 169 fn read_xmm(&mut self, reg: &mut R::ReadXmm); 170 /// Visit a read-write SSE register. 171 fn read_write_xmm(&mut self, reg: &mut R::ReadWriteXmm); 172 /// Visit a read-only fixed SSE register; for safety, this register cannot 173 /// be modified in-place. 174 fn fixed_read_xmm(&mut self, reg: &R::ReadXmm); 175 /// Visit a read-write fixed SSE register; for safety, this register cannot 176 /// be modified in-place. 177 fn fixed_read_write_xmm(&mut self, reg: &R::ReadWriteXmm); 178 } 179