1 //! Immediate operands to instructions. 2 3 use crate::api::CodeSink; 4 use alloc::{format, string::String}; 5 use core::fmt; 6 7 /// This helper function prints the unsigned hexadecimal representation of the 8 /// immediate value: e.g., this prints `$0xfe` to represent both the signed `-2` 9 /// and the unsigned `254`. 10 macro_rules! hexify { 11 ($n:expr) => { 12 format!("$0x{:x}", $n) 13 }; 14 } 15 16 /// Like `hexify!`, but this performs a sign extension. 17 macro_rules! hexify_sign_extend { 18 ($n:expr, $from:ty => $to:ty) => {{ 19 let from: $from = $n; // Assert the type we expect. 20 let to = <$to>::from(from); 21 format!("$0x{:x}", to) 22 }}; 23 } 24 25 /// An 8-bit immediate operand. 26 #[derive(Clone, Copy, Debug)] 27 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 28 pub struct Imm8(u8); 29 30 impl Imm8 { 31 #[must_use] new(value: u8) -> Self32 pub fn new(value: u8) -> Self { 33 Self(value) 34 } 35 36 #[must_use] value(&self) -> u837 pub fn value(&self) -> u8 { 38 self.0 39 } 40 encode(&self, sink: &mut impl CodeSink)41 pub fn encode(&self, sink: &mut impl CodeSink) { 42 sink.put1(self.0); 43 } 44 } 45 46 impl From<u8> for Imm8 { from(imm8: u8) -> Self47 fn from(imm8: u8) -> Self { 48 Self(imm8) 49 } 50 } 51 52 impl TryFrom<i32> for Imm8 { 53 type Error = core::num::TryFromIntError; try_from(simm32: i32) -> Result<Self, Self::Error>54 fn try_from(simm32: i32) -> Result<Self, Self::Error> { 55 Ok(Self(u8::try_from(simm32)?)) 56 } 57 } 58 59 impl fmt::Display for Imm8 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 61 write!(f, "$0x{:x}", self.0) 62 } 63 } 64 65 /// A _signed_ 8-bit immediate operand (suitable for sign extension). 66 #[derive(Clone, Copy, Debug)] 67 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 68 pub struct Simm8(i8); 69 70 impl Simm8 { 71 #[must_use] new(value: i8) -> Self72 pub fn new(value: i8) -> Self { 73 Self(value) 74 } 75 76 #[must_use] value(&self) -> i877 pub fn value(&self) -> i8 { 78 self.0 79 } 80 encode(&self, sink: &mut impl CodeSink)81 pub fn encode(&self, sink: &mut impl CodeSink) { 82 sink.put1(self.0 as u8); 83 } 84 85 #[must_use] to_string(&self, extend: Extension) -> String86 pub fn to_string(&self, extend: Extension) -> String { 87 use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord}; 88 match extend { 89 None => hexify!(self.0), 90 SignExtendWord => hexify_sign_extend!(self.0, i8 => i16), 91 SignExtendLong => hexify_sign_extend!(self.0, i8 => i32), 92 SignExtendQuad => hexify_sign_extend!(self.0, i8 => i64), 93 } 94 } 95 } 96 97 impl From<i8> for Simm8 { from(simm8: i8) -> Self98 fn from(simm8: i8) -> Self { 99 Self(simm8) 100 } 101 } 102 103 impl TryFrom<i32> for Simm8 { 104 type Error = core::num::TryFromIntError; try_from(simm32: i32) -> Result<Self, Self::Error>105 fn try_from(simm32: i32) -> Result<Self, Self::Error> { 106 Ok(Self(i8::try_from(simm32)?)) 107 } 108 } 109 110 /// A 16-bit immediate operand. 111 #[derive(Copy, Clone, Debug)] 112 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 113 pub struct Imm16(u16); 114 115 impl Imm16 { 116 #[must_use] new(value: u16) -> Self117 pub fn new(value: u16) -> Self { 118 Self(value) 119 } 120 121 #[must_use] value(&self) -> u16122 pub fn value(&self) -> u16 { 123 self.0 124 } 125 encode(&self, sink: &mut impl CodeSink)126 pub fn encode(&self, sink: &mut impl CodeSink) { 127 sink.put2(self.0); 128 } 129 } 130 131 impl From<u16> for Imm16 { from(imm16: u16) -> Self132 fn from(imm16: u16) -> Self { 133 Self(imm16) 134 } 135 } 136 137 impl TryFrom<i32> for Imm16 { 138 type Error = core::num::TryFromIntError; try_from(simm32: i32) -> Result<Self, Self::Error>139 fn try_from(simm32: i32) -> Result<Self, Self::Error> { 140 Ok(Self(u16::try_from(simm32)?)) 141 } 142 } 143 144 impl fmt::Display for Imm16 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result145 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 146 write!(f, "$0x{:x}", self.0) 147 } 148 } 149 150 /// A _signed_ 16-bit immediate operand (suitable for sign extension). 151 #[derive(Copy, Clone, Debug)] 152 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 153 pub struct Simm16(i16); 154 155 impl Simm16 { 156 #[must_use] new(value: i16) -> Self157 pub fn new(value: i16) -> Self { 158 Self(value) 159 } 160 161 #[must_use] value(&self) -> i16162 pub fn value(&self) -> i16 { 163 self.0 164 } 165 encode(&self, sink: &mut impl CodeSink)166 pub fn encode(&self, sink: &mut impl CodeSink) { 167 sink.put2(self.0 as u16); 168 } 169 170 #[must_use] to_string(&self, extend: Extension) -> String171 pub fn to_string(&self, extend: Extension) -> String { 172 use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord}; 173 match extend { 174 None => hexify!(self.0), 175 SignExtendWord => unreachable!("the 16-bit value is already 16 bits"), 176 SignExtendLong => hexify_sign_extend!(self.0, i16 => i32), 177 SignExtendQuad => hexify_sign_extend!(self.0, i16 => i64), 178 } 179 } 180 } 181 182 impl From<i16> for Simm16 { from(simm16: i16) -> Self183 fn from(simm16: i16) -> Self { 184 Self(simm16) 185 } 186 } 187 188 impl TryFrom<i32> for Simm16 { 189 type Error = core::num::TryFromIntError; try_from(simm32: i32) -> Result<Self, Self::Error>190 fn try_from(simm32: i32) -> Result<Self, Self::Error> { 191 Ok(Self(i16::try_from(simm32)?)) 192 } 193 } 194 195 /// A 32-bit immediate operand. 196 /// 197 /// Note that, "in 64-bit mode, the typical size of immediate operands remains 198 /// 32 bits. When the operand size is 64 bits, the processor sign-extends all 199 /// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5). 200 #[derive(Copy, Clone, Debug)] 201 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 202 pub struct Imm32(u32); 203 204 impl Imm32 { 205 #[must_use] new(value: u32) -> Self206 pub fn new(value: u32) -> Self { 207 Self(value) 208 } 209 210 #[must_use] value(&self) -> u32211 pub fn value(&self) -> u32 { 212 self.0 213 } 214 encode(&self, sink: &mut impl CodeSink)215 pub fn encode(&self, sink: &mut impl CodeSink) { 216 sink.put4(self.0); 217 } 218 } 219 220 impl From<u32> for Imm32 { from(imm32: u32) -> Self221 fn from(imm32: u32) -> Self { 222 Self(imm32) 223 } 224 } 225 226 impl From<i32> for Imm32 { from(simm32: i32) -> Self227 fn from(simm32: i32) -> Self { 228 // TODO: should this be a `TryFrom`? 229 Self(simm32 as u32) 230 } 231 } 232 233 impl fmt::Display for Imm32 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result234 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 235 write!(f, "$0x{:x}", self.0) 236 } 237 } 238 239 /// A _signed_ 32-bit immediate operand (suitable for sign extension). 240 /// 241 /// Note that, "in 64-bit mode, the typical size of immediate operands remains 242 /// 32 bits. When the operand size is 64 bits, the processor sign-extends all 243 /// immediates to 64 bits prior to their use" (Intel SDM Vol. 2, 2.2.1.5). 244 #[derive(Copy, Clone, Debug)] 245 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 246 pub struct Simm32(i32); 247 248 impl Simm32 { 249 #[must_use] new(value: i32) -> Self250 pub fn new(value: i32) -> Self { 251 Self(value) 252 } 253 254 #[must_use] value(&self) -> i32255 pub fn value(&self) -> i32 { 256 self.0 257 } 258 encode(&self, sink: &mut impl CodeSink)259 pub fn encode(&self, sink: &mut impl CodeSink) { 260 sink.put4(self.0 as u32); 261 } 262 263 #[must_use] to_string(&self, extend: Extension) -> String264 pub fn to_string(&self, extend: Extension) -> String { 265 use Extension::{None, SignExtendLong, SignExtendQuad, SignExtendWord}; 266 match extend { 267 None => hexify!(self.0), 268 SignExtendWord => unreachable!("cannot sign extend a 32-bit value to 16 bits"), 269 SignExtendLong => unreachable!("the 32-bit value is already 32 bits"), 270 SignExtendQuad => hexify_sign_extend!(self.0, i32 => i64), 271 } 272 } 273 } 274 275 impl From<i32> for Simm32 { from(simm32: i32) -> Self276 fn from(simm32: i32) -> Self { 277 Self(simm32) 278 } 279 } 280 281 /// A 64-bit immediate operand. 282 /// 283 /// This form is quite rare; see certain `mov` instructions. 284 #[derive(Copy, Clone, Debug)] 285 #[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))] 286 pub struct Imm64(u64); 287 288 impl Imm64 { 289 #[must_use] new(value: u64) -> Self290 pub fn new(value: u64) -> Self { 291 Self(value) 292 } 293 294 #[must_use] value(&self) -> u64295 pub fn value(&self) -> u64 { 296 self.0 297 } 298 encode(&self, sink: &mut impl CodeSink)299 pub fn encode(&self, sink: &mut impl CodeSink) { 300 sink.put8(self.0); 301 } 302 } 303 304 impl From<u64> for Imm64 { from(imm64: u64) -> Self305 fn from(imm64: u64) -> Self { 306 Self(imm64) 307 } 308 } 309 310 impl fmt::Display for Imm64 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result311 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 312 write!(f, "$0x{:x}", self.0) 313 } 314 } 315 316 /// Define the ways an immediate may be sign- or zero-extended. 317 #[derive(Clone, Copy, Debug)] 318 pub enum Extension { 319 None, 320 SignExtendQuad, 321 SignExtendLong, 322 SignExtendWord, 323 } 324