[chore]: Bump github.com/gin-contrib/cors from 1.5.0 to 1.7.0 (#2745)

This commit is contained in:
dependabot[bot] 2024-03-11 10:12:06 +00:00 committed by GitHub
commit e24efcac8b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
158 changed files with 11727 additions and 4290 deletions

View file

@ -1,13 +1,13 @@
package x86_64
import (
`errors`
`fmt`
`math`
`reflect`
`strconv`
`strings`
`sync/atomic`
"errors"
"fmt"
"math"
"reflect"
"strconv"
"strings"
"sync/atomic"
)
// RelativeOffset represents an RIP-relative offset.
@ -15,496 +15,635 @@ 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)
}
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
// RN_SAE represents "Round Nearest", which is the default rounding option.
RN_SAE RoundingControl = iota
// RD_SAE represents "Round Down".
RD_SAE
// RD_SAE represents "Round Down".
RD_SAE
// RU_SAE represents "Round Up".
RU_SAE
// RU_SAE represents "Round Up".
RU_SAE
// RZ_SAE represents "Round towards Zero".
RZ_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",
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")
}
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
// SAE represents the flag "Suppress All Exceptions" for floating point operations.
SAE ExceptionControl = iota
)
func (ExceptionControl) String() string {
return "sae"
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
// None indicates the Addressable does not contain any addressable value.
None AddressType = iota
// Memory indicates the Addressable contains a memory address.
Memory
// Memory indicates the Addressable contains a memory address.
Memory
// Offset indicates the Addressable contains an RIP-relative offset.
Offset
// Offset indicates the Addressable contains an RIP-relative offset.
Offset
// Reference indicates the Addressable contains a label reference.
Reference
// 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()
Free()
}
// Label represents a location within the program.
type Label struct {
refs int64
Name string
Dest *Instruction
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))
}
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)
}
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)
}
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
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)
}
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
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)"
}
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
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)
_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)
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)
return self.Addr.Type == Memory && self.Addr.Memory.isVMY(evex)
}
func (self *MemoryOperand) isVMZ() bool {
return self.Addr.Type == Memory && self.Addr.Memory.isVMZ()
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
}
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
return self.Size == 0 || self.Size == n
}
func (self *MemoryOperand) isBroadcast(n int, b uint8) bool {
return self.Size == n && self.Broadcast == b
return self.Size == n && self.Broadcast == b
}
func (self *MemoryOperand) formatMask() string {
if !self.Masked {
return ""
} else {
return self.Mask.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)
}
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")
}
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")
}
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")
}
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)
}
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()
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
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()
self.ensureAddrValid()
self.ensureSizeValid()
self.ensureBroadcastValid()
}
// MemoryAddress represents a memory address.
type MemoryAddress struct {
Base Register
Index Register
Scale uint8
Displacement int32
Base Register
Index Register
Scale uint8
Displacement int32
}
const (
_Scales = 0b100010111 // bit-mask for valid scales (0, 1, 2, 4, 8)
_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)))
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)))
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))
return self.isMemBase() && (self.Index == nil || isZMM(self.Index))
}
func (self *MemoryAddress) isMem() bool {
return self.isMemBase() && (self.Index == nil || isReg64(self.Index))
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
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
var dp int
var sb strings.Builder
/* the displacement part */
if dp = int(self.Displacement); dp != 0 {
sb.WriteString(strconv.Itoa(dp))
}
/* 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())
}
/* 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())
/* 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)))
}
}
/* 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()
/* 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")
}
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
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)
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)
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
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)
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
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
}
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
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
}
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)
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 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
}
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)
return isImmExt(v, ext, math.MinInt8, math.MaxInt8)
}
func isImm32Ext(v interface{}, ext int) bool {
return isImmExt(v, ext, math.MinInt32, math.MaxInt32)
return isImmExt(v, ext, math.MinInt32, math.MaxInt32)
}

View file

@ -1,117 +1,38 @@
package x86_64
import (
`sync`
)
var (
labelPool sync.Pool
programPool sync.Pool
instructionPool sync.Pool
memoryOperandPool sync.Pool
)
func freeLabel(v *Label) {
labelPool.Put(v)
}
func clearLabel(p *Label) *Label {
*p = Label{}
return p
}
// CreateLabel creates a new Label, it may allocate a new one or grab one from a pool.
func CreateLabel(name string) *Label {
var p *Label
var v interface{}
p := new(Label)
/* attempt to grab from the pool */
if v = labelPool.Get(); v == nil {
p = new(Label)
} else {
p = clearLabel(v.(*Label))
}
/* initialize the label */
p.refs = 1
p.Name = name
return p
/* initialize the label */
p.refs = 1
p.Name = name
return p
}
func newProgram(arch *Arch) *Program {
var p *Program
var v interface{}
p := new(Program)
/* attempt to grab from the pool */
if v = programPool.Get(); v == nil {
p = new(Program)
} else {
p = clearProgram(v.(*Program))
}
/* initialize the program */
p.arch = arch
return p
}
func freeProgram(p *Program) {
programPool.Put(p)
}
func clearProgram(p *Program) *Program {
*p = Program{}
return p
/* initialize the program */
p.arch = arch
return p
}
func newInstruction(name string, argc int, argv Operands) *Instruction {
var v interface{}
var p *Instruction
p := new(Instruction)
/* attempt to grab from the pool */
if v = instructionPool.Get(); v == nil {
p = new(Instruction)
} else {
p = clearInstruction(v.(*Instruction))
}
/* initialize the instruction */
p.name = name
p.argc = argc
p.argv = argv
return p
}
func freeInstruction(v *Instruction) {
instructionPool.Put(v)
}
func clearInstruction(p *Instruction) *Instruction {
*p = Instruction { prefix: p.prefix[:0] }
return p
}
func freeMemoryOperand(m *MemoryOperand) {
memoryOperandPool.Put(m)
}
func clearMemoryOperand(m *MemoryOperand) *MemoryOperand {
*m = MemoryOperand{}
return m
/* initialize the instruction */
p.name = name
p.argc = argc
p.argv = argv
return p
}
// CreateMemoryOperand creates a new MemoryOperand, it may allocate a new one or grab one from a pool.
func CreateMemoryOperand() *MemoryOperand {
var v interface{}
var p *MemoryOperand
p := new(MemoryOperand)
/* attempt to grab from the pool */
if v = memoryOperandPool.Get(); v == nil {
p = new(MemoryOperand)
} else {
p = clearMemoryOperand(v.(*MemoryOperand))
}
/* initialize the memory operand */
p.refs = 1
return p
/* initialize the memory operand */
p.refs = 1
return p
}

