123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- package x86_64
- import (
- `errors`
- `fmt`
- `math`
- `reflect`
- `strconv`
- `strings`
- `sync/atomic`
- )
- // RelativeOffset represents an RIP-relative offset.
- type RelativeOffset int32
- // String implements the fmt.Stringer interface.
- func (self RelativeOffset) String() string {
- if self == 0 {
- return "(%rip)"
- } else {
- return fmt.Sprintf("%d(%%rip)", self)
- }
- }
- // RoundingControl represents a floating-point rounding option.
- type RoundingControl uint8
- const (
- // RN_SAE represents "Round Nearest", which is the default rounding option.
- RN_SAE RoundingControl = iota
- // RD_SAE represents "Round Down".
- RD_SAE
- // RU_SAE represents "Round Up".
- RU_SAE
- // RZ_SAE represents "Round towards Zero".
- RZ_SAE
- )
- var _RC_NAMES = map[RoundingControl]string {
- RN_SAE: "rn-sae",
- RD_SAE: "rd-sae",
- RU_SAE: "ru-sae",
- RZ_SAE: "rz-sae",
- }
- func (self RoundingControl) String() string {
- if v, ok := _RC_NAMES[self]; ok {
- return v
- } else {
- panic("invalid RoundingControl value")
- }
- }
- // ExceptionControl represents the "Suppress All Exceptions" flag.
- type ExceptionControl uint8
- const (
- // SAE represents the flag "Suppress All Exceptions" for floating point operations.
- SAE ExceptionControl = iota
- )
- func (ExceptionControl) String() string {
- return "sae"
- }
- // AddressType indicates which kind of value that an Addressable object contains.
- type AddressType uint
- const (
- // None indicates the Addressable does not contain any addressable value.
- None AddressType = iota
- // Memory indicates the Addressable contains a memory address.
- Memory
- // Offset indicates the Addressable contains an RIP-relative offset.
- Offset
- // Reference indicates the Addressable contains a label reference.
- Reference
- )
- // Disposable is a type of object that can be Free'd manually.
- type Disposable interface {
- Free()
- }
- // Label represents a location within the program.
- type Label struct {
- refs int64
- Name string
- Dest *Instruction
- }
- func (self *Label) offset(p uintptr, n int) RelativeOffset {
- if self.Dest == nil {
- panic("unresolved label: " + self.Name)
- } else {
- return RelativeOffset(self.Dest.pc - p - uintptr(n))
- }
- }
- // Free decreases the reference count of a Label, if the
- // refcount drops to 0, the Label will be recycled.
- func (self *Label) Free() {
- if atomic.AddInt64(&self.refs, -1) == 0 {
- freeLabel(self)
- }
- }
- // String implements the fmt.Stringer interface.
- func (self *Label) String() string {
- if self.Dest == nil {
- return fmt.Sprintf("%s(%%rip)", self.Name)
- } else {
- return fmt.Sprintf("%s(%%rip)@%#x", self.Name, self.Dest.pc)
- }
- }
- // Retain increases the reference count of a Label.
- func (self *Label) Retain() *Label {
- atomic.AddInt64(&self.refs, 1)
- return self
- }
- // Evaluate implements the interface expr.Term.
- func (self *Label) Evaluate() (int64, error) {
- if self.Dest != nil {
- return int64(self.Dest.pc), nil
- } else {
- return 0, errors.New("unresolved label: " + self.Name)
- }
- }
- // Addressable is a union to represent an addressable operand.
- type Addressable struct {
- Type AddressType
- Memory MemoryAddress
- Offset RelativeOffset
- Reference *Label
- }
- // String implements the fmt.Stringer interface.
- func (self *Addressable) String() string {
- switch self.Type {
- case None : return "(not addressable)"
- case Memory : return self.Memory.String()
- case Offset : return self.Offset.String()
- case Reference : return self.Reference.String()
- default : return "(invalid addressable)"
- }
- }
- // MemoryOperand represents a memory operand for an instruction.
- type MemoryOperand struct {
- refs int64
- Size int
- Addr Addressable
- Mask RegisterMask
- Masked bool
- Broadcast uint8
- }
- const (
- _Sizes = 0b10000000100010111 // bit-mask for valid sizes (0, 1, 2, 4, 8, 16)
- )
- func (self *MemoryOperand) isVMX(evex bool) bool {
- return self.Addr.Type == Memory && self.Addr.Memory.isVMX(evex)
- }
- func (self *MemoryOperand) isVMY(evex bool) bool {
- return self.Addr.Type == Memory && self.Addr.Memory.isVMY(evex)
- }
- func (self *MemoryOperand) isVMZ() bool {
- return self.Addr.Type == Memory && self.Addr.Memory.isVMZ()
- }
- func (self *MemoryOperand) isMem() bool {
- if (_Sizes & (1 << self.Broadcast)) == 0 {
- return false
- } else if self.Addr.Type == Memory {
- return self.Addr.Memory.isMem()
- } else if self.Addr.Type == Offset {
- return true
- } else if self.Addr.Type == Reference {
- return true
- } else {
- return false
- }
- }
- func (self *MemoryOperand) isSize(n int) bool {
- return self.Size == 0 || self.Size == n
- }
- func (self *MemoryOperand) isBroadcast(n int, b uint8) bool {
- return self.Size == n && self.Broadcast == b
- }
- func (self *MemoryOperand) formatMask() string {
- if !self.Masked {
- return ""
- } else {
- return self.Mask.String()
- }
- }
- func (self *MemoryOperand) formatBroadcast() string {
- if self.Broadcast == 0 {
- return ""
- } else {
- return fmt.Sprintf("{1to%d}", self.Broadcast)
- }
- }
- func (self *MemoryOperand) ensureAddrValid() {
- switch self.Addr.Type {
- case None : break
- case Memory : self.Addr.Memory.EnsureValid()
- case Offset : break
- case Reference : break
- default : panic("invalid address type")
- }
- }
- func (self *MemoryOperand) ensureSizeValid() {
- if (_Sizes & (1 << self.Size)) == 0 {
- panic("invalid memory operand size")
- }
- }
- func (self *MemoryOperand) ensureBroadcastValid() {
- if (_Sizes & (1 << self.Broadcast)) == 0 {
- panic("invalid memory operand broadcast")
- }
- }
- // Free decreases the reference count of a MemoryOperand, if the
- // refcount drops to 0, the Label will be recycled.
- func (self *MemoryOperand) Free() {
- if atomic.AddInt64(&self.refs, -1) == 0 {
- freeMemoryOperand(self)
- }
- }
- // String implements the fmt.Stringer interface.
- func (self *MemoryOperand) String() string {
- return self.Addr.String() + self.formatMask() + self.formatBroadcast()
- }
- // Retain increases the reference count of a MemoryOperand.
- func (self *MemoryOperand) Retain() *MemoryOperand {
- atomic.AddInt64(&self.refs, 1)
- return self
- }
- // EnsureValid checks if the memory operand is valid, if not, it panics.
- func (self *MemoryOperand) EnsureValid() {
- self.ensureAddrValid()
- self.ensureSizeValid()
- self.ensureBroadcastValid()
- }
- // MemoryAddress represents a memory address.
- type MemoryAddress struct {
- Base Register
- Index Register
- Scale uint8
- Displacement int32
- }
- const (
- _Scales = 0b100010111 // bit-mask for valid scales (0, 1, 2, 4, 8)
- )
- func (self *MemoryAddress) isVMX(evex bool) bool {
- return self.isMemBase() && (self.Index == nil || isXMM(self.Index) || (evex && isEVEXXMM(self.Index)))
- }
- func (self *MemoryAddress) isVMY(evex bool) bool {
- return self.isMemBase() && (self.Index == nil || isYMM(self.Index) || (evex && isEVEXYMM(self.Index)))
- }
- func (self *MemoryAddress) isVMZ() bool {
- return self.isMemBase() && (self.Index == nil || isZMM(self.Index))
- }
- func (self *MemoryAddress) isMem() bool {
- return self.isMemBase() && (self.Index == nil || isReg64(self.Index))
- }
- func (self *MemoryAddress) isMemBase() bool {
- return (self.Base == nil || isReg64(self.Base)) && // `Base` must be 64-bit if present
- (self.Scale == 0) == (self.Index == nil) && // `Scale` and `Index` depends on each other
- (_Scales & (1 << self.Scale)) != 0 // `Scale` can only be 0, 1, 2, 4 or 8
- }
- // String implements the fmt.Stringer interface.
- func (self *MemoryAddress) String() string {
- var dp int
- var sb strings.Builder
- /* the displacement part */
- if dp = int(self.Displacement); dp != 0 {
- sb.WriteString(strconv.Itoa(dp))
- }
- /* the base register */
- if sb.WriteByte('('); self.Base != nil {
- sb.WriteByte('%')
- sb.WriteString(self.Base.String())
- }
- /* index is optional */
- if self.Index != nil {
- sb.WriteString(",%")
- sb.WriteString(self.Index.String())
- /* scale is also optional */
- if self.Scale >= 2 {
- sb.WriteByte(',')
- sb.WriteString(strconv.Itoa(int(self.Scale)))
- }
- }
- /* close the bracket */
- sb.WriteByte(')')
- return sb.String()
- }
- // EnsureValid checks if the memory address is valid, if not, it panics.
- func (self *MemoryAddress) EnsureValid() {
- if !self.isMemBase() || (self.Index != nil && !isIndexable(self.Index)) {
- panic("not a valid memory address")
- }
- }
- // Ref constructs a memory reference to a label.
- func Ref(ref *Label) (v *MemoryOperand) {
- v = CreateMemoryOperand()
- v.Addr.Type = Reference
- v.Addr.Reference = ref
- return
- }
- // Abs construct a simple memory address that represents absolute addressing.
- func Abs(disp int32) *MemoryOperand {
- return Sib(nil, nil, 0, disp)
- }
- // Ptr constructs a simple memory operand with base and displacement.
- func Ptr(base Register, disp int32) *MemoryOperand {
- return Sib(base, nil, 0, disp)
- }
- // Sib constructs a simple memory operand that represents a complete memory address.
- func Sib(base Register, index Register, scale uint8, disp int32) (v *MemoryOperand) {
- v = CreateMemoryOperand()
- v.Addr.Type = Memory
- v.Addr.Memory.Base = base
- v.Addr.Memory.Index = index
- v.Addr.Memory.Scale = scale
- v.Addr.Memory.Displacement = disp
- v.EnsureValid()
- return
- }
- /** Operand Matching Helpers **/
- const _IntMask =
- (1 << reflect.Int ) |
- (1 << reflect.Int8 ) |
- (1 << reflect.Int16 ) |
- (1 << reflect.Int32 ) |
- (1 << reflect.Int64 ) |
- (1 << reflect.Uint ) |
- (1 << reflect.Uint8 ) |
- (1 << reflect.Uint16 ) |
- (1 << reflect.Uint32 ) |
- (1 << reflect.Uint64 ) |
- (1 << reflect.Uintptr)
- func isInt(k reflect.Kind) bool {
- return (_IntMask & (1 << k)) != 0
- }
- func asInt64(v interface{}) (int64, bool) {
- if isSpecial(v) {
- return 0, false
- } else if x := efaceOf(v); isInt(x.kind()) {
- return x.toInt64(), true
- } else {
- return 0, false
- }
- }
- func inRange(v interface{}, low int64, high int64) bool {
- x, ok := asInt64(v)
- return ok && x >= low && x <= high
- }
- func isSpecial(v interface{}) bool {
- switch v.(type) {
- case Register8 : return true
- case Register16 : return true
- case Register32 : return true
- case Register64 : return true
- case KRegister : return true
- case MMRegister : return true
- case XMMRegister : return true
- case YMMRegister : return true
- case ZMMRegister : return true
- case RelativeOffset : return true
- case RoundingControl : return true
- case ExceptionControl : return true
- default : return false
- }
- }
- func isIndexable(v interface{}) bool {
- return isZMM(v) || isReg64(v) || isEVEXXMM(v) || isEVEXYMM(v)
- }
- func isImm4 (v interface{}) bool { return inRange(v, 0, 15) }
- func isImm8 (v interface{}) bool { return inRange(v, math.MinInt8, math.MaxUint8) }
- func isImm16 (v interface{}) bool { return inRange(v, math.MinInt16, math.MaxUint16) }
- func isImm32 (v interface{}) bool { return inRange(v, math.MinInt32, math.MaxUint32) }
- func isImm64 (v interface{}) bool { _, r := asInt64(v) ; return r }
- func isConst1 (v interface{}) bool { x, r := asInt64(v) ; return r && x == 1 }
- func isConst3 (v interface{}) bool { x, r := asInt64(v) ; return r && x == 3 }
- func isRel8 (v interface{}) bool { x, r := v.(RelativeOffset) ; return r && x >= math.MinInt8 && x <= math.MaxInt8 }
- func isRel32 (v interface{}) bool { _, r := v.(RelativeOffset) ; return r }
- func isLabel (v interface{}) bool { _, r := v.(*Label) ; return r }
- func isReg8 (v interface{}) bool { _, r := v.(Register8) ; return r }
- func isReg8REX (v interface{}) bool { x, r := v.(Register8) ; return r && (x & 0x80) == 0 && x >= SPL }
- func isReg16 (v interface{}) bool { _, r := v.(Register16) ; return r }
- func isReg32 (v interface{}) bool { _, r := v.(Register32) ; return r }
- func isReg64 (v interface{}) bool { _, r := v.(Register64) ; return r }
- func isMM (v interface{}) bool { _, r := v.(MMRegister) ; return r }
- func isXMM (v interface{}) bool { x, r := v.(XMMRegister) ; return r && x <= XMM15 }
- func isEVEXXMM (v interface{}) bool { _, r := v.(XMMRegister) ; return r }
- func isXMMk (v interface{}) bool { x, r := v.(MaskedRegister) ; return isXMM(v) || (r && isXMM(x.Reg) && !x.Mask.Z) }
- func isXMMkz (v interface{}) bool { x, r := v.(MaskedRegister) ; return isXMM(v) || (r && isXMM(x.Reg)) }
- func isYMM (v interface{}) bool { x, r := v.(YMMRegister) ; return r && x <= YMM15 }
- func isEVEXYMM (v interface{}) bool { _, r := v.(YMMRegister) ; return r }
- func isYMMk (v interface{}) bool { x, r := v.(MaskedRegister) ; return isYMM(v) || (r && isYMM(x.Reg) && !x.Mask.Z) }
- func isYMMkz (v interface{}) bool { x, r := v.(MaskedRegister) ; return isYMM(v) || (r && isYMM(x.Reg)) }
- func isZMM (v interface{}) bool { _, r := v.(ZMMRegister) ; return r }
- func isZMMk (v interface{}) bool { x, r := v.(MaskedRegister) ; return isZMM(v) || (r && isZMM(x.Reg) && !x.Mask.Z) }
- func isZMMkz (v interface{}) bool { x, r := v.(MaskedRegister) ; return isZMM(v) || (r && isZMM(x.Reg)) }
- func isK (v interface{}) bool { _, r := v.(KRegister) ; return r }
- func isKk (v interface{}) bool { x, r := v.(MaskedRegister) ; return isK(v) || (r && isK(x.Reg) && !x.Mask.Z) }
- func isM (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isMem() && x.Broadcast == 0 && !x.Masked }
- func isMk (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isMem() && x.Broadcast == 0 && !(x.Masked && x.Mask.Z) }
- func isMkz (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isMem() && x.Broadcast == 0 }
- func isM8 (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isM(v) && x.isSize(1) }
- func isM16 (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isM(v) && x.isSize(2) }
- func isM16kz (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMkz(v) && x.isSize(2) }
- func isM32 (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isM(v) && x.isSize(4) }
- func isM32k (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMk(v) && x.isSize(4) }
- func isM32kz (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMkz(v) && x.isSize(4) }
- func isM64 (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isM(v) && x.isSize(8) }
- func isM64k (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMk(v) && x.isSize(8) }
- func isM64kz (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMkz(v) && x.isSize(8) }
- func isM128 (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isM(v) && x.isSize(16) }
- func isM128kz (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMkz(v) && x.isSize(16) }
- func isM256 (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isM(v) && x.isSize(32) }
- func isM256kz (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMkz(v) && x.isSize(32) }
- func isM512 (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isM(v) && x.isSize(64) }
- func isM512kz (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && isMkz(v) && x.isSize(64) }
- func isM64M32bcst (v interface{}) bool { x, r := v.(*MemoryOperand) ; return isM64(v) || (r && x.isBroadcast(4, 2)) }
- func isM128M32bcst (v interface{}) bool { x, r := v.(*MemoryOperand) ; return isM128(v) || (r && x.isBroadcast(4, 4)) }
- func isM256M32bcst (v interface{}) bool { x, r := v.(*MemoryOperand) ; return isM256(v) || (r && x.isBroadcast(4, 8)) }
- func isM512M32bcst (v interface{}) bool { x, r := v.(*MemoryOperand) ; return isM512(v) || (r && x.isBroadcast(4, 16)) }
- func isM128M64bcst (v interface{}) bool { x, r := v.(*MemoryOperand) ; return isM128(v) || (r && x.isBroadcast(8, 2)) }
- func isM256M64bcst (v interface{}) bool { x, r := v.(*MemoryOperand) ; return isM256(v) || (r && x.isBroadcast(8, 4)) }
- func isM512M64bcst (v interface{}) bool { x, r := v.(*MemoryOperand) ; return isM512(v) || (r && x.isBroadcast(8, 8)) }
- func isVMX (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMX(false) && !x.Masked }
- func isEVEXVMX (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMX(true) && !x.Masked }
- func isVMXk (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMX(true) }
- func isVMY (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMY(false) && !x.Masked }
- func isEVEXVMY (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMY(true) && !x.Masked }
- func isVMYk (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMY(true) }
- func isVMZ (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMZ() && !x.Masked }
- func isVMZk (v interface{}) bool { x, r := v.(*MemoryOperand) ; return r && x.isVMZ() }
- func isSAE (v interface{}) bool { _, r := v.(ExceptionControl) ; return r }
- func isER (v interface{}) bool { _, r := v.(RoundingControl) ; return r }
- func isImmExt(v interface{}, ext int, min int64, max int64) bool {
- if x, ok := asInt64(v); !ok {
- return false
- } else if m := int64(1) << (8 * ext); x < m && x >= m + min {
- return true
- } else {
- return x <= max && x >= min
- }
- }
- func isImm8Ext(v interface{}, ext int) bool {
- return isImmExt(v, ext, math.MinInt8, math.MaxInt8)
- }
- func isImm32Ext(v interface{}, ext int) bool {
- return isImmExt(v, ext, math.MinInt32, math.MaxInt32)
- }
|