123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675 |
- package x86_64
- import (
- `encoding/binary`
- `math`
- )
- /** Operand Encoding Helpers **/
- func imml(v interface{}) byte {
- return byte(toImmAny(v) & 0x0f)
- }
- func relv(v interface{}) int64 {
- switch r := v.(type) {
- case *Label : return 0
- case RelativeOffset : return int64(r)
- default : panic("invalid relative offset")
- }
- }
- func addr(v interface{}) interface{} {
- switch a := v.(*MemoryOperand).Addr; a.Type {
- case Memory : return a.Memory
- case Offset : return a.Offset
- case Reference : return a.Reference
- default : panic("invalid memory operand type")
- }
- }
- func bcode(v interface{}) byte {
- if m, ok := v.(*MemoryOperand); !ok {
- panic("v is not a memory operand")
- } else if m.Broadcast == 0 {
- return 0
- } else {
- return 1
- }
- }
- func vcode(v interface{}) byte {
- switch r := v.(type) {
- case XMMRegister : return byte(r)
- case YMMRegister : return byte(r)
- case ZMMRegister : return byte(r)
- case MaskedRegister : return vcode(r.Reg)
- default : panic("v is not a vector register")
- }
- }
- func kcode(v interface{}) byte {
- switch r := v.(type) {
- case KRegister : return byte(r)
- case XMMRegister : return 0
- case YMMRegister : return 0
- case ZMMRegister : return 0
- case RegisterMask : return byte(r.K)
- case MaskedRegister : return byte(r.Mask.K)
- case *MemoryOperand : return toKcodeMem(r)
- default : panic("v is not a maskable operand")
- }
- }
- func zcode(v interface{}) byte {
- switch r := v.(type) {
- case KRegister : return 0
- case XMMRegister : return 0
- case YMMRegister : return 0
- case ZMMRegister : return 0
- case RegisterMask : return toZcodeRegM(r)
- case MaskedRegister : return toZcodeRegM(r.Mask)
- case *MemoryOperand : return toZcodeMem(r)
- default : panic("v is not a maskable operand")
- }
- }
- func lcode(v interface{}) byte {
- switch r := v.(type) {
- case Register8 : return byte(r & 0x07)
- case Register16 : return byte(r & 0x07)
- case Register32 : return byte(r & 0x07)
- case Register64 : return byte(r & 0x07)
- case KRegister : return byte(r & 0x07)
- case MMRegister : return byte(r & 0x07)
- case XMMRegister : return byte(r & 0x07)
- case YMMRegister : return byte(r & 0x07)
- case ZMMRegister : return byte(r & 0x07)
- case MaskedRegister : return lcode(r.Reg)
- default : panic("v is not a register")
- }
- }
- func hcode(v interface{}) byte {
- switch r := v.(type) {
- case Register8 : return byte(r >> 3) & 1
- case Register16 : return byte(r >> 3) & 1
- case Register32 : return byte(r >> 3) & 1
- case Register64 : return byte(r >> 3) & 1
- case KRegister : return byte(r >> 3) & 1
- case MMRegister : return byte(r >> 3) & 1
- case XMMRegister : return byte(r >> 3) & 1
- case YMMRegister : return byte(r >> 3) & 1
- case ZMMRegister : return byte(r >> 3) & 1
- case MaskedRegister : return hcode(r.Reg)
- default : panic("v is not a register")
- }
- }
- func ecode(v interface{}) byte {
- switch r := v.(type) {
- case Register8 : return byte(r >> 4) & 1
- case Register16 : return byte(r >> 4) & 1
- case Register32 : return byte(r >> 4) & 1
- case Register64 : return byte(r >> 4) & 1
- case KRegister : return byte(r >> 4) & 1
- case MMRegister : return byte(r >> 4) & 1
- case XMMRegister : return byte(r >> 4) & 1
- case YMMRegister : return byte(r >> 4) & 1
- case ZMMRegister : return byte(r >> 4) & 1
- case MaskedRegister : return ecode(r.Reg)
- default : panic("v is not a register")
- }
- }
- func hlcode(v interface{}) byte {
- switch r := v.(type) {
- case Register8 : return toHLcodeReg8(r)
- case Register16 : return byte(r & 0x0f)
- case Register32 : return byte(r & 0x0f)
- case Register64 : return byte(r & 0x0f)
- case KRegister : return byte(r & 0x0f)
- case MMRegister : return byte(r & 0x0f)
- case XMMRegister : return byte(r & 0x0f)
- case YMMRegister : return byte(r & 0x0f)
- case ZMMRegister : return byte(r & 0x0f)
- case MaskedRegister : return hlcode(r.Reg)
- default : panic("v is not a register")
- }
- }
- func ehcode(v interface{}) byte {
- switch r := v.(type) {
- case Register8 : return byte(r >> 3) & 0x03
- case Register16 : return byte(r >> 3) & 0x03
- case Register32 : return byte(r >> 3) & 0x03
- case Register64 : return byte(r >> 3) & 0x03
- case KRegister : return byte(r >> 3) & 0x03
- case MMRegister : return byte(r >> 3) & 0x03
- case XMMRegister : return byte(r >> 3) & 0x03
- case YMMRegister : return byte(r >> 3) & 0x03
- case ZMMRegister : return byte(r >> 3) & 0x03
- case MaskedRegister : return ehcode(r.Reg)
- default : panic("v is not a register")
- }
- }
- func toImmAny(v interface{}) int64 {
- if x, ok := asInt64(v); ok {
- return x
- } else {
- panic("value is not an integer")
- }
- }
- func toHcodeOpt(v interface{}) byte {
- if v == nil {
- return 0
- } else {
- return hcode(v)
- }
- }
- func toEcodeVMM(v interface{}, x byte) byte {
- switch r := v.(type) {
- case XMMRegister : return ecode(r)
- case YMMRegister : return ecode(r)
- case ZMMRegister : return ecode(r)
- default : return x
- }
- }
- func toKcodeMem(v *MemoryOperand) byte {
- if !v.Masked {
- return 0
- } else {
- return byte(v.Mask.K)
- }
- }
- func toZcodeMem(v *MemoryOperand) byte {
- if !v.Masked || v.Mask.Z {
- return 0
- } else {
- return 1
- }
- }
- func toZcodeRegM(v RegisterMask) byte {
- if v.Z {
- return 1
- } else {
- return 0
- }
- }
- func toHLcodeReg8(v Register8) byte {
- switch v {
- case AH: fallthrough
- case BH: fallthrough
- case CH: fallthrough
- case DH: panic("ah/bh/ch/dh registers never use 4-bit encoding")
- default: return byte(v & 0x0f)
- }
- }
- /** Instruction Encoding Helpers **/
- const (
- _N_inst = 16
- )
- const (
- _F_rel1 = 1 << iota
- _F_rel4
- )
- type _Encoding struct {
- len int
- flags int
- bytes [_N_inst]byte
- encoder func(m *_Encoding, v []interface{})
- }
- // buf ensures len + n <= len(bytes).
- func (self *_Encoding) buf(n int) []byte {
- if i := self.len; i + n > _N_inst {
- panic("instruction too long")
- } else {
- return self.bytes[i:]
- }
- }
- // emit encodes a single byte.
- func (self *_Encoding) emit(v byte) {
- self.buf(1)[0] = v
- self.len++
- }
- // imm1 encodes a single byte immediate value.
- func (self *_Encoding) imm1(v int64) {
- self.emit(byte(v))
- }
- // imm2 encodes a two-byte immediate value in little-endian.
- func (self *_Encoding) imm2(v int64) {
- binary.LittleEndian.PutUint16(self.buf(2), uint16(v))
- self.len += 2
- }
- // imm4 encodes a 4-byte immediate value in little-endian.
- func (self *_Encoding) imm4(v int64) {
- binary.LittleEndian.PutUint32(self.buf(4), uint32(v))
- self.len += 4
- }
- // imm8 encodes an 8-byte immediate value in little-endian.
- func (self *_Encoding) imm8(v int64) {
- binary.LittleEndian.PutUint64(self.buf(8), uint64(v))
- self.len += 8
- }
- // vex2 encodes a 2-byte or 3-byte VEX prefix.
- //
- // 2-byte VEX prefix:
- // Requires: VEX.W = 0, VEX.mmmmm = 0b00001 and VEX.B = VEX.X = 0
- // +----------------+
- // Byte 0: | Bits 0-7: 0xc5 |
- // +----------------+
- //
- // +-----------+----------------+----------+--------------+
- // Byte 1: | Bit 7: ~R | Bits 3-6 ~vvvv | Bit 2: L | Bits 0-1: pp |
- // +-----------+----------------+----------+--------------+
- //
- // 3-byte VEX prefix:
- // +----------------+
- // Byte 0: | Bits 0-7: 0xc4 |
- // +----------------+
- //
- // +-----------+-----------+-----------+-------------------+
- // Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: 0b00001 |
- // +-----------+-----------+-----------+-------------------+
- //
- // +----------+-----------------+----------+--------------+
- // Byte 2: | Bit 7: 0 | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
- // +----------+-----------------+----------+--------------+
- //
- func (self *_Encoding) vex2(lpp byte, r byte, rm interface{}, vvvv byte) {
- var b byte
- var x byte
- /* VEX.R must be a single-bit mask */
- if r > 1 {
- panic("VEX.R must be a 1-bit mask")
- }
- /* VEX.Lpp must be a 3-bit mask */
- if lpp &^ 0b111 != 0 {
- panic("VEX.Lpp must be a 3-bit mask")
- }
- /* VEX.vvvv must be a 4-bit mask */
- if vvvv &^ 0b1111 != 0 {
- panic("VEX.vvvv must be a 4-bit mask")
- }
- /* encode the RM bits if any */
- if rm != nil {
- switch v := rm.(type) {
- case *Label : break
- case Register : b = hcode(v)
- case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
- case RelativeOffset : break
- default : panic("rm is expected to be a register or a memory address")
- }
- }
- /* if VEX.B and VEX.X are zeroes, 2-byte VEX prefix can be used */
- if x == 0 && b == 0 {
- self.emit(0xc5)
- self.emit(0xf8 ^ (r << 7) ^ (vvvv << 3) ^ lpp)
- } else {
- self.emit(0xc4)
- self.emit(0xe1 ^ (r << 7) ^ (x << 6) ^ (b << 5))
- self.emit(0x78 ^ (vvvv << 3) ^ lpp)
- }
- }
- // vex3 encodes a 3-byte VEX or XOP prefix.
- //
- // 3-byte VEX/XOP prefix
- // +-----------------------------------+
- // Byte 0: | Bits 0-7: 0xc4 (VEX) / 0x8f (XOP) |
- // +-----------------------------------+
- //
- // +-----------+-----------+-----------+-----------------+
- // Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: mmmmm |
- // +-----------+-----------+-----------+-----------------+
- //
- // +----------+-----------------+----------+--------------+
- // Byte 2: | Bit 7: W | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
- // +----------+-----------------+----------+--------------+
- //
- func (self *_Encoding) vex3(esc byte, mmmmm byte, wlpp byte, r byte, rm interface{}, vvvv byte) {
- var b byte
- var x byte
- /* VEX.R must be a single-bit mask */
- if r > 1 {
- panic("VEX.R must be a 1-bit mask")
- }
- /* VEX.vvvv must be a 4-bit mask */
- if vvvv &^ 0b1111 != 0 {
- panic("VEX.vvvv must be a 4-bit mask")
- }
- /* escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix */
- if esc != 0xc4 && esc != 0x8f {
- panic("escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix")
- }
- /* VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7 */
- if wlpp &^ 0b10000111 != 0 {
- panic("VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7")
- }
- /* VEX.m-mmmm is expected to be a 5-bit mask */
- if mmmmm &^ 0b11111 != 0 {
- panic("VEX.m-mmmm is expected to be a 5-bit mask")
- }
- /* encode the RM bits */
- switch v := rm.(type) {
- case *Label : break
- case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
- case RelativeOffset : break
- default : panic("rm is expected to be a register or a memory address")
- }
- /* encode the 3-byte VEX or XOP prefix */
- self.emit(esc)
- self.emit(0xe0 ^ (r << 7) ^ (x << 6) ^ (b << 5) ^ mmmmm)
- self.emit(0x78 ^ (vvvv << 3) ^ wlpp)
- }
- // evex encodes a 4-byte EVEX prefix.
- func (self *_Encoding) evex(mm byte, w1pp byte, ll byte, rr byte, rm interface{}, vvvvv byte, aaa byte, zz byte, bb byte) {
- var b byte
- var x byte
- /* EVEX.b must be a single-bit mask */
- if bb > 1 {
- panic("EVEX.b must be a 1-bit mask")
- }
- /* EVEX.z must be a single-bit mask */
- if zz > 1 {
- panic("EVEX.z must be a 1-bit mask")
- }
- /* EVEX.mm must be a 2-bit mask */
- if mm &^ 0b11 != 0 {
- panic("EVEX.mm must be a 2-bit mask")
- }
- /* EVEX.L'L must be a 2-bit mask */
- if ll &^ 0b11 != 0 {
- panic("EVEX.L'L must be a 2-bit mask")
- }
- /* EVEX.R'R must be a 2-bit mask */
- if rr &^ 0b11 != 0 {
- panic("EVEX.R'R must be a 2-bit mask")
- }
- /* EVEX.aaa must be a 3-bit mask */
- if aaa &^ 0b111 != 0 {
- panic("EVEX.aaa must be a 3-bit mask")
- }
- /* EVEX.v'vvvv must be a 5-bit mask */
- if vvvvv &^ 0b11111 != 0 {
- panic("EVEX.v'vvvv must be a 5-bit mask")
- }
- /* EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7 */
- if w1pp &^ 0b10000011 != 0b100 {
- panic("EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7")
- }
- /* extract bits from EVEX.R'R and EVEX.v'vvvv */
- r1, r0 := rr >> 1, rr & 1
- v1, v0 := vvvvv >> 4, vvvvv & 0b1111
- /* encode the RM bits if any */
- if rm != nil {
- switch m := rm.(type) {
- case *Label : break
- case Register : b, x = hcode(m), ecode(m)
- case MemoryAddress : b, x, v1 = toHcodeOpt(m.Base), toHcodeOpt(m.Index), toEcodeVMM(m.Index, v1)
- case RelativeOffset : break
- default : panic("rm is expected to be a register or a memory address")
- }
- }
- /* EVEX prefix bytes */
- p0 := (r0 << 7) | (x << 6) | (b << 5) | (r1 << 4) | mm
- p1 := (v0 << 3) | w1pp
- p2 := (zz << 7) | (ll << 5) | (b << 4) | (v1 << 3) | aaa
- /* p0: invert RXBR' (bits 4-7)
- * p1: invert vvvv (bits 3-6)
- * p2: invert V' (bit 3) */
- self.emit(0x62)
- self.emit(p0 ^ 0xf0)
- self.emit(p1 ^ 0x78)
- self.emit(p2 ^ 0x08)
- }
- // rexm encodes a mandatory REX prefix.
- func (self *_Encoding) rexm(w byte, r byte, rm interface{}) {
- var b byte
- var x byte
- /* REX.R must be 0 or 1 */
- if r != 0 && r != 1 {
- panic("REX.R must be 0 or 1")
- }
- /* REX.W must be 0 or 1 */
- if w != 0 && w != 1 {
- panic("REX.W must be 0 or 1")
- }
- /* encode the RM bits */
- switch v := rm.(type) {
- case *Label : break
- case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
- case RelativeOffset : break
- default : panic("rm is expected to be a register or a memory address")
- }
- /* encode the REX prefix */
- self.emit(0x40 | (w << 3) | (r << 2) | (x << 1) | b)
- }
- // rexo encodes an optional REX prefix.
- func (self *_Encoding) rexo(r byte, rm interface{}, force bool) {
- var b byte
- var x byte
- /* REX.R must be 0 or 1 */
- if r != 0 && r != 1 {
- panic("REX.R must be 0 or 1")
- }
- /* encode the RM bits */
- switch v := rm.(type) {
- case *Label : break
- case Register : b = hcode(v)
- case MemoryAddress : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
- case RelativeOffset : break
- default : panic("rm is expected to be a register or a memory address")
- }
- /* if REX.R, REX.X, and REX.B are all zeroes, REX prefix can be omitted */
- if force || r != 0 || x != 0 || b != 0 {
- self.emit(0x40 | (r << 2) | (x << 1) | b)
- }
- }
- // mrsd encodes ModR/M, SIB and Displacement.
- //
- // ModR/M byte
- // +----------------+---------------+---------------+
- // | Bits 6-7: Mode | Bits 3-5: Reg | Bits 0-2: R/M |
- // +----------------+---------------+---------------+
- //
- // SIB byte
- // +-----------------+-----------------+----------------+
- // | Bits 6-7: Scale | Bits 3-5: Index | Bits 0-2: Base |
- // +-----------------+-----------------+----------------+
- //
- func (self *_Encoding) mrsd(reg byte, rm interface{}, disp8v int32) {
- var ok bool
- var mm MemoryAddress
- var ro RelativeOffset
- /* ModRM encodes the lower 3-bit of the register */
- if reg > 7 {
- panic("invalid register bits")
- }
- /* check the displacement scale */
- switch disp8v {
- case 1: break
- case 2: break
- case 4: break
- case 8: break
- case 16: break
- case 32: break
- case 64: break
- default: panic("invalid displacement size")
- }
- /* special case: unresolved labels, assuming a zero offset */
- if _, ok = rm.(*Label); ok {
- self.emit(0x05 | (reg << 3))
- self.imm4(0)
- return
- }
- /* special case: RIP-relative offset
- * ModRM.Mode == 0 and ModeRM.R/M == 5 indicates (rip + disp32) addressing */
- if ro, ok = rm.(RelativeOffset); ok {
- self.emit(0x05 | (reg << 3))
- self.imm4(int64(ro))
- return
- }
- /* must be a generic memory address */
- if mm, ok = rm.(MemoryAddress); !ok {
- panic("rm must be a memory address")
- }
- /* absolute addressing, encoded as disp(%rbp,%rsp,1) */
- if mm.Base == nil && mm.Index == nil {
- self.emit(0x04 | (reg << 3))
- self.emit(0x25)
- self.imm4(int64(mm.Displacement))
- return
- }
- /* no SIB byte */
- if mm.Index == nil && lcode(mm.Base) != 0b100 {
- cc := lcode(mm.Base)
- dv := mm.Displacement
- /* ModRM.Mode == 0 (no displacement) */
- if dv == 0 && mm.Base != RBP && mm.Base != R13 {
- if cc == 0b101 {
- panic("rbp/r13 is not encodable as a base register (interpreted as disp32 address)")
- } else {
- self.emit((reg << 3) | cc)
- return
- }
- }
- /* ModRM.Mode == 1 (8-bit displacement) */
- if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv % disp8v == 0 {
- self.emit(0x40 | (reg << 3) | cc)
- self.imm1(int64(dq))
- return
- }
- /* ModRM.Mode == 2 (32-bit displacement) */
- self.emit(0x80 | (reg << 3) | cc)
- self.imm4(int64(mm.Displacement))
- return
- }
- /* all encodings below use ModRM.R/M = 4 (0b100) to indicate the presence of SIB */
- if mm.Index == RSP {
- panic("rsp is not encodable as an index register (interpreted as no index)")
- }
- /* index = 4 (0b100) denotes no-index encoding */
- var scale byte
- var index byte = 0x04
- /* encode the scale byte */
- if mm.Scale != 0 {
- switch mm.Scale {
- case 1 : scale = 0
- case 2 : scale = 1
- case 4 : scale = 2
- case 8 : scale = 3
- default : panic("invalid scale value")
- }
- }
- /* encode the index byte */
- if mm.Index != nil {
- index = lcode(mm.Index)
- }
- /* SIB.Base = 5 (0b101) and ModRM.Mode = 0 indicates no-base encoding with disp32 */
- if mm.Base == nil {
- self.emit((reg << 3) | 0b100)
- self.emit((scale << 6) | (index << 3) | 0b101)
- self.imm4(int64(mm.Displacement))
- return
- }
- /* base L-code & displacement value */
- cc := lcode(mm.Base)
- dv := mm.Displacement
- /* ModRM.Mode == 0 (no displacement) */
- if dv == 0 && cc != 0b101 {
- self.emit((reg << 3) | 0b100)
- self.emit((scale << 6) | (index << 3) | cc)
- return
- }
- /* ModRM.Mode == 1 (8-bit displacement) */
- if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv % disp8v == 0 {
- self.emit(0x44 | (reg << 3))
- self.emit((scale << 6) | (index << 3) | cc)
- self.imm1(int64(dq))
- return
- }
- /* ModRM.Mode == 2 (32-bit displacement) */
- self.emit(0x84 | (reg << 3))
- self.emit((scale << 6) | (index << 3) | cc)
- self.imm4(int64(mm.Displacement))
- }
- // encode invokes the encoder to encode this instruction.
- func (self *_Encoding) encode(v []interface{}) int {
- self.len = 0
- self.encoder(self, v)
- return self.len
- }
|