1 pub mod encode { 2 use crate::{CodeSink, KnownOffsetTable, inst}; 3 4 /// `NOP` 5 pub fn nop_1b(_: &inst::nop_1b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 6 buf.put1(0x90); 7 } 8 9 /// `66 NOP` 10 pub fn nop_2b(_: &inst::nop_2b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 11 buf.put1(0x66); 12 buf.put1(0x90); 13 } 14 15 /// `NOP DWORD ptr [EAX]` 16 pub fn nop_3b(_: &inst::nop_3b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 17 buf.put1(0x0F); 18 buf.put1(0x1F); 19 buf.put1(0x00); 20 } 21 22 /// `NOP DWORD ptr [EAX + 00H]` 23 pub fn nop_4b(_: &inst::nop_4b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 24 buf.put1(0x0F); 25 buf.put1(0x1F); 26 buf.put1(0x40); 27 buf.put1(0x00); 28 } 29 30 /// `NOP DWORD ptr [EAX + EAX*1 + 00H]` 31 pub fn nop_5b(_: &inst::nop_5b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 32 buf.put1(0x0F); 33 buf.put1(0x1F); 34 buf.put1(0x44); 35 buf.put2(0x00_00); 36 } 37 38 /// `66 NOP DWORD ptr [EAX + EAX*1 + 00H]` 39 pub fn nop_6b(_: &inst::nop_6b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 40 buf.put1(0x66); 41 buf.put1(0x0F); 42 buf.put1(0x1F); 43 buf.put1(0x44); 44 buf.put2(0x00_00); 45 } 46 47 /// `NOP DWORD ptr [EAX + 00000000H]` 48 pub fn nop_7b(_: &inst::nop_7b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 49 buf.put1(0x0F); 50 buf.put1(0x1F); 51 buf.put1(0x80); 52 buf.put4(0x00_00_00_00); 53 } 54 55 /// `NOP DWORD ptr [EAX + EAX*1 + 00000000H]` 56 pub fn nop_8b(_: &inst::nop_8b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 57 buf.put1(0x0F); 58 buf.put1(0x1F); 59 buf.put1(0x84); 60 buf.put1(0x00); 61 buf.put4(0x00_00_00_00); 62 } 63 64 /// `66 NOP DWORD ptr [EAX + EAX*1 + 00000000H]` 65 pub fn nop_9b(_: &inst::nop_9b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) { 66 buf.put1(0x66); 67 buf.put1(0x0F); 68 buf.put1(0x1F); 69 buf.put1(0x84); 70 buf.put1(0x00); 71 buf.put4(0x00_00_00_00); 72 } 73 } 74 75 pub mod mnemonic { 76 use crate::inst; 77 use crate::{Registers, XmmMem}; 78 use std::borrow::Cow; 79 80 macro_rules! lock { 81 ($name:tt => $mnemonic:expr) => { 82 pub fn $name<R: Registers>(_: &inst::$name<R>) -> Cow<'static, str> { 83 Cow::Borrowed(concat!("lock ", $mnemonic)) 84 } 85 }; 86 } 87 88 lock!(lock_addb_mi => "addb"); 89 lock!(lock_addw_mi => "addw"); 90 lock!(lock_addl_mi => "addl"); 91 lock!(lock_addq_mi_sxl => "addq"); 92 lock!(lock_addl_mi_sxb => "addl"); 93 lock!(lock_addq_mi_sxb => "addq"); 94 lock!(lock_addb_mr => "addb"); 95 lock!(lock_addw_mr => "addw"); 96 lock!(lock_addl_mr => "addl"); 97 lock!(lock_addq_mr => "addq"); 98 99 lock!(lock_adcb_mi => "adcb"); 100 lock!(lock_adcw_mi => "adcw"); 101 lock!(lock_adcl_mi => "adcl"); 102 lock!(lock_adcq_mi_sxl => "adcq"); 103 lock!(lock_adcl_mi_sxb => "adcl"); 104 lock!(lock_adcq_mi_sxb => "adcq"); 105 lock!(lock_adcb_mr => "adcb"); 106 lock!(lock_adcw_mr => "adcw"); 107 lock!(lock_adcl_mr => "adcl"); 108 lock!(lock_adcq_mr => "adcq"); 109 110 lock!(lock_subb_mi => "subb"); 111 lock!(lock_subw_mi => "subw"); 112 lock!(lock_subl_mi => "subl"); 113 lock!(lock_subq_mi_sxl => "subq"); 114 lock!(lock_subl_mi_sxb => "subl"); 115 lock!(lock_subq_mi_sxb => "subq"); 116 lock!(lock_subb_mr => "subb"); 117 lock!(lock_subw_mr => "subw"); 118 lock!(lock_subl_mr => "subl"); 119 lock!(lock_subq_mr => "subq"); 120 121 lock!(lock_sbbb_mi => "sbbb"); 122 lock!(lock_sbbw_mi => "sbbw"); 123 lock!(lock_sbbl_mi => "sbbl"); 124 lock!(lock_sbbq_mi_sxl => "sbbq"); 125 lock!(lock_sbbl_mi_sxb => "sbbl"); 126 lock!(lock_sbbq_mi_sxb => "sbbq"); 127 lock!(lock_sbbb_mr => "sbbb"); 128 lock!(lock_sbbw_mr => "sbbw"); 129 lock!(lock_sbbl_mr => "sbbl"); 130 lock!(lock_sbbq_mr => "sbbq"); 131 132 lock!(lock_andb_mi => "andb"); 133 lock!(lock_andw_mi => "andw"); 134 lock!(lock_andl_mi => "andl"); 135 lock!(lock_andq_mi_sxl => "andq"); 136 lock!(lock_andl_mi_sxb => "andl"); 137 lock!(lock_andq_mi_sxb => "andq"); 138 lock!(lock_andb_mr => "andb"); 139 lock!(lock_andw_mr => "andw"); 140 lock!(lock_andl_mr => "andl"); 141 lock!(lock_andq_mr => "andq"); 142 143 lock!(lock_orb_mi => "orb"); 144 lock!(lock_orw_mi => "orw"); 145 lock!(lock_orl_mi => "orl"); 146 lock!(lock_orq_mi_sxl => "orq"); 147 lock!(lock_orl_mi_sxb => "orl"); 148 lock!(lock_orq_mi_sxb => "orq"); 149 lock!(lock_orb_mr => "orb"); 150 lock!(lock_orw_mr => "orw"); 151 lock!(lock_orl_mr => "orl"); 152 lock!(lock_orq_mr => "orq"); 153 154 lock!(lock_xorb_mi => "xorb"); 155 lock!(lock_xorw_mi => "xorw"); 156 lock!(lock_xorl_mi => "xorl"); 157 lock!(lock_xorq_mi_sxl => "xorq"); 158 lock!(lock_xorl_mi_sxb => "xorl"); 159 lock!(lock_xorq_mi_sxb => "xorq"); 160 lock!(lock_xorb_mr => "xorb"); 161 lock!(lock_xorw_mr => "xorw"); 162 lock!(lock_xorl_mr => "xorl"); 163 lock!(lock_xorq_mr => "xorq"); 164 165 lock!(lock_xaddb_mr => "xaddb"); 166 lock!(lock_xaddw_mr => "xaddw"); 167 lock!(lock_xaddl_mr => "xaddl"); 168 lock!(lock_xaddq_mr => "xaddq"); 169 170 lock!(lock_cmpxchgb_mr => "cmpxchgb"); 171 lock!(lock_cmpxchgw_mr => "cmpxchgw"); 172 lock!(lock_cmpxchgl_mr => "cmpxchgl"); 173 lock!(lock_cmpxchgq_mr => "cmpxchgq"); 174 lock!(lock_cmpxchg16b_m => "cmpxchg16b"); 175 176 pub fn vcvtpd2ps_a<R: Registers>(inst: &inst::vcvtpd2ps_a<R>) -> Cow<'static, str> { 177 match inst.xmm_m128 { 178 XmmMem::Xmm(_) => "vcvtpd2ps".into(), 179 XmmMem::Mem(_) => "vcvtpd2psx".into(), 180 } 181 } 182 183 pub fn vcvttpd2dq_a<R: Registers>(inst: &inst::vcvttpd2dq_a<R>) -> Cow<'static, str> { 184 match inst.xmm_m128 { 185 XmmMem::Xmm(_) => "vcvttpd2dq".into(), 186 XmmMem::Mem(_) => "vcvttpd2dqx".into(), 187 } 188 } 189 } 190 191 pub mod display { 192 use crate::inst; 193 use crate::{Amode, Gpr, Registers, Size}; 194 use std::fmt; 195 196 pub fn pseudo_op(imm: u8) -> &'static str { 197 match imm { 198 0 => "eq", 199 1 => "lt", 200 2 => "le", 201 3 => "unord", 202 4 => "neq", 203 5 => "nlt", 204 6 => "nle", 205 7 => "ord", 206 _ => panic!("not a valid immediate for pseudo op"), 207 } 208 } 209 210 pub fn cmpps_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpps_a<R>) -> fmt::Result { 211 let xmm1 = inst.xmm1.to_string(); 212 let xmm_m128 = inst.xmm_m128.to_string(); 213 let imm8 = inst.imm8.to_string(); 214 if inst.imm8.value() > 7 { 215 return write!(f, "{} {imm8}, {xmm_m128}, {xmm1}", inst.mnemonic()); 216 } 217 let name = format!("cmp{}ps", pseudo_op(inst.imm8.value())); 218 write!(f, "{name} {xmm_m128}, {xmm1}") 219 } 220 221 pub fn cmpss_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpss_a<R>) -> fmt::Result { 222 let xmm1 = inst.xmm1.to_string(); 223 let xmm_m32 = inst.xmm_m32.to_string(); 224 let imm8 = inst.imm8.to_string(); 225 if inst.imm8.value() > 7 { 226 return write!(f, "{} {imm8}, {xmm_m32}, {xmm1}", inst.mnemonic()); 227 } 228 let name = format!("cmp{}ss", pseudo_op(inst.imm8.value())); 229 write!(f, "{name} {xmm_m32}, {xmm1}") 230 } 231 232 pub fn cmpsd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpsd_a<R>) -> fmt::Result { 233 let xmm1 = inst.xmm1.to_string(); 234 let xmm_m64 = inst.xmm_m64.to_string(); 235 let imm8 = inst.imm8.to_string(); 236 if inst.imm8.value() > 7 { 237 return write!(f, "{} {imm8}, {xmm_m64}, {xmm1}", inst.mnemonic()); 238 } 239 let name = format!("cmp{}sd", pseudo_op(inst.imm8.value())); 240 write!(f, "{name} {xmm_m64}, {xmm1}") 241 } 242 243 pub fn cmppd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmppd_a<R>) -> fmt::Result { 244 let xmm1 = inst.xmm1.to_string(); 245 let xmm_m128 = inst.xmm_m128.to_string(); 246 let imm8 = inst.imm8.to_string(); 247 if inst.imm8.value() > 7 { 248 return write!(f, "{} {imm8}, {xmm_m128}, {xmm1}", inst.mnemonic()); 249 } 250 let name = format!("cmp{}pd", pseudo_op(inst.imm8.value())); 251 write!(f, "{name} {xmm_m128}, {xmm1}") 252 } 253 254 pub fn nop_1b(f: &mut fmt::Formatter, _: &inst::nop_1b) -> fmt::Result { 255 write!(f, "nop") 256 } 257 258 pub fn nop_2b(f: &mut fmt::Formatter, _: &inst::nop_2b) -> fmt::Result { 259 write!(f, "nop") 260 } 261 262 pub fn nop_3b(f: &mut fmt::Formatter, _: &inst::nop_3b) -> fmt::Result { 263 write!(f, "nopl (%rax)") 264 } 265 266 pub fn nop_4b(f: &mut fmt::Formatter, _: &inst::nop_4b) -> fmt::Result { 267 write!(f, "nopl (%rax)") 268 } 269 270 pub fn nop_5b(f: &mut fmt::Formatter, _: &inst::nop_5b) -> fmt::Result { 271 write!(f, "nopl (%rax, %rax)") 272 } 273 274 pub fn nop_6b(f: &mut fmt::Formatter, _: &inst::nop_6b) -> fmt::Result { 275 write!(f, "nopw (%rax, %rax)") 276 } 277 278 pub fn nop_7b(f: &mut fmt::Formatter, _: &inst::nop_7b) -> fmt::Result { 279 write!(f, "nopl (%rax)") 280 } 281 282 pub fn nop_8b(f: &mut fmt::Formatter, _: &inst::nop_8b) -> fmt::Result { 283 write!(f, "nopl (%rax, %rax)") 284 } 285 286 pub fn nop_9b(f: &mut fmt::Formatter, _: &inst::nop_9b) -> fmt::Result { 287 write!(f, "nopw (%rax, %rax)") 288 } 289 290 pub fn xchgb_rm<R: Registers>( 291 f: &mut fmt::Formatter<'_>, 292 inst: &inst::xchgb_rm<R>, 293 ) -> fmt::Result { 294 let inst::xchgb_rm { r8, m8 } = inst; 295 xchg_rm::<R>(f, r8, m8, Size::Byte) 296 } 297 298 pub fn xchgw_rm<R: Registers>( 299 f: &mut fmt::Formatter<'_>, 300 inst: &inst::xchgw_rm<R>, 301 ) -> fmt::Result { 302 let inst::xchgw_rm { r16, m16 } = inst; 303 xchg_rm::<R>(f, r16, m16, Size::Word) 304 } 305 306 pub fn xchgl_rm<R: Registers>( 307 f: &mut fmt::Formatter<'_>, 308 inst: &inst::xchgl_rm<R>, 309 ) -> fmt::Result { 310 let inst::xchgl_rm { r32, m32 } = inst; 311 xchg_rm::<R>(f, r32, m32, Size::Doubleword) 312 } 313 314 pub fn xchgq_rm<R: Registers>( 315 f: &mut fmt::Formatter<'_>, 316 inst: &inst::xchgq_rm<R>, 317 ) -> fmt::Result { 318 let inst::xchgq_rm { r64, m64 } = inst; 319 xchg_rm::<R>(f, r64, m64, Size::Quadword) 320 } 321 322 /// Swap the order of printing (register first) to match Capstone. 323 fn xchg_rm<R: Registers>( 324 f: &mut fmt::Formatter<'_>, 325 reg: &Gpr<R::ReadWriteGpr>, 326 mem: &Amode<R::ReadGpr>, 327 size: Size, 328 ) -> fmt::Result { 329 let reg = reg.to_string(size); 330 let mem = mem.to_string(); 331 let suffix = match size { 332 Size::Byte => "b", 333 Size::Word => "w", 334 Size::Doubleword => "l", 335 Size::Quadword => "q", 336 }; 337 write!(f, "xchg{suffix} {reg}, {mem}") 338 } 339 } 340 341 pub mod visit { 342 use crate::inst::*; 343 use crate::{Amode, Fixed, Gpr, GprMem, RegisterVisitor, Registers, gpr}; 344 345 pub fn mulxl_rvm<R: Registers>(mulx: &mut mulxl_rvm<R>, visitor: &mut impl RegisterVisitor<R>) { 346 visit_mulx( 347 &mut mulx.r32a, 348 &mut mulx.r32b, 349 &mut mulx.rm32, 350 &mut mulx.edx, 351 visitor, 352 ) 353 } 354 355 pub fn mulxq_rvm<R: Registers>(mulx: &mut mulxq_rvm<R>, visitor: &mut impl RegisterVisitor<R>) { 356 visit_mulx( 357 &mut mulx.r64a, 358 &mut mulx.r64b, 359 &mut mulx.rm64, 360 &mut mulx.rdx, 361 visitor, 362 ) 363 } 364 365 /// Both mulxl and mulxq have custom register allocator behavior where if the 366 /// two writable registers are the same then only one is flagged as writable. 367 /// That represents how when they're both the same only one register is written, 368 /// not both. 369 fn visit_mulx<R: Registers>( 370 ra: &mut Gpr<R::WriteGpr>, 371 rb: &mut Gpr<R::WriteGpr>, 372 src1: &mut GprMem<R::ReadGpr, R::ReadGpr>, 373 src2: &mut Fixed<R::ReadGpr, { gpr::enc::RDX }>, 374 visitor: &mut impl RegisterVisitor<R>, 375 ) { 376 if ra == rb { 377 visitor.write_gpr(ra.as_mut()); 378 *rb = *ra; 379 } else { 380 visitor.write_gpr(ra.as_mut()); 381 visitor.write_gpr(rb.as_mut()); 382 } 383 visitor.read_gpr_mem(src1); 384 let enc = src2.expected_enc(); 385 visitor.fixed_read_gpr(&mut src2.0, enc); 386 } 387 388 pub fn lock_xaddb_mr<R: Registers>( 389 lock_xadd: &mut lock_xaddb_mr<R>, 390 visitor: &mut impl RegisterVisitor<R>, 391 ) { 392 let lock_xaddb_mr { r8, m8 } = lock_xadd; 393 lock_xadd_mr(r8, m8, visitor) 394 } 395 396 pub fn lock_xaddw_mr<R: Registers>( 397 lock_xadd: &mut lock_xaddw_mr<R>, 398 visitor: &mut impl RegisterVisitor<R>, 399 ) { 400 let lock_xaddw_mr { r16, m16 } = lock_xadd; 401 lock_xadd_mr(r16, m16, visitor) 402 } 403 404 pub fn lock_xaddl_mr<R: Registers>( 405 lock_xadd: &mut lock_xaddl_mr<R>, 406 visitor: &mut impl RegisterVisitor<R>, 407 ) { 408 let lock_xaddl_mr { r32, m32 } = lock_xadd; 409 lock_xadd_mr(r32, m32, visitor) 410 } 411 412 pub fn lock_xaddq_mr<R: Registers>( 413 lock_xadd: &mut lock_xaddq_mr<R>, 414 visitor: &mut impl RegisterVisitor<R>, 415 ) { 416 let lock_xaddq_mr { r64, m64 } = lock_xadd; 417 lock_xadd_mr(r64, m64, visitor) 418 } 419 420 /// Intel says the memory operand comes first, but regalloc requires the 421 /// register operand comes first, so the custom visit implementation here 422 /// resolves that. 423 fn lock_xadd_mr<R: Registers>( 424 reg: &mut Gpr<R::ReadWriteGpr>, 425 mem: &mut Amode<R::ReadGpr>, 426 visitor: &mut impl RegisterVisitor<R>, 427 ) { 428 visitor.read_write_gpr(reg.as_mut()); 429 visitor.read_amode(mem); 430 } 431 } 432