You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-library/vendor/github.com/chenzhuoyu/iasm/x86_64/operands.go

511 lines
18 KiB

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)
}