View file

@ -1,127 +1,149 @@
package x86_64
import (
`fmt`
`math`
`math/bits`
"fmt"
"math"
"math/bits"
`github.com/chenzhuoyu/iasm/expr`
"github.com/chenzhuoyu/iasm/expr"
)
type (
_PseudoType int
_InstructionEncoder func(*Program, ...interface{}) *Instruction
_PseudoType int
_InstructionEncoder func(*Program, ...interface{}) *Instruction
)
const (
_PseudoNop _PseudoType = iota + 1
_PseudoByte
_PseudoWord
_PseudoLong
_PseudoQuad
_PseudoData
_PseudoAlign
_PseudoNop _PseudoType = iota + 1
_PseudoByte
_PseudoWord
_PseudoLong
_PseudoQuad
_PseudoData
_PseudoAlign
)
func (self _PseudoType) String() string {
switch self {
case _PseudoNop : return ".nop"
case _PseudoByte : return ".byte"
case _PseudoWord : return ".word"
case _PseudoLong : return ".long"
case _PseudoQuad : return ".quad"
case _PseudoData : return ".data"
case _PseudoAlign : return ".align"
default : panic("unreachable")
}
switch self {
case _PseudoNop:
return ".nop"
case _PseudoByte:
return ".byte"
case _PseudoWord:
return ".word"
case _PseudoLong:
return ".long"
case _PseudoQuad:
return ".quad"
case _PseudoData:
return ".data"
case _PseudoAlign:
return ".align"
default:
panic("unreachable")
}
}
type _Pseudo struct {
kind _PseudoType
data []byte
uint uint64
expr *expr.Expr
kind _PseudoType
data []byte
uint uint64
expr *expr.Expr
}
func (self *_Pseudo) free() {
if self.expr != nil {
self.expr.Free()
}
if self.expr != nil {
self.expr.Free()
}
}
func (self *_Pseudo) encode(m *[]byte, pc uintptr) int {
switch self.kind {
case _PseudoNop : return 0
case _PseudoByte : self.encodeByte(m) ; return 1
case _PseudoWord : self.encodeWord(m) ; return 2
case _PseudoLong : self.encodeLong(m) ; return 4
case _PseudoQuad : self.encodeQuad(m) ; return 8
case _PseudoData : self.encodeData(m) ; return len(self.data)
case _PseudoAlign : self.encodeAlign(m, pc) ; return self.alignSize(pc)
default : panic("invalid pseudo instruction")
}
switch self.kind {
case _PseudoNop:
return 0
case _PseudoByte:
self.encodeByte(m)
return 1
case _PseudoWord:
self.encodeWord(m)
return 2
case _PseudoLong:
self.encodeLong(m)
return 4
case _PseudoQuad:
self.encodeQuad(m)
return 8
case _PseudoData:
self.encodeData(m)
return len(self.data)
case _PseudoAlign:
self.encodeAlign(m, pc)
return self.alignSize(pc)
default:
panic("invalid pseudo instruction")
}
}
func (self *_Pseudo) evalExpr(low int64, high int64) int64 {
if v, err := self.expr.Evaluate(); err != nil {
panic(err)
} else if v < low || v > high {
panic(fmt.Sprintf("expression out of range [%d, %d]: %d", low, high, v))
} else {
return v
}
if v, err := self.expr.Evaluate(); err != nil {
panic(err)
} else if v < low || v > high {
panic(fmt.Sprintf("expression out of range [%d, %d]: %d", low, high, v))
} else {
return v
}
}
func (self *_Pseudo) alignSize(pc uintptr) int {
if !ispow2(self.uint) {
panic(fmt.Sprintf("aligment should be a power of 2, not %d", self.uint))
} else {
return align(int(pc), bits.TrailingZeros64(self.uint)) - int(pc)
}
if !ispow2(self.uint) {
panic(fmt.Sprintf("aligment should be a power of 2, not %d", self.uint))
} else {
return align(int(pc), bits.TrailingZeros64(self.uint)) - int(pc)
}
}
func (self *_Pseudo) encodeData(m *[]byte) {
if m != nil {
*m = append(*m, self.data...)
}
if m != nil {
*m = append(*m, self.data...)
}
}
func (self *_Pseudo) encodeByte(m *[]byte) {
if m != nil {
append8(m, byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
}
if m != nil {
append8(m, byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
}
}
func (self *_Pseudo) encodeWord(m *[]byte) {
if m != nil {
append16(m, uint16(self.evalExpr(math.MinInt16, math.MaxUint16)))
}
if m != nil {
append16(m, uint16(self.evalExpr(math.MinInt16, math.MaxUint16)))
}
}
func (self *_Pseudo) encodeLong(m *[]byte) {
if m != nil {
append32(m, uint32(self.evalExpr(math.MinInt32, math.MaxUint32)))
}
if m != nil {
append32(m, uint32(self.evalExpr(math.MinInt32, math.MaxUint32)))
}
}
func (self *_Pseudo) encodeQuad(m *[]byte) {
if m != nil {
if v, err := self.expr.Evaluate(); err != nil {
panic(err)
} else {
append64(m, uint64(v))
}
}
if m != nil {
if v, err := self.expr.Evaluate(); err != nil {
panic(err)
} else {
append64(m, uint64(v))
}
}
}
func (self *_Pseudo) encodeAlign(m *[]byte, pc uintptr) {
if m != nil {
if self.expr == nil {
expandmm(m, self.alignSize(pc), 0)
} else {
expandmm(m, self.alignSize(pc), byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
}
}
if m != nil {
if self.expr == nil {
expandmm(m, self.alignSize(pc), 0)
} else {
expandmm(m, self.alignSize(pc), byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
}
}
}
// Operands represents a sequence of operand required by an instruction.
@ -131,15 +153,15 @@ type Operands [_N_args]interface{}
type InstructionDomain uint8
const (
DomainGeneric InstructionDomain = iota
DomainMMXSSE
DomainAVX
DomainFMA
DomainCrypto
DomainMask
DomainAMDSpecific
DomainMisc
DomainPseudo
DomainGeneric InstructionDomain = iota
DomainMMXSSE
DomainAVX
DomainFMA
DomainCrypto
DomainMask
DomainAMDSpecific
DomainMisc
DomainPseudo
)
type (
@ -147,139 +169,139 @@ type (
)
const (
_B_none _BranchType = iota
_B_conditional
_B_unconditional
_B_none _BranchType = iota
_B_conditional
_B_unconditional
)
// Instruction represents an unencoded instruction.
type Instruction struct {
next *Instruction
pc uintptr
nb int
len int
argc int
name string
argv Operands
forms [_N_forms]_Encoding
pseudo _Pseudo
branch _BranchType
domain InstructionDomain
prefix []byte
next *Instruction
pc uintptr
nb int
len int
argc int
name string
argv Operands
forms [_N_forms]_Encoding
pseudo _Pseudo
branch _BranchType
domain InstructionDomain
prefix []byte
}
func (self *Instruction) add(flags int, encoder func(m *_Encoding, v []interface{})) {
self.forms[self.len].flags = flags
self.forms[self.len].encoder = encoder
self.len++
self.forms[self.len].flags = flags
self.forms[self.len].encoder = encoder
self.len++
}
func (self *Instruction) free() {
self.clear()
self.pseudo.free()
freeInstruction(self)
self.clear()
self.pseudo.free()
//freeInstruction(self)
}
func (self *Instruction) clear() {
for i := 0; i < self.argc; i++ {
if v, ok := self.argv[i].(Disposable); ok {
v.Free()
}
}
for i := 0; i < self.argc; i++ {
if v, ok := self.argv[i].(Disposable); ok {
v.Free()
}
}
}
func (self *Instruction) check(e *_Encoding) bool {
if (e.flags & _F_rel1) != 0 {
return isRel8(self.argv[0])
} else if (e.flags & _F_rel4) != 0 {
return isRel32(self.argv[0]) || isLabel(self.argv[0])
} else {
return true
}
if (e.flags & _F_rel1) != 0 {
return isRel8(self.argv[0])
} else if (e.flags & _F_rel4) != 0 {
return isRel32(self.argv[0]) || isLabel(self.argv[0])
} else {
return true
}
}
func (self *Instruction) encode(m *[]byte) int {
n := math.MaxInt64
p := (*_Encoding)(nil)
n := math.MaxInt64
p := (*_Encoding)(nil)
/* encode prefixes if any */
if self.nb = len(self.prefix); m != nil {
*m = append(*m, self.prefix...)
}
/* encode prefixes if any */
if self.nb = len(self.prefix); m != nil {
*m = append(*m, self.prefix...)
}
/* check for pseudo-instructions */
if self.pseudo.kind != 0 {
self.nb += self.pseudo.encode(m, self.pc)
return self.nb
}
/* check for pseudo-instructions */
if self.pseudo.kind != 0 {
self.nb += self.pseudo.encode(m, self.pc)
return self.nb
}
/* find the shortest encoding */
for i := 0; i < self.len; i++ {
if e := &self.forms[i]; self.check(e) {
if v := e.encode(self.argv[:self.argc]); v < n {
n = v
p = e
}
}
}
/* find the shortest encoding */
for i := 0; i < self.len; i++ {
if e := &self.forms[i]; self.check(e) {
if v := e.encode(self.argv[:self.argc]); v < n {
n = v
p = e
}
}
}
/* add to buffer if needed */
if m != nil {
*m = append(*m, p.bytes[:n]...)
}
/* add to buffer if needed */
if m != nil {
*m = append(*m, p.bytes[:n]...)
}
/* update the instruction length */
self.nb += n
return self.nb
/* update the instruction length */
self.nb += n
return self.nb
}
/** Instruction Prefixes **/
const (
_P_cs = 0x2e
_P_ds = 0x3e
_P_es = 0x26
_P_fs = 0x64
_P_gs = 0x65
_P_ss = 0x36
_P_lock = 0xf0
_P_cs = 0x2e
_P_ds = 0x3e
_P_es = 0x26
_P_fs = 0x64
_P_gs = 0x65
_P_ss = 0x36
_P_lock = 0xf0
)
// CS overrides the memory operation of this instruction to CS.
func (self *Instruction) CS() *Instruction {
self.prefix = append(self.prefix, _P_cs)
return self
self.prefix = append(self.prefix, _P_cs)
return self
}
// DS overrides the memory operation of this instruction to DS,
// this is the default section for most instructions if not specified.
func (self *Instruction) DS() *Instruction {
self.prefix = append(self.prefix, _P_ds)
return self
self.prefix = append(self.prefix, _P_ds)
return self
}
// ES overrides the memory operation of this instruction to ES.
func (self *Instruction) ES() *Instruction {
self.prefix = append(self.prefix, _P_es)
return self
self.prefix = append(self.prefix, _P_es)
return self
}
// FS overrides the memory operation of this instruction to FS.
func (self *Instruction) FS() *Instruction {
self.prefix = append(self.prefix, _P_fs)
return self
self.prefix = append(self.prefix, _P_fs)
return self
}
// GS overrides the memory operation of this instruction to GS.
func (self *Instruction) GS() *Instruction {
self.prefix = append(self.prefix, _P_gs)
return self
self.prefix = append(self.prefix, _P_gs)
return self
}
// SS overrides the memory operation of this instruction to SS.
func (self *Instruction) SS() *Instruction {
self.prefix = append(self.prefix, _P_ss)
return self
self.prefix = append(self.prefix, _P_ss)
return self
}
// LOCK causes the processor's LOCK# signal to be asserted during execution of
@ -287,128 +309,132 @@ func (self *Instruction) SS() *Instruction {
// In a multiprocessor environment, the LOCK# signal insures that the processor
// has exclusive use of any shared memory while the signal is asserted.
func (self *Instruction) LOCK() *Instruction {
self.prefix = append(self.prefix, _P_lock)
return self
self.prefix = append(self.prefix, _P_lock)
return self
}
/** Basic Instruction Properties **/
// Name returns the instruction name.
func (self *Instruction) Name() string {
return self.name
return self.name
}
// Domain returns the domain of this instruction.
func (self *Instruction) Domain() InstructionDomain {
return self.domain
return self.domain
}
// Operands returns the operands of this instruction.
func (self *Instruction) Operands() []interface{} {
return self.argv[:self.argc]
return self.argv[:self.argc]
}
// Program represents a sequence of instructions.
type Program struct {
arch *Arch
head *Instruction
tail *Instruction
arch *Arch
head *Instruction
tail *Instruction
}
const (
_N_near = 2 // near-branch (-128 ~ +127) takes 2 bytes to encode
_N_far_cond = 6 // conditional far-branch takes 6 bytes to encode
_N_far_uncond = 5 // unconditional far-branch takes 5 bytes to encode
_N_near = 2 // near-branch (-128 ~ +127) takes 2 bytes to encode
_N_far_cond = 6 // conditional far-branch takes 6 bytes to encode
_N_far_uncond = 5 // unconditional far-branch takes 5 bytes to encode
)
func (self *Program) clear() {
for p, q := self.head, self.head; p != nil; p = q {
q = p.next
p.free()
}
for p, q := self.head, self.head; p != nil; p = q {
q = p.next
p.free()
}
}
func (self *Program) alloc(name string, argc int, argv Operands) *Instruction {
p := self.tail
q := newInstruction(name, argc, argv)
p := self.tail
q := newInstruction(name, argc, argv)
/* attach to tail if any */
if p != nil {
p.next = q
} else {
self.head = q
}
/* attach to tail if any */
if p != nil {
p.next = q
} else {
self.head = q
}
/* set the new tail */
self.tail = q
return q
/* set the new tail */
self.tail = q
return q
}
func (self *Program) pseudo(kind _PseudoType) (p *Instruction) {
p = self.alloc(kind.String(), 0, Operands{})
p.domain = DomainPseudo
p.pseudo.kind = kind
return
p = self.alloc(kind.String(), 0, Operands{})
p.domain = DomainPseudo
p.pseudo.kind = kind
return
}
func (self *Program) require(isa ISA) {
if !self.arch.HasISA(isa) {
panic("ISA '" + isa.String() + "' was not enabled")
}
if !self.arch.HasISA(isa) {
panic("ISA '" + isa.String() + "' was not enabled")
}
}
func (self *Program) branchSize(p *Instruction) int {
switch p.branch {
case _B_none : panic("p is not a branch")
case _B_conditional : return _N_far_cond
case _B_unconditional : return _N_far_uncond
default : panic("invalid instruction")
}
switch p.branch {
case _B_none:
panic("p is not a branch")
case _B_conditional:
return _N_far_cond
case _B_unconditional:
return _N_far_uncond
default:
panic("invalid instruction")
}
}
/** Pseudo-Instructions **/
// Byte is a pseudo-instruction to add raw byte to the assembled code.
func (self *Program) Byte(v *expr.Expr) (p *Instruction) {
p = self.pseudo(_PseudoByte)
p.pseudo.expr = v
return
p = self.pseudo(_PseudoByte)
p.pseudo.expr = v
return
}
// Word is a pseudo-instruction to add raw uint16 as little-endian to the assembled code.
func (self *Program) Word(v *expr.Expr) (p *Instruction) {
p = self.pseudo(_PseudoWord)
p.pseudo.expr = v
return
p = self.pseudo(_PseudoWord)
p.pseudo.expr = v
return
}
// Long is a pseudo-instruction to add raw uint32 as little-endian to the assembled code.
func (self *Program) Long(v *expr.Expr) (p *Instruction) {
p = self.pseudo(_PseudoLong)
p.pseudo.expr = v
return
p = self.pseudo(_PseudoLong)
p.pseudo.expr = v
return
}
// Quad is a pseudo-instruction to add raw uint64 as little-endian to the assembled code.
func (self *Program) Quad(v *expr.Expr) (p *Instruction) {
p = self.pseudo(_PseudoQuad)
p.pseudo.expr = v
return
p = self.pseudo(_PseudoQuad)
p.pseudo.expr = v
return
}
// Data is a pseudo-instruction to add raw bytes to the assembled code.
func (self *Program) Data(v []byte) (p *Instruction) {
p = self.pseudo(_PseudoData)
p.pseudo.data = v
return
p = self.pseudo(_PseudoData)
p.pseudo.data = v
return
}
// Align is a pseudo-instruction to ensure the PC is aligned to a certain value.
func (self *Program) Align(align uint64, padding *expr.Expr) (p *Instruction) {
p = self.pseudo(_PseudoAlign)
p.pseudo.uint = align
p.pseudo.expr = padding
return
p = self.pseudo(_PseudoAlign)
p.pseudo.uint = align
p.pseudo.expr = padding
return
}
/** Program Assembler **/
@ -417,126 +443,126 @@ func (self *Program) Align(align uint64, padding *expr.Expr) (p *Instruction) {
// Any operation performed after Free is undefined behavior.
//
// NOTE: This also frees all the instructions, labels, memory
// operands and expressions associated with this program.
//
// operands and expressions associated with this program.
func (self *Program) Free() {
self.clear()
freeProgram(self)
self.clear()
//freeProgram(self)
}
// Link pins a label at the current position.
func (self *Program) Link(p *Label) {
if p.Dest != nil {
panic("lable was alreay linked")
} else {
p.Dest = self.pseudo(_PseudoNop)
}
if p.Dest != nil {
panic("lable was alreay linked")
} else {
p.Dest = self.pseudo(_PseudoNop)
}
}
// Assemble assembles and links the entire program into machine code.
func (self *Program) Assemble(pc uintptr) (ret []byte) {
orig := pc
next := true
offs := uintptr(0)
orig := pc
next := true
offs := uintptr(0)
/* Pass 0: PC-precompute, assume all labeled branches are far-branches. */
for p := self.head; p != nil; p = p.next {
if p.pc = pc; !isLabel(p.argv[0]) || p.branch == _B_none {
pc += uintptr(p.encode(nil))
} else {
pc += uintptr(self.branchSize(p))
}
}
/* Pass 0: PC-precompute, assume all labeled branches are far-branches. */
for p := self.head; p != nil; p = p.next {
if p.pc = pc; !isLabel(p.argv[0]) || p.branch == _B_none {
pc += uintptr(p.encode(nil))
} else {
pc += uintptr(self.branchSize(p))
}
}
/* allocate space for the machine code */
nb := int(pc - orig)
ret = make([]byte, 0, nb)
/* allocate space for the machine code */
nb := int(pc - orig)
ret = make([]byte, 0, nb)
/* Pass 1: adjust all the jumps */
for next {
next = false
offs = uintptr(0)
/* Pass 1: adjust all the jumps */
for next {
next = false
offs = uintptr(0)
/* scan all the branches */
for p := self.head; p != nil; p = p.next {
var ok bool
var lb *Label
/* scan all the branches */
for p := self.head; p != nil; p = p.next {
var ok bool
var lb *Label
/* re-calculate the alignment here */
if nb = p.nb; p.pseudo.kind == _PseudoAlign {
p.pc -= offs
offs += uintptr(nb - p.encode(nil))
continue
}
/* re-calculate the alignment here */
if nb = p.nb; p.pseudo.kind == _PseudoAlign {
p.pc -= offs
offs += uintptr(nb - p.encode(nil))
continue
}
/* adjust the program counter */
p.pc -= offs
lb, ok = p.argv[0].(*Label)
/* adjust the program counter */
p.pc -= offs
lb, ok = p.argv[0].(*Label)
/* only care about labeled far-branches */
if !ok || p.nb == _N_near || p.branch == _B_none {
continue
}
/* only care about labeled far-branches */
if !ok || p.nb == _N_near || p.branch == _B_none {
continue
}
/* calculate the jump offset */
size := self.branchSize(p)
diff := lb.offset(p.pc, size)
/* calculate the jump offset */
size := self.branchSize(p)
diff := lb.offset(p.pc, size)
/* too far to be a near jump */
if diff > 127 || diff < -128 {
p.nb = size
continue
}
/* too far to be a near jump */
if diff > 127 || diff < -128 {
p.nb = size
continue
}
/* a far jump becomes a near jump, calculate
* the PC adjustment value and assemble again */
next = true
p.nb = _N_near
offs += uintptr(size - _N_near)
}
}
/* a far jump becomes a near jump, calculate
* the PC adjustment value and assemble again */
next = true
p.nb = _N_near
offs += uintptr(size - _N_near)
}
}
/* Pass 3: link all the cross-references */
for p := self.head; p != nil; p = p.next {
for i := 0; i < p.argc; i++ {
var ok bool
var lb *Label
var op *MemoryOperand
/* Pass 3: link all the cross-references */
for p := self.head; p != nil; p = p.next {
for i := 0; i < p.argc; i++ {
var ok bool
var lb *Label
var op *MemoryOperand
/* resolve labels */
if lb, ok = p.argv[i].(*Label); ok {
p.argv[i] = lb.offset(p.pc, p.nb)
continue
}
/* resolve labels */
if lb, ok = p.argv[i].(*Label); ok {
p.argv[i] = lb.offset(p.pc, p.nb)
continue
}
/* check for memory operands */
if op, ok = p.argv[i].(*MemoryOperand); !ok {
continue
}
/* check for memory operands */
if op, ok = p.argv[i].(*MemoryOperand); !ok {
continue
}
/* check for label references */
if op.Addr.Type != Reference {
continue
}
/* check for label references */
if op.Addr.Type != Reference {
continue
}
/* replace the label with the real offset */
op.Addr.Type = Offset
op.Addr.Offset = op.Addr.Reference.offset(p.pc, p.nb)
}
}
/* replace the label with the real offset */
op.Addr.Type = Offset
op.Addr.Offset = op.Addr.Reference.offset(p.pc, p.nb)
}
}
/* Pass 4: actually encode all the instructions */
for p := self.head; p != nil; p = p.next {
p.encode(&ret)
}
/* Pass 4: actually encode all the instructions */
for p := self.head; p != nil; p = p.next {
p.encode(&ret)
}
/* all done */
return ret
/* all done */
return ret
}
// AssembleAndFree is like Assemble, but it frees the Program after assembling.
func (self *Program) AssembleAndFree(pc uintptr) (ret []byte) {
ret = self.Assemble(pc)
self.Free()
return
}
ret = self.Assemble(pc)
self.Free()
return
}