1 pub mod encode { 2 use crate::{CodeSink, inst}; 3 4 /// `NOP` 5 pub fn nop_1b(_: &inst::nop_1b, buf: &mut impl CodeSink) { 6 buf.put1(0x90); 7 } 8 9 /// `66 NOP` 10 pub fn nop_2b(_: &inst::nop_2b, buf: &mut impl CodeSink) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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, GprMem, Registers, Size}; 194 use std::fmt; 195 196 pub fn callq_d(f: &mut fmt::Formatter, inst: &inst::callq_d) -> fmt::Result { 197 let inst::callq_d { imm32 } = inst; 198 display_displacement(f, "callq", i64::from(imm32.value()) + 5) 199 } 200 201 pub fn callq_m<R: Registers>(f: &mut fmt::Formatter, inst: &inst::callq_m<R>) -> fmt::Result { 202 let inst::callq_m { rm64 } = inst; 203 let op = rm64.to_string(Size::Quadword); 204 write!(f, "callq *{op}") 205 } 206 207 /// Return the predicate string used for the immediate of a `cmp*` 208 /// instruction. 209 fn pred_as_str(imm: u8) -> &'static str { 210 match imm { 211 0 => "eq", 212 1 => "lt", 213 2 => "le", 214 3 => "unord", 215 4 => "neq", 216 5 => "nlt", 217 6 => "nle", 218 7 => "ord", 219 _ => panic!("not a valid predicate for `cmp*`"), 220 } 221 } 222 223 pub fn cmpss_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpss_a<R>) -> fmt::Result { 224 let xmm1 = inst.xmm1.to_string(); 225 let xmm_m32 = inst.xmm_m32.to_string(); 226 let pred = inst.imm8.value(); 227 if pred > 7 { 228 let imm8 = inst.imm8.to_string(); 229 write!(f, "cmpss {imm8}, {xmm_m32}, {xmm1}") 230 } else { 231 write!(f, "cmp{}ss {xmm_m32}, {xmm1}", pred_as_str(pred)) 232 } 233 } 234 235 pub fn cmpsd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpsd_a<R>) -> fmt::Result { 236 let xmm1 = inst.xmm1.to_string(); 237 let xmm_m64 = inst.xmm_m64.to_string(); 238 let pred = inst.imm8.value(); 239 if pred > 7 { 240 let imm8 = inst.imm8.to_string(); 241 write!(f, "cmpsd {imm8}, {xmm_m64}, {xmm1}") 242 } else { 243 write!(f, "cmp{}sd {xmm_m64}, {xmm1}", pred_as_str(pred)) 244 } 245 } 246 247 pub fn cmpps_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpps_a<R>) -> fmt::Result { 248 let xmm1 = inst.xmm1.to_string(); 249 let xmm_m128 = inst.xmm_m128.to_string(); 250 let pred = inst.imm8.value(); 251 if pred > 7 { 252 let imm8 = inst.imm8.to_string(); 253 write!(f, "cmpps {imm8}, {xmm_m128}, {xmm1}") 254 } else { 255 write!(f, "cmp{}ps {xmm_m128}, {xmm1}", pred_as_str(pred)) 256 } 257 } 258 259 pub fn cmppd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmppd_a<R>) -> fmt::Result { 260 let xmm1 = inst.xmm1.to_string(); 261 let xmm_m128 = inst.xmm_m128.to_string(); 262 let pred = inst.imm8.value(); 263 if pred > 7 { 264 let imm8 = inst.imm8.to_string(); 265 write!(f, "cmppd {imm8}, {xmm_m128}, {xmm1}") 266 } else { 267 write!(f, "cmp{}pd {xmm_m128}, {xmm1}", pred_as_str(pred)) 268 } 269 } 270 271 /// Return the predicate string used for the immediate of a `vcmp*` 272 /// instruction; this is a more complex version of `pred_as_str`. 273 fn vex_pred_as_str(imm: u8) -> &'static str { 274 match imm { 275 0x0 => "eq", 276 0x1 => "lt", 277 0x2 => "le", 278 0x3 => "unord", 279 0x4 => "neq", 280 0x5 => "nlt", 281 0x6 => "nle", 282 0x7 => "ord", 283 0x8 => "eq_uq", 284 0x9 => "nge", 285 0xa => "ngt", 286 0xb => "false", 287 0xc => "neq_oq", 288 0xd => "ge", 289 0xe => "gt", 290 0xf => "true", 291 0x10 => "eq_os", 292 0x11 => "lt_oq", 293 0x12 => "le_oq", 294 0x13 => "unord_s", 295 0x14 => "neq_us", 296 0x15 => "nlt_uq", 297 0x16 => "nle_uq", 298 0x17 => "ord_s", 299 0x18 => "eq_us", 300 0x19 => "nge_uq", 301 0x1a => "ngt_uq", 302 0x1b => "false_os", 303 0x1c => "neq_os", 304 0x1d => "ge_oq", 305 0x1e => "gt_oq", 306 0x1f => "true_us", 307 _ => panic!("not a valid predicate for `cmp*`"), 308 } 309 } 310 311 pub fn vcmpss_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpss_b<R>) -> fmt::Result { 312 let xmm1 = inst.xmm1.to_string(); 313 let xmm2 = inst.xmm2.to_string(); 314 let xmm_m32 = inst.xmm_m32.to_string(); 315 let pred = inst.imm8.value(); 316 if pred > 0x1f { 317 let imm8 = inst.imm8.to_string(); 318 write!(f, "vcmpss {imm8}, {xmm_m32}, {xmm2}, {xmm1}") 319 } else { 320 write!( 321 f, 322 "vcmp{}ss {xmm_m32}, {xmm2}, {xmm1}", 323 vex_pred_as_str(pred) 324 ) 325 } 326 } 327 328 pub fn vcmpsd_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpsd_b<R>) -> fmt::Result { 329 let xmm1 = inst.xmm1.to_string(); 330 let xmm2 = inst.xmm2.to_string(); 331 let xmm_m64 = inst.xmm_m64.to_string(); 332 let pred = inst.imm8.value(); 333 if pred > 0x1f { 334 let imm8 = inst.imm8.to_string(); 335 write!(f, "vcmpsd {imm8}, {xmm_m64}, {xmm2}, {xmm1}") 336 } else { 337 write!( 338 f, 339 "vcmp{}sd {xmm_m64}, {xmm2}, {xmm1}", 340 vex_pred_as_str(pred) 341 ) 342 } 343 } 344 345 pub fn vcmpps_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpps_b<R>) -> fmt::Result { 346 let xmm1 = inst.xmm1.to_string(); 347 let xmm2 = inst.xmm2.to_string(); 348 let xmm_m128 = inst.xmm_m128.to_string(); 349 let pred = inst.imm8.value(); 350 if pred > 0x1f { 351 let imm8 = inst.imm8.to_string(); 352 write!(f, "vcmpps {imm8}, {xmm_m128}, {xmm2}, {xmm1}") 353 } else { 354 write!( 355 f, 356 "vcmp{}ps {xmm_m128}, {xmm2}, {xmm1}", 357 vex_pred_as_str(pred) 358 ) 359 } 360 } 361 362 pub fn vcmppd_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmppd_b<R>) -> fmt::Result { 363 let xmm1 = inst.xmm1.to_string(); 364 let xmm2 = inst.xmm2.to_string(); 365 let xmm_m128 = inst.xmm_m128.to_string(); 366 let pred = inst.imm8.value(); 367 if pred > 0x1f { 368 let imm8 = inst.imm8.to_string(); 369 write!(f, "vcmppd {imm8}, {xmm_m128}, {xmm2}, {xmm1}") 370 } else { 371 write!( 372 f, 373 "vcmp{}pd {xmm_m128}, {xmm2}, {xmm1}", 374 vex_pred_as_str(pred) 375 ) 376 } 377 } 378 379 pub fn nop_1b(f: &mut fmt::Formatter, _: &inst::nop_1b) -> fmt::Result { 380 write!(f, "nop") 381 } 382 383 pub fn nop_2b(f: &mut fmt::Formatter, _: &inst::nop_2b) -> fmt::Result { 384 write!(f, "nop") 385 } 386 387 pub fn nop_3b(f: &mut fmt::Formatter, _: &inst::nop_3b) -> fmt::Result { 388 write!(f, "nopl (%rax)") 389 } 390 391 pub fn nop_4b(f: &mut fmt::Formatter, _: &inst::nop_4b) -> fmt::Result { 392 write!(f, "nopl (%rax)") 393 } 394 395 pub fn nop_5b(f: &mut fmt::Formatter, _: &inst::nop_5b) -> fmt::Result { 396 write!(f, "nopl (%rax, %rax)") 397 } 398 399 pub fn nop_6b(f: &mut fmt::Formatter, _: &inst::nop_6b) -> fmt::Result { 400 write!(f, "nopw (%rax, %rax)") 401 } 402 403 pub fn nop_7b(f: &mut fmt::Formatter, _: &inst::nop_7b) -> fmt::Result { 404 write!(f, "nopl (%rax)") 405 } 406 407 pub fn nop_8b(f: &mut fmt::Formatter, _: &inst::nop_8b) -> fmt::Result { 408 write!(f, "nopl (%rax, %rax)") 409 } 410 411 pub fn nop_9b(f: &mut fmt::Formatter, _: &inst::nop_9b) -> fmt::Result { 412 write!(f, "nopw (%rax, %rax)") 413 } 414 415 pub fn xchgb_rm<R: Registers>( 416 f: &mut fmt::Formatter<'_>, 417 inst: &inst::xchgb_rm<R>, 418 ) -> fmt::Result { 419 let inst::xchgb_rm { r8, m8 } = inst; 420 xchg_rm::<R>(f, r8, m8, Size::Byte) 421 } 422 423 pub fn xchgw_rm<R: Registers>( 424 f: &mut fmt::Formatter<'_>, 425 inst: &inst::xchgw_rm<R>, 426 ) -> fmt::Result { 427 let inst::xchgw_rm { r16, m16 } = inst; 428 xchg_rm::<R>(f, r16, m16, Size::Word) 429 } 430 431 pub fn xchgl_rm<R: Registers>( 432 f: &mut fmt::Formatter<'_>, 433 inst: &inst::xchgl_rm<R>, 434 ) -> fmt::Result { 435 let inst::xchgl_rm { r32, m32 } = inst; 436 xchg_rm::<R>(f, r32, m32, Size::Doubleword) 437 } 438 439 pub fn xchgq_rm<R: Registers>( 440 f: &mut fmt::Formatter<'_>, 441 inst: &inst::xchgq_rm<R>, 442 ) -> fmt::Result { 443 let inst::xchgq_rm { r64, m64 } = inst; 444 xchg_rm::<R>(f, r64, m64, Size::Quadword) 445 } 446 447 /// Swap the order of printing (register first) to match Capstone. 448 fn xchg_rm<R: Registers>( 449 f: &mut fmt::Formatter<'_>, 450 reg: &Gpr<R::ReadWriteGpr>, 451 mem: &Amode<R::ReadGpr>, 452 size: Size, 453 ) -> fmt::Result { 454 let reg = reg.to_string(size); 455 let mem = mem.to_string(); 456 let suffix = match size { 457 Size::Byte => "b", 458 Size::Word => "w", 459 Size::Doubleword => "l", 460 Size::Quadword => "q", 461 }; 462 write!(f, "xchg{suffix} {reg}, {mem}") 463 } 464 465 pub fn sarb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarb_m1<R>) -> fmt::Result { 466 let inst::sarb_m1 { rm8 } = inst; 467 shift_m1::<R>(f, "sarb", rm8, Size::Byte) 468 } 469 470 pub fn sarw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarw_m1<R>) -> fmt::Result { 471 let inst::sarw_m1 { rm16 } = inst; 472 shift_m1::<R>(f, "sarw", rm16, Size::Word) 473 } 474 475 pub fn sarl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarl_m1<R>) -> fmt::Result { 476 let inst::sarl_m1 { rm32 } = inst; 477 shift_m1::<R>(f, "sarl", rm32, Size::Doubleword) 478 } 479 480 pub fn sarq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarq_m1<R>) -> fmt::Result { 481 let inst::sarq_m1 { rm64 } = inst; 482 shift_m1::<R>(f, "sarq", rm64, Size::Quadword) 483 } 484 485 pub fn shlb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlb_m1<R>) -> fmt::Result { 486 let inst::shlb_m1 { rm8 } = inst; 487 shift_m1::<R>(f, "shlb", rm8, Size::Byte) 488 } 489 490 pub fn shlw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlw_m1<R>) -> fmt::Result { 491 let inst::shlw_m1 { rm16 } = inst; 492 shift_m1::<R>(f, "shlw", rm16, Size::Word) 493 } 494 495 pub fn shll_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shll_m1<R>) -> fmt::Result { 496 let inst::shll_m1 { rm32 } = inst; 497 shift_m1::<R>(f, "shll", rm32, Size::Doubleword) 498 } 499 500 pub fn shlq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlq_m1<R>) -> fmt::Result { 501 let inst::shlq_m1 { rm64 } = inst; 502 shift_m1::<R>(f, "shlq", rm64, Size::Quadword) 503 } 504 505 pub fn shrb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrb_m1<R>) -> fmt::Result { 506 let inst::shrb_m1 { rm8 } = inst; 507 shift_m1::<R>(f, "shrb", rm8, Size::Byte) 508 } 509 510 pub fn shrw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrw_m1<R>) -> fmt::Result { 511 let inst::shrw_m1 { rm16 } = inst; 512 shift_m1::<R>(f, "shrw", rm16, Size::Word) 513 } 514 515 pub fn shrl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrl_m1<R>) -> fmt::Result { 516 let inst::shrl_m1 { rm32 } = inst; 517 shift_m1::<R>(f, "shrl", rm32, Size::Doubleword) 518 } 519 520 pub fn shrq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrq_m1<R>) -> fmt::Result { 521 let inst::shrq_m1 { rm64 } = inst; 522 shift_m1::<R>(f, "shrq", rm64, Size::Quadword) 523 } 524 525 pub fn rorb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorb_m1<R>) -> fmt::Result { 526 let inst::rorb_m1 { rm8 } = inst; 527 shift_m1::<R>(f, "rorb", rm8, Size::Byte) 528 } 529 530 pub fn rorw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorw_m1<R>) -> fmt::Result { 531 let inst::rorw_m1 { rm16 } = inst; 532 shift_m1::<R>(f, "rorw", rm16, Size::Word) 533 } 534 535 pub fn rorl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorl_m1<R>) -> fmt::Result { 536 let inst::rorl_m1 { rm32 } = inst; 537 shift_m1::<R>(f, "rorl", rm32, Size::Doubleword) 538 } 539 540 pub fn rorq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorq_m1<R>) -> fmt::Result { 541 let inst::rorq_m1 { rm64 } = inst; 542 shift_m1::<R>(f, "rorq", rm64, Size::Quadword) 543 } 544 545 pub fn rolb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolb_m1<R>) -> fmt::Result { 546 let inst::rolb_m1 { rm8 } = inst; 547 shift_m1::<R>(f, "rolb", rm8, Size::Byte) 548 } 549 550 pub fn rolw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolw_m1<R>) -> fmt::Result { 551 let inst::rolw_m1 { rm16 } = inst; 552 shift_m1::<R>(f, "rolw", rm16, Size::Word) 553 } 554 555 pub fn roll_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::roll_m1<R>) -> fmt::Result { 556 let inst::roll_m1 { rm32 } = inst; 557 shift_m1::<R>(f, "roll", rm32, Size::Doubleword) 558 } 559 560 pub fn rolq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolq_m1<R>) -> fmt::Result { 561 let inst::rolq_m1 { rm64 } = inst; 562 shift_m1::<R>(f, "rolq", rm64, Size::Quadword) 563 } 564 565 fn shift_m1<R: Registers>( 566 f: &mut fmt::Formatter<'_>, 567 mnemonic: &str, 568 rm: &GprMem<R::ReadWriteGpr, R::ReadGpr>, 569 size: Size, 570 ) -> fmt::Result { 571 let reg = rm.to_string(size); 572 match rm { 573 GprMem::Gpr(_) => write!(f, "{mnemonic} $1, {reg}"), 574 GprMem::Mem(_) => write!(f, "{mnemonic} {reg}"), 575 } 576 } 577 578 pub fn jmpq_m<R: Registers>(f: &mut fmt::Formatter<'_>, jmp: &inst::jmpq_m<R>) -> fmt::Result { 579 let inst::jmpq_m { rm64 } = jmp; 580 let rm64 = rm64.to_string(Size::Quadword); 581 write!(f, "jmpq *{rm64}") 582 } 583 584 pub fn jmp_d8(f: &mut fmt::Formatter<'_>, jmp: &inst::jmp_d8) -> fmt::Result { 585 let inst::jmp_d8 { imm8 } = jmp; 586 display_displacement(f, "jmp", i64::from(imm8.value()) + 2) 587 } 588 589 pub fn jmp_d32(f: &mut fmt::Formatter<'_>, jmp: &inst::jmp_d32) -> fmt::Result { 590 let inst::jmp_d32 { imm32 } = jmp; 591 display_displacement(f, "jmp", i64::from(imm32.value()) + 5) 592 } 593 594 macro_rules! jcc { 595 ($($mnemonic:tt = $j8:ident / $j32:ident;)*) => ($( 596 pub fn $j8(f: &mut fmt::Formatter<'_>, jmp: &inst::$j8) -> fmt::Result { 597 let inst::$j8 { imm8 } = jmp; 598 display_displacement(f, $mnemonic, i64::from(imm8.value()) + 2) 599 } 600 601 pub fn $j32(f: &mut fmt::Formatter<'_>, jmp: &inst::$j32) -> fmt::Result { 602 let inst::$j32 { imm32 } = jmp; 603 display_displacement(f, $mnemonic, i64::from(imm32.value()) + 6) 604 } 605 )*) 606 } 607 608 jcc! { 609 "ja" = ja_d8 / ja_d32; 610 "jae" = jae_d8 / jae_d32; 611 "jb" = jb_d8 / jb_d32; 612 "jbe" = jbe_d8 / jbe_d32; 613 "je" = je_d8 / je_d32; 614 "jg" = jg_d8 / jg_d32; 615 "jge" = jge_d8 / jge_d32; 616 "jl" = jl_d8 / jl_d32; 617 "jle" = jle_d8 / jle_d32; 618 "jne" = jne_d8 / jne_d32; 619 "jno" = jno_d8 / jno_d32; 620 "jnp" = jnp_d8 / jnp_d32; 621 "jns" = jns_d8 / jns_d32; 622 "jo" = jo_d8 / jo_d32; 623 "jp" = jp_d8 / jp_d32; 624 "js" = js_d8 / js_d32; 625 } 626 627 fn display_displacement( 628 f: &mut fmt::Formatter<'_>, 629 mnemonic: &str, 630 displacement: i64, 631 ) -> fmt::Result { 632 if displacement >= 0 && displacement < 10 { 633 write!(f, "{mnemonic} {displacement}") 634 } else { 635 write!(f, "{mnemonic} {displacement:#x}") 636 } 637 } 638 } 639 640 pub mod visit { 641 use crate::inst::*; 642 use crate::{Amode, Fixed, Gpr, GprMem, RegisterVisitor, Registers, gpr}; 643 644 pub fn mulxl_rvm<R: Registers>(mulx: &mut mulxl_rvm<R>, visitor: &mut impl RegisterVisitor<R>) { 645 visit_mulx( 646 &mut mulx.r32a, 647 &mut mulx.r32b, 648 &mut mulx.rm32, 649 &mut mulx.edx, 650 visitor, 651 ) 652 } 653 654 pub fn mulxq_rvm<R: Registers>(mulx: &mut mulxq_rvm<R>, visitor: &mut impl RegisterVisitor<R>) { 655 visit_mulx( 656 &mut mulx.r64a, 657 &mut mulx.r64b, 658 &mut mulx.rm64, 659 &mut mulx.rdx, 660 visitor, 661 ) 662 } 663 664 /// Both mulxl and mulxq have custom register allocator behavior where if the 665 /// two writable registers are the same then only one is flagged as writable. 666 /// That represents how when they're both the same only one register is written, 667 /// not both. 668 fn visit_mulx<R: Registers>( 669 ra: &mut Gpr<R::WriteGpr>, 670 rb: &mut Gpr<R::WriteGpr>, 671 src1: &mut GprMem<R::ReadGpr, R::ReadGpr>, 672 src2: &mut Fixed<R::ReadGpr, { gpr::enc::RDX }>, 673 visitor: &mut impl RegisterVisitor<R>, 674 ) { 675 if ra == rb { 676 visitor.write_gpr(ra.as_mut()); 677 *rb = *ra; 678 } else { 679 visitor.write_gpr(ra.as_mut()); 680 visitor.write_gpr(rb.as_mut()); 681 } 682 visitor.read_gpr_mem(src1); 683 let enc = src2.expected_enc(); 684 visitor.fixed_read_gpr(&mut src2.0, enc); 685 } 686 687 pub fn lock_xaddb_mr<R: Registers>( 688 lock_xadd: &mut lock_xaddb_mr<R>, 689 visitor: &mut impl RegisterVisitor<R>, 690 ) { 691 let lock_xaddb_mr { r8, m8 } = lock_xadd; 692 lock_xadd_mr(r8, m8, visitor) 693 } 694 695 pub fn lock_xaddw_mr<R: Registers>( 696 lock_xadd: &mut lock_xaddw_mr<R>, 697 visitor: &mut impl RegisterVisitor<R>, 698 ) { 699 let lock_xaddw_mr { r16, m16 } = lock_xadd; 700 lock_xadd_mr(r16, m16, visitor) 701 } 702 703 pub fn lock_xaddl_mr<R: Registers>( 704 lock_xadd: &mut lock_xaddl_mr<R>, 705 visitor: &mut impl RegisterVisitor<R>, 706 ) { 707 let lock_xaddl_mr { r32, m32 } = lock_xadd; 708 lock_xadd_mr(r32, m32, visitor) 709 } 710 711 pub fn lock_xaddq_mr<R: Registers>( 712 lock_xadd: &mut lock_xaddq_mr<R>, 713 visitor: &mut impl RegisterVisitor<R>, 714 ) { 715 let lock_xaddq_mr { r64, m64 } = lock_xadd; 716 lock_xadd_mr(r64, m64, visitor) 717 } 718 719 /// Intel says the memory operand comes first, but regalloc requires the 720 /// register operand comes first, so the custom visit implementation here 721 /// resolves that. 722 fn lock_xadd_mr<R: Registers>( 723 reg: &mut Gpr<R::ReadWriteGpr>, 724 mem: &mut Amode<R::ReadGpr>, 725 visitor: &mut impl RegisterVisitor<R>, 726 ) { 727 visitor.read_write_gpr(reg.as_mut()); 728 visitor.read_amode(mem); 729 } 730 } 731