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