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