github.com/cloudwego/iasm@v0.2.0/x86_64/operands.go (about) 1 // 2 // Copyright 2024 CloudWeGo Authors 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 package x86_64 18 19 import ( 20 "errors" 21 "fmt" 22 "math" 23 "reflect" 24 "strconv" 25 "strings" 26 "sync/atomic" 27 ) 28 29 // RelativeOffset represents an RIP-relative offset. 30 type RelativeOffset int32 31 32 // String implements the fmt.Stringer interface. 33 func (self RelativeOffset) String() string { 34 if self == 0 { 35 return "(%rip)" 36 } else { 37 return fmt.Sprintf("%d(%%rip)", self) 38 } 39 } 40 41 // RoundingControl represents a floating-point rounding option. 42 type RoundingControl uint8 43 44 const ( 45 // RN_SAE represents "Round Nearest", which is the default rounding option. 46 RN_SAE RoundingControl = iota 47 48 // RD_SAE represents "Round Down". 49 RD_SAE 50 51 // RU_SAE represents "Round Up". 52 RU_SAE 53 54 // RZ_SAE represents "Round towards Zero". 55 RZ_SAE 56 ) 57 58 var _RC_NAMES = map[RoundingControl]string{ 59 RN_SAE: "rn-sae", 60 RD_SAE: "rd-sae", 61 RU_SAE: "ru-sae", 62 RZ_SAE: "rz-sae", 63 } 64 65 func (self RoundingControl) String() string { 66 if v, ok := _RC_NAMES[self]; ok { 67 return v 68 } else { 69 panic("invalid RoundingControl value") 70 } 71 } 72 73 // ExceptionControl represents the "Suppress All Exceptions" flag. 74 type ExceptionControl uint8 75 76 const ( 77 // SAE represents the flag "Suppress All Exceptions" for floating point operations. 78 SAE ExceptionControl = iota 79 ) 80 81 func (ExceptionControl) String() string { 82 return "sae" 83 } 84 85 // AddressType indicates which kind of value that an Addressable object contains. 86 type AddressType uint 87 88 const ( 89 // None indicates the Addressable does not contain any addressable value. 90 None AddressType = iota 91 92 // Memory indicates the Addressable contains a memory address. 93 Memory 94 95 // Offset indicates the Addressable contains an RIP-relative offset. 96 Offset 97 98 // Reference indicates the Addressable contains a label reference. 99 Reference 100 ) 101 102 // Disposable is a type of object that can be Free'd manually. 103 type Disposable interface { 104 Free() 105 } 106 107 // Label represents a location within the program. 108 type Label struct { 109 refs int64 110 Name string 111 Dest *Instruction 112 } 113 114 func (self *Label) offset(p uintptr, n int) RelativeOffset { 115 if self.Dest == nil { 116 panic("unresolved label: " + self.Name) 117 } else { 118 return RelativeOffset(self.Dest.pc - p - uintptr(n)) 119 } 120 } 121 122 // Free decreases the reference count of a Label, if the 123 // refcount drops to 0, the Label will be recycled. 124 func (self *Label) Free() { 125 if atomic.AddInt64(&self.refs, -1) == 0 { 126 //freeLabel(self) 127 } 128 } 129 130 // String implements the fmt.Stringer interface. 131 func (self *Label) String() string { 132 if self.Dest == nil { 133 return fmt.Sprintf("%s(%%rip)", self.Name) 134 } else { 135 return fmt.Sprintf("%s(%%rip)@%#x", self.Name, self.Dest.pc) 136 } 137 } 138 139 // Retain increases the reference count of a Label. 140 func (self *Label) Retain() *Label { 141 atomic.AddInt64(&self.refs, 1) 142 return self 143 } 144 145 // Evaluate implements the interface expr.Term. 146 func (self *Label) Evaluate() (int64, error) { 147 if self.Dest != nil { 148 return int64(self.Dest.pc), nil 149 } else { 150 return 0, errors.New("unresolved label: " + self.Name) 151 } 152 } 153 154 // Addressable is a union to represent an addressable operand. 155 type Addressable struct { 156 Type AddressType 157 Memory MemoryAddress 158 Offset RelativeOffset 159 Reference *Label 160 } 161 162 // String implements the fmt.Stringer interface. 163 func (self *Addressable) String() string { 164 switch self.Type { 165 case None: 166 return "(not addressable)" 167 case Memory: 168 return self.Memory.String() 169 case Offset: 170 return self.Offset.String() 171 case Reference: 172 return self.Reference.String() 173 default: 174 return "(invalid addressable)" 175 } 176 } 177 178 // MemoryOperand represents a memory operand for an instruction. 179 type MemoryOperand struct { 180 refs int64 181 Size int 182 Addr Addressable 183 Mask RegisterMask 184 Masked bool 185 Broadcast uint8 186 } 187 188 const ( 189 _Sizes = 0b10000000100010111 // bit-mask for valid sizes (0, 1, 2, 4, 8, 16) 190 ) 191 192 func (self *MemoryOperand) isVMX(evex bool) bool { 193 return self.Addr.Type == Memory && self.Addr.Memory.isVMX(evex) 194 } 195 196 func (self *MemoryOperand) isVMY(evex bool) bool { 197 return self.Addr.Type == Memory && self.Addr.Memory.isVMY(evex) 198 } 199 200 func (self *MemoryOperand) isVMZ() bool { 201 return self.Addr.Type == Memory && self.Addr.Memory.isVMZ() 202 } 203 204 func (self *MemoryOperand) isMem() bool { 205 if (_Sizes & (1 << self.Broadcast)) == 0 { 206 return false 207 } else if self.Addr.Type == Memory { 208 return self.Addr.Memory.isMem() 209 } else if self.Addr.Type == Offset { 210 return true 211 } else if self.Addr.Type == Reference { 212 return true 213 } else { 214 return false 215 } 216 } 217 218 func (self *MemoryOperand) isSize(n int) bool { 219 return self.Size == 0 || self.Size == n 220 } 221 222 func (self *MemoryOperand) isBroadcast(n int, b uint8) bool { 223 return self.Size == n && self.Broadcast == b 224 } 225 226 func (self *MemoryOperand) formatMask() string { 227 if !self.Masked { 228 return "" 229 } else { 230 return self.Mask.String() 231 } 232 } 233 234 func (self *MemoryOperand) formatBroadcast() string { 235 if self.Broadcast == 0 { 236 return "" 237 } else { 238 return fmt.Sprintf("{1to%d}", self.Broadcast) 239 } 240 } 241 242 func (self *MemoryOperand) ensureAddrValid() { 243 switch self.Addr.Type { 244 case None: 245 break 246 case Memory: 247 self.Addr.Memory.EnsureValid() 248 case Offset: 249 break 250 case Reference: 251 break 252 default: 253 panic("invalid address type") 254 } 255 } 256 257 func (self *MemoryOperand) ensureSizeValid() { 258 if (_Sizes & (1 << self.Size)) == 0 { 259 panic("invalid memory operand size") 260 } 261 } 262 263 func (self *MemoryOperand) ensureBroadcastValid() { 264 if (_Sizes & (1 << self.Broadcast)) == 0 { 265 panic("invalid memory operand broadcast") 266 } 267 } 268 269 // Free decreases the reference count of a MemoryOperand, if the 270 // refcount drops to 0, the Label will be recycled. 271 func (self *MemoryOperand) Free() { 272 if atomic.AddInt64(&self.refs, -1) == 0 { 273 //freeMemoryOperand(self) 274 } 275 } 276 277 // String implements the fmt.Stringer interface. 278 func (self *MemoryOperand) String() string { 279 return self.Addr.String() + self.formatMask() + self.formatBroadcast() 280 } 281 282 // Retain increases the reference count of a MemoryOperand. 283 func (self *MemoryOperand) Retain() *MemoryOperand { 284 atomic.AddInt64(&self.refs, 1) 285 return self 286 } 287 288 // EnsureValid checks if the memory operand is valid, if not, it panics. 289 func (self *MemoryOperand) EnsureValid() { 290 self.ensureAddrValid() 291 self.ensureSizeValid() 292 self.ensureBroadcastValid() 293 } 294 295 // MemoryAddress represents a memory address. 296 type MemoryAddress struct { 297 Base Register 298 Index Register 299 Scale uint8 300 Displacement int32 301 } 302 303 const ( 304 _Scales = 0b100010111 // bit-mask for valid scales (0, 1, 2, 4, 8) 305 ) 306 307 func (self *MemoryAddress) isVMX(evex bool) bool { 308 return self.isMemBase() && (self.Index == nil || isXMM(self.Index) || (evex && isEVEXXMM(self.Index))) 309 } 310 311 func (self *MemoryAddress) isVMY(evex bool) bool { 312 return self.isMemBase() && (self.Index == nil || isYMM(self.Index) || (evex && isEVEXYMM(self.Index))) 313 } 314 315 func (self *MemoryAddress) isVMZ() bool { 316 return self.isMemBase() && (self.Index == nil || isZMM(self.Index)) 317 } 318 319 func (self *MemoryAddress) isMem() bool { 320 return self.isMemBase() && (self.Index == nil || isReg64(self.Index)) 321 } 322 323 func (self *MemoryAddress) isMemBase() bool { 324 return (self.Base == nil || isReg64(self.Base)) && // `Base` must be 64-bit if present 325 (self.Scale == 0) == (self.Index == nil) && // `Scale` and `Index` depends on each other 326 (_Scales&(1<<self.Scale)) != 0 // `Scale` can only be 0, 1, 2, 4 or 8 327 } 328 329 // String implements the fmt.Stringer interface. 330 func (self *MemoryAddress) String() string { 331 var dp int 332 var sb strings.Builder 333 334 /* the displacement part */ 335 if dp = int(self.Displacement); dp != 0 { 336 sb.WriteString(strconv.Itoa(dp)) 337 } 338 339 /* the base register */ 340 if sb.WriteByte('('); self.Base != nil { 341 sb.WriteByte('%') 342 sb.WriteString(self.Base.String()) 343 } 344 345 /* index is optional */ 346 if self.Index != nil { 347 sb.WriteString(",%") 348 sb.WriteString(self.Index.String()) 349 350 /* scale is also optional */ 351 if self.Scale >= 2 { 352 sb.WriteByte(',') 353 sb.WriteString(strconv.Itoa(int(self.Scale))) 354 } 355 } 356 357 /* close the bracket */ 358 sb.WriteByte(')') 359 return sb.String() 360 } 361 362 // EnsureValid checks if the memory address is valid, if not, it panics. 363 func (self *MemoryAddress) EnsureValid() { 364 if !self.isMemBase() || (self.Index != nil && !isIndexable(self.Index)) { 365 panic("not a valid memory address") 366 } 367 } 368 369 // Ref constructs a memory reference to a label. 370 func Ref(ref *Label) (v *MemoryOperand) { 371 v = CreateMemoryOperand() 372 v.Addr.Type = Reference 373 v.Addr.Reference = ref 374 return 375 } 376 377 // Abs construct a simple memory address that represents absolute addressing. 378 func Abs(disp int32) *MemoryOperand { 379 return Sib(nil, nil, 0, disp) 380 } 381 382 // Ptr constructs a simple memory operand with base and displacement. 383 func Ptr(base Register, disp int32) *MemoryOperand { 384 return Sib(base, nil, 0, disp) 385 } 386 387 // Sib constructs a simple memory operand that represents a complete memory address. 388 func Sib(base Register, index Register, scale uint8, disp int32) (v *MemoryOperand) { 389 v = CreateMemoryOperand() 390 v.Addr.Type = Memory 391 v.Addr.Memory.Base = base 392 v.Addr.Memory.Index = index 393 v.Addr.Memory.Scale = scale 394 v.Addr.Memory.Displacement = disp 395 v.EnsureValid() 396 return 397 } 398 399 /** Operand Matching Helpers **/ 400 401 const _IntMask = (1 << reflect.Int) | 402 (1 << reflect.Int8) | 403 (1 << reflect.Int16) | 404 (1 << reflect.Int32) | 405 (1 << reflect.Int64) | 406 (1 << reflect.Uint) | 407 (1 << reflect.Uint8) | 408 (1 << reflect.Uint16) | 409 (1 << reflect.Uint32) | 410 (1 << reflect.Uint64) | 411 (1 << reflect.Uintptr) 412 413 func isInt(k reflect.Kind) bool { 414 return (_IntMask & (1 << k)) != 0 415 } 416 417 func asInt64(v interface{}) (int64, bool) { 418 if isSpecial(v) { 419 return 0, false 420 } else if x := efaceOf(v); isInt(x.kind()) { 421 return x.toInt64(), true 422 } else { 423 return 0, false 424 } 425 } 426 427 func inRange(v interface{}, low int64, high int64) bool { 428 x, ok := asInt64(v) 429 return ok && x >= low && x <= high 430 } 431 432 func isSpecial(v interface{}) bool { 433 switch v.(type) { 434 case Register8: 435 return true 436 case Register16: 437 return true 438 case Register32: 439 return true 440 case Register64: 441 return true 442 case KRegister: 443 return true 444 case MMRegister: 445 return true 446 case XMMRegister: 447 return true 448 case YMMRegister: 449 return true 450 case ZMMRegister: 451 return true 452 case RelativeOffset: 453 return true 454 case RoundingControl: 455 return true 456 case ExceptionControl: 457 return true 458 default: 459 return false 460 } 461 } 462 463 func isIndexable(v interface{}) bool { 464 return isZMM(v) || isReg64(v) || isEVEXXMM(v) || isEVEXYMM(v) 465 } 466 467 func isImm4(v interface{}) bool { return inRange(v, 0, 15) } 468 func isImm8(v interface{}) bool { return inRange(v, math.MinInt8, math.MaxUint8) } 469 func isImm16(v interface{}) bool { return inRange(v, math.MinInt16, math.MaxUint16) } 470 func isImm32(v interface{}) bool { return inRange(v, math.MinInt32, math.MaxUint32) } 471 func isImm64(v interface{}) bool { _, r := asInt64(v); return r } 472 func isConst1(v interface{}) bool { x, r := asInt64(v); return r && x == 1 } 473 func isConst3(v interface{}) bool { x, r := asInt64(v); return r && x == 3 } 474 func isRel8(v interface{}) bool { 475 x, r := v.(RelativeOffset) 476 return r && x >= math.MinInt8 && x <= math.MaxInt8 477 } 478 func isRel32(v interface{}) bool { _, r := v.(RelativeOffset); return r } 479 func isLabel(v interface{}) bool { _, r := v.(*Label); return r } 480 func isReg8(v interface{}) bool { _, r := v.(Register8); return r } 481 func isReg8REX(v interface{}) bool { 482 x, r := v.(Register8) 483 return r && (x&0x80) == 0 && x >= SPL 484 } 485 func isReg16(v interface{}) bool { _, r := v.(Register16); return r } 486 func isReg32(v interface{}) bool { _, r := v.(Register32); return r } 487 func isReg64(v interface{}) bool { _, r := v.(Register64); return r } 488 func isMM(v interface{}) bool { _, r := v.(MMRegister); return r } 489 func isXMM(v interface{}) bool { x, r := v.(XMMRegister); return r && x <= XMM15 } 490 func isEVEXXMM(v interface{}) bool { _, r := v.(XMMRegister); return r } 491 func isXMMk(v interface{}) bool { 492 x, r := v.(MaskedRegister) 493 return isXMM(v) || (r && isXMM(x.Reg) && !x.Mask.Z) 494 } 495 func isXMMkz(v interface{}) bool { 496 x, r := v.(MaskedRegister) 497 return isXMM(v) || (r && isXMM(x.Reg)) 498 } 499 func isYMM(v interface{}) bool { x, r := v.(YMMRegister); return r && x <= YMM15 } 500 func isEVEXYMM(v interface{}) bool { _, r := v.(YMMRegister); return r } 501 func isYMMk(v interface{}) bool { 502 x, r := v.(MaskedRegister) 503 return isYMM(v) || (r && isYMM(x.Reg) && !x.Mask.Z) 504 } 505 func isYMMkz(v interface{}) bool { 506 x, r := v.(MaskedRegister) 507 return isYMM(v) || (r && isYMM(x.Reg)) 508 } 509 func isZMM(v interface{}) bool { _, r := v.(ZMMRegister); return r } 510 func isZMMk(v interface{}) bool { 511 x, r := v.(MaskedRegister) 512 return isZMM(v) || (r && isZMM(x.Reg) && !x.Mask.Z) 513 } 514 func isZMMkz(v interface{}) bool { 515 x, r := v.(MaskedRegister) 516 return isZMM(v) || (r && isZMM(x.Reg)) 517 } 518 func isK(v interface{}) bool { _, r := v.(KRegister); return r } 519 func isKk(v interface{}) bool { 520 x, r := v.(MaskedRegister) 521 return isK(v) || (r && isK(x.Reg) && !x.Mask.Z) 522 } 523 func isM(v interface{}) bool { 524 x, r := v.(*MemoryOperand) 525 return r && x.isMem() && x.Broadcast == 0 && !x.Masked 526 } 527 func isMk(v interface{}) bool { 528 x, r := v.(*MemoryOperand) 529 return r && x.isMem() && x.Broadcast == 0 && !(x.Masked && x.Mask.Z) 530 } 531 func isMkz(v interface{}) bool { 532 x, r := v.(*MemoryOperand) 533 return r && x.isMem() && x.Broadcast == 0 534 } 535 func isM8(v interface{}) bool { 536 x, r := v.(*MemoryOperand) 537 return r && isM(v) && x.isSize(1) 538 } 539 func isM16(v interface{}) bool { 540 x, r := v.(*MemoryOperand) 541 return r && isM(v) && x.isSize(2) 542 } 543 func isM16kz(v interface{}) bool { 544 x, r := v.(*MemoryOperand) 545 return r && isMkz(v) && x.isSize(2) 546 } 547 func isM32(v interface{}) bool { 548 x, r := v.(*MemoryOperand) 549 return r && isM(v) && x.isSize(4) 550 } 551 func isM32k(v interface{}) bool { 552 x, r := v.(*MemoryOperand) 553 return r && isMk(v) && x.isSize(4) 554 } 555 func isM32kz(v interface{}) bool { 556 x, r := v.(*MemoryOperand) 557 return r && isMkz(v) && x.isSize(4) 558 } 559 func isM64(v interface{}) bool { 560 x, r := v.(*MemoryOperand) 561 return r && isM(v) && x.isSize(8) 562 } 563 func isM64k(v interface{}) bool { 564 x, r := v.(*MemoryOperand) 565 return r && isMk(v) && x.isSize(8) 566 } 567 func isM64kz(v interface{}) bool { 568 x, r := v.(*MemoryOperand) 569 return r && isMkz(v) && x.isSize(8) 570 } 571 func isM128(v interface{}) bool { 572 x, r := v.(*MemoryOperand) 573 return r && isM(v) && x.isSize(16) 574 } 575 func isM128kz(v interface{}) bool { 576 x, r := v.(*MemoryOperand) 577 return r && isMkz(v) && x.isSize(16) 578 } 579 func isM256(v interface{}) bool { 580 x, r := v.(*MemoryOperand) 581 return r && isM(v) && x.isSize(32) 582 } 583 func isM256kz(v interface{}) bool { 584 x, r := v.(*MemoryOperand) 585 return r && isMkz(v) && x.isSize(32) 586 } 587 func isM512(v interface{}) bool { 588 x, r := v.(*MemoryOperand) 589 return r && isM(v) && x.isSize(64) 590 } 591 func isM512kz(v interface{}) bool { 592 x, r := v.(*MemoryOperand) 593 return r && isMkz(v) && x.isSize(64) 594 } 595 func isM64M32bcst(v interface{}) bool { 596 x, r := v.(*MemoryOperand) 597 return isM64(v) || (r && x.isBroadcast(4, 2)) 598 } 599 func isM128M32bcst(v interface{}) bool { 600 x, r := v.(*MemoryOperand) 601 return isM128(v) || (r && x.isBroadcast(4, 4)) 602 } 603 func isM256M32bcst(v interface{}) bool { 604 x, r := v.(*MemoryOperand) 605 return isM256(v) || (r && x.isBroadcast(4, 8)) 606 } 607 func isM512M32bcst(v interface{}) bool { 608 x, r := v.(*MemoryOperand) 609 return isM512(v) || (r && x.isBroadcast(4, 16)) 610 } 611 func isM128M64bcst(v interface{}) bool { 612 x, r := v.(*MemoryOperand) 613 return isM128(v) || (r && x.isBroadcast(8, 2)) 614 } 615 func isM256M64bcst(v interface{}) bool { 616 x, r := v.(*MemoryOperand) 617 return isM256(v) || (r && x.isBroadcast(8, 4)) 618 } 619 func isM512M64bcst(v interface{}) bool { 620 x, r := v.(*MemoryOperand) 621 return isM512(v) || (r && x.isBroadcast(8, 8)) 622 } 623 func isVMX(v interface{}) bool { 624 x, r := v.(*MemoryOperand) 625 return r && x.isVMX(false) && !x.Masked 626 } 627 func isEVEXVMX(v interface{}) bool { 628 x, r := v.(*MemoryOperand) 629 return r && x.isVMX(true) && !x.Masked 630 } 631 func isVMXk(v interface{}) bool { x, r := v.(*MemoryOperand); return r && x.isVMX(true) } 632 func isVMY(v interface{}) bool { 633 x, r := v.(*MemoryOperand) 634 return r && x.isVMY(false) && !x.Masked 635 } 636 func isEVEXVMY(v interface{}) bool { 637 x, r := v.(*MemoryOperand) 638 return r && x.isVMY(true) && !x.Masked 639 } 640 func isVMYk(v interface{}) bool { x, r := v.(*MemoryOperand); return r && x.isVMY(true) } 641 func isVMZ(v interface{}) bool { 642 x, r := v.(*MemoryOperand) 643 return r && x.isVMZ() && !x.Masked 644 } 645 func isVMZk(v interface{}) bool { x, r := v.(*MemoryOperand); return r && x.isVMZ() } 646 func isSAE(v interface{}) bool { _, r := v.(ExceptionControl); return r } 647 func isER(v interface{}) bool { _, r := v.(RoundingControl); return r } 648 649 func isImmExt(v interface{}, ext int, min int64, max int64) bool { 650 if x, ok := asInt64(v); !ok { 651 return false 652 } else if m := int64(1) << (8 * ext); x < m && x >= m+min { 653 return true 654 } else { 655 return x <= max && x >= min 656 } 657 } 658 659 func isImm8Ext(v interface{}, ext int) bool { 660 return isImmExt(v, ext, math.MinInt8, math.MaxInt8) 661 } 662 663 func isImm32Ext(v interface{}, ext int) bool { 664 return isImmExt(v, ext, math.MinInt32, math.MaxInt32) 665 }