github.com/cloudwego/iasm@v0.2.0/x86_64/encodings.go (about)

     1  //
     2  // Copyright 2024 CloudWeGo Authors
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package x86_64
    18  
    19  import (
    20      `encoding/binary`
    21      `math`
    22  )
    23  
    24  /** Operand Encoding Helpers **/
    25  
    26  func imml(v interface{}) byte {
    27      return byte(toImmAny(v) & 0x0f)
    28  }
    29  
    30  func relv(v interface{}) int64 {
    31      switch r := v.(type) {
    32          case *Label         : return 0
    33          case RelativeOffset : return int64(r)
    34          default             : panic("invalid relative offset")
    35      }
    36  }
    37  
    38  func addr(v interface{}) interface{} {
    39      switch a := v.(*MemoryOperand).Addr; a.Type {
    40          case Memory    : return a.Memory
    41          case Offset    : return a.Offset
    42          case Reference : return a.Reference
    43          default        : panic("invalid memory operand type")
    44      }
    45  }
    46  
    47  func bcode(v interface{}) byte {
    48      if m, ok := v.(*MemoryOperand); !ok {
    49          panic("v is not a memory operand")
    50      } else if m.Broadcast == 0 {
    51          return 0
    52      } else {
    53          return 1
    54      }
    55  }
    56  
    57  func vcode(v interface{}) byte {
    58      switch r := v.(type) {
    59          case XMMRegister    : return byte(r)
    60          case YMMRegister    : return byte(r)
    61          case ZMMRegister    : return byte(r)
    62          case MaskedRegister : return vcode(r.Reg)
    63          default             : panic("v is not a vector register")
    64      }
    65  }
    66  
    67  func kcode(v interface{}) byte {
    68      switch r := v.(type) {
    69          case KRegister      : return byte(r)
    70          case XMMRegister    : return 0
    71          case YMMRegister    : return 0
    72          case ZMMRegister    : return 0
    73          case RegisterMask   : return byte(r.K)
    74          case MaskedRegister : return byte(r.Mask.K)
    75          case *MemoryOperand : return toKcodeMem(r)
    76          default             : panic("v is not a maskable operand")
    77      }
    78  }
    79  
    80  func zcode(v interface{}) byte {
    81      switch r := v.(type) {
    82          case KRegister      : return 0
    83          case XMMRegister    : return 0
    84          case YMMRegister    : return 0
    85          case ZMMRegister    : return 0
    86          case RegisterMask   : return toZcodeRegM(r)
    87          case MaskedRegister : return toZcodeRegM(r.Mask)
    88          case *MemoryOperand : return toZcodeMem(r)
    89          default             : panic("v is not a maskable operand")
    90      }
    91  }
    92  
    93  func lcode(v interface{}) byte {
    94      switch r := v.(type) {
    95          case Register8      : return byte(r & 0x07)
    96          case Register16     : return byte(r & 0x07)
    97          case Register32     : return byte(r & 0x07)
    98          case Register64     : return byte(r & 0x07)
    99          case KRegister      : return byte(r & 0x07)
   100          case MMRegister     : return byte(r & 0x07)
   101          case XMMRegister    : return byte(r & 0x07)
   102          case YMMRegister    : return byte(r & 0x07)
   103          case ZMMRegister    : return byte(r & 0x07)
   104          case MaskedRegister : return lcode(r.Reg)
   105          default             : panic("v is not a register")
   106      }
   107  }
   108  
   109  func hcode(v interface{}) byte {
   110      switch r := v.(type) {
   111          case Register8      : return byte(r >> 3) & 1
   112          case Register16     : return byte(r >> 3) & 1
   113          case Register32     : return byte(r >> 3) & 1
   114          case Register64     : return byte(r >> 3) & 1
   115          case KRegister      : return byte(r >> 3) & 1
   116          case MMRegister     : return byte(r >> 3) & 1
   117          case XMMRegister    : return byte(r >> 3) & 1
   118          case YMMRegister    : return byte(r >> 3) & 1
   119          case ZMMRegister    : return byte(r >> 3) & 1
   120          case MaskedRegister : return hcode(r.Reg)
   121          default             : panic("v is not a register")
   122      }
   123  }
   124  
   125  func ecode(v interface{}) byte {
   126      switch r := v.(type) {
   127          case Register8      : return byte(r >> 4) & 1
   128          case Register16     : return byte(r >> 4) & 1
   129          case Register32     : return byte(r >> 4) & 1
   130          case Register64     : return byte(r >> 4) & 1
   131          case KRegister      : return byte(r >> 4) & 1
   132          case MMRegister     : return byte(r >> 4) & 1
   133          case XMMRegister    : return byte(r >> 4) & 1
   134          case YMMRegister    : return byte(r >> 4) & 1
   135          case ZMMRegister    : return byte(r >> 4) & 1
   136          case MaskedRegister : return ecode(r.Reg)
   137          default             : panic("v is not a register")
   138      }
   139  }
   140  
   141  func hlcode(v interface{}) byte {
   142      switch r := v.(type) {
   143          case Register8      : return toHLcodeReg8(r)
   144          case Register16     : return byte(r & 0x0f)
   145          case Register32     : return byte(r & 0x0f)
   146          case Register64     : return byte(r & 0x0f)
   147          case KRegister      : return byte(r & 0x0f)
   148          case MMRegister     : return byte(r & 0x0f)
   149          case XMMRegister    : return byte(r & 0x0f)
   150          case YMMRegister    : return byte(r & 0x0f)
   151          case ZMMRegister    : return byte(r & 0x0f)
   152          case MaskedRegister : return hlcode(r.Reg)
   153          default             : panic("v is not a register")
   154      }
   155  }
   156  
   157  func ehcode(v interface{}) byte {
   158      switch r := v.(type) {
   159          case Register8      : return byte(r >> 3) & 0x03
   160          case Register16     : return byte(r >> 3) & 0x03
   161          case Register32     : return byte(r >> 3) & 0x03
   162          case Register64     : return byte(r >> 3) & 0x03
   163          case KRegister      : return byte(r >> 3) & 0x03
   164          case MMRegister     : return byte(r >> 3) & 0x03
   165          case XMMRegister    : return byte(r >> 3) & 0x03
   166          case YMMRegister    : return byte(r >> 3) & 0x03
   167          case ZMMRegister    : return byte(r >> 3) & 0x03
   168          case MaskedRegister : return ehcode(r.Reg)
   169          default             : panic("v is not a register")
   170      }
   171  }
   172  
   173  func toImmAny(v interface{}) int64 {
   174      if x, ok := asInt64(v); ok {
   175          return x
   176      } else {
   177          panic("value is not an integer")
   178      }
   179  }
   180  
   181  func toHcodeOpt(v interface{}) byte {
   182      if v == nil {
   183          return 0
   184      } else {
   185          return hcode(v)
   186      }
   187  }
   188  
   189  func toEcodeVMM(v interface{}, x byte) byte {
   190      switch r := v.(type) {
   191          case XMMRegister : return ecode(r)
   192          case YMMRegister : return ecode(r)
   193          case ZMMRegister : return ecode(r)
   194          default          : return x
   195      }
   196  }
   197  
   198  func toKcodeMem(v *MemoryOperand) byte {
   199      if !v.Masked {
   200          return 0
   201      } else {
   202          return byte(v.Mask.K)
   203      }
   204  }
   205  
   206  func toZcodeMem(v *MemoryOperand) byte {
   207      if !v.Masked || v.Mask.Z {
   208          return 0
   209      } else {
   210          return 1
   211      }
   212  }
   213  
   214  func toZcodeRegM(v RegisterMask) byte {
   215      if v.Z {
   216          return 1
   217      } else {
   218          return 0
   219      }
   220  }
   221  
   222  func toHLcodeReg8(v Register8) byte {
   223      switch v {
   224          case AH: fallthrough
   225          case BH: fallthrough
   226          case CH: fallthrough
   227          case DH: panic("ah/bh/ch/dh registers never use 4-bit encoding")
   228          default: return byte(v & 0x0f)
   229      }
   230  }
   231  
   232  /** Instruction Encoding Helpers **/
   233  
   234  const (
   235      _N_inst = 16
   236  )
   237  
   238  const (
   239      _F_rel1 = 1 << iota
   240      _F_rel4
   241  )
   242  
   243  type _Encoding struct {
   244      len     int
   245      flags   int
   246      bytes   [_N_inst]byte
   247      encoder func(m *_Encoding, v []interface{})
   248  }
   249  
   250  // buf ensures len + n <= len(bytes).
   251  func (self *_Encoding) buf(n int) []byte {
   252      if i := self.len; i + n > _N_inst {
   253          panic("instruction too long")
   254      } else {
   255          return self.bytes[i:]
   256      }
   257  }
   258  
   259  // emit encodes a single byte.
   260  func (self *_Encoding) emit(v byte) {
   261      self.buf(1)[0] = v
   262      self.len++
   263  }
   264  
   265  // imm1 encodes a single byte immediate value.
   266  func (self *_Encoding) imm1(v int64) {
   267      self.emit(byte(v))
   268  }
   269  
   270  // imm2 encodes a two-byte immediate value in little-endian.
   271  func (self *_Encoding) imm2(v int64) {
   272      binary.LittleEndian.PutUint16(self.buf(2), uint16(v))
   273      self.len += 2
   274  }
   275  
   276  // imm4 encodes a 4-byte immediate value in little-endian.
   277  func (self *_Encoding) imm4(v int64) {
   278      binary.LittleEndian.PutUint32(self.buf(4), uint32(v))
   279      self.len += 4
   280  }
   281  
   282  // imm8 encodes an 8-byte immediate value in little-endian.
   283  func (self *_Encoding) imm8(v int64) {
   284      binary.LittleEndian.PutUint64(self.buf(8), uint64(v))
   285      self.len += 8
   286  }
   287  
   288  // vex2 encodes a 2-byte or 3-byte VEX prefix.
   289  //
   290  //                          2-byte VEX prefix:
   291  // Requires: VEX.W = 0, VEX.mmmmm = 0b00001 and VEX.B = VEX.X = 0
   292  //         +----------------+
   293  // Byte 0: | Bits 0-7: 0xc5 |
   294  //         +----------------+
   295  //
   296  //         +-----------+----------------+----------+--------------+
   297  // Byte 1: | Bit 7: ~R | Bits 3-6 ~vvvv | Bit 2: L | Bits 0-1: pp |
   298  //         +-----------+----------------+----------+--------------+
   299  //
   300  //                          3-byte VEX prefix:
   301  //         +----------------+
   302  // Byte 0: | Bits 0-7: 0xc4 |
   303  //         +----------------+
   304  //
   305  //         +-----------+-----------+-----------+-------------------+
   306  // Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: 0b00001 |
   307  //         +-----------+-----------+-----------+-------------------+
   308  //
   309  //         +----------+-----------------+----------+--------------+
   310  // Byte 2: | Bit 7: 0 | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
   311  //         +----------+-----------------+----------+--------------+
   312  //
   313  func (self *_Encoding) vex2(lpp byte, r byte, rm interface{}, vvvv byte) {
   314      var b byte
   315      var x byte
   316  
   317      /* VEX.R must be a single-bit mask */
   318      if r > 1 {
   319          panic("VEX.R must be a 1-bit mask")
   320      }
   321  
   322      /* VEX.Lpp must be a 3-bit mask */
   323      if lpp &^ 0b111 != 0 {
   324          panic("VEX.Lpp must be a 3-bit mask")
   325      }
   326  
   327      /* VEX.vvvv must be a 4-bit mask */
   328      if vvvv &^ 0b1111 != 0 {
   329          panic("VEX.vvvv must be a 4-bit mask")
   330      }
   331  
   332      /* encode the RM bits if any */
   333      if rm != nil {
   334          switch v := rm.(type) {
   335              case *Label         : break
   336              case Register       : b = hcode(v)
   337              case MemoryAddress  : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
   338              case RelativeOffset : break
   339              default             : panic("rm is expected to be a register or a memory address")
   340          }
   341      }
   342  
   343      /* if VEX.B and VEX.X are zeroes, 2-byte VEX prefix can be used */
   344      if x == 0 && b == 0 {
   345          self.emit(0xc5)
   346          self.emit(0xf8 ^ (r << 7) ^ (vvvv << 3) ^ lpp)
   347      } else {
   348          self.emit(0xc4)
   349          self.emit(0xe1 ^ (r << 7) ^ (x << 6) ^ (b << 5))
   350          self.emit(0x78 ^ (vvvv << 3) ^ lpp)
   351      }
   352  }
   353  
   354  // vex3 encodes a 3-byte VEX or XOP prefix.
   355  //
   356  //                         3-byte VEX/XOP prefix
   357  //         +-----------------------------------+
   358  // Byte 0: | Bits 0-7: 0xc4 (VEX) / 0x8f (XOP) |
   359  //         +-----------------------------------+
   360  //
   361  //         +-----------+-----------+-----------+-----------------+
   362  // Byte 1: | Bit 7: ~R | Bit 6: ~X | Bit 5: ~B | Bits 0-4: mmmmm |
   363  //         +-----------+-----------+-----------+-----------------+
   364  //
   365  //         +----------+-----------------+----------+--------------+
   366  // Byte 2: | Bit 7: W | Bits 3-6: ~vvvv | Bit 2: L | Bits 0-1: pp |
   367  //         +----------+-----------------+----------+--------------+
   368  //
   369  func (self *_Encoding) vex3(esc byte, mmmmm byte, wlpp byte, r byte, rm interface{}, vvvv byte) {
   370      var b byte
   371      var x byte
   372  
   373      /* VEX.R must be a single-bit mask */
   374      if r > 1 {
   375          panic("VEX.R must be a 1-bit mask")
   376      }
   377  
   378      /* VEX.vvvv must be a 4-bit mask */
   379      if vvvv &^ 0b1111 != 0 {
   380          panic("VEX.vvvv must be a 4-bit mask")
   381      }
   382  
   383      /* escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix */
   384      if esc != 0xc4 && esc != 0x8f {
   385          panic("escape must be a 3-byte VEX (0xc4) or XOP (0x8f) prefix")
   386      }
   387  
   388      /* VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7 */
   389      if wlpp &^ 0b10000111 != 0 {
   390          panic("VEX.W____Lpp is expected to have no bits set except 0, 1, 2 and 7")
   391      }
   392  
   393      /* VEX.m-mmmm is expected to be a 5-bit mask */
   394      if mmmmm &^ 0b11111 != 0 {
   395          panic("VEX.m-mmmm is expected to be a 5-bit mask")
   396      }
   397  
   398      /* encode the RM bits */
   399      switch v := rm.(type) {
   400          case *Label         : break
   401          case MemoryAddress  : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
   402          case RelativeOffset : break
   403          default             : panic("rm is expected to be a register or a memory address")
   404      }
   405  
   406      /* encode the 3-byte VEX or XOP prefix */
   407      self.emit(esc)
   408      self.emit(0xe0 ^ (r << 7) ^ (x << 6) ^ (b << 5) ^ mmmmm)
   409      self.emit(0x78 ^ (vvvv << 3) ^ wlpp)
   410  }
   411  
   412  // evex encodes a 4-byte EVEX prefix.
   413  func (self *_Encoding) evex(mm byte, w1pp byte, ll byte, rr byte, rm interface{}, vvvvv byte, aaa byte, zz byte, bb byte) {
   414      var b byte
   415      var x byte
   416  
   417      /* EVEX.b must be a single-bit mask */
   418      if bb > 1 {
   419          panic("EVEX.b must be a 1-bit mask")
   420      }
   421  
   422      /* EVEX.z must be a single-bit mask */
   423      if zz > 1 {
   424          panic("EVEX.z must be a 1-bit mask")
   425      }
   426  
   427      /* EVEX.mm must be a 2-bit mask */
   428      if mm &^ 0b11 != 0 {
   429          panic("EVEX.mm must be a 2-bit mask")
   430      }
   431  
   432      /* EVEX.L'L must be a 2-bit mask */
   433      if ll &^ 0b11 != 0 {
   434          panic("EVEX.L'L must be a 2-bit mask")
   435      }
   436  
   437      /* EVEX.R'R must be a 2-bit mask */
   438      if rr &^ 0b11 != 0 {
   439          panic("EVEX.R'R must be a 2-bit mask")
   440      }
   441  
   442      /* EVEX.aaa must be a 3-bit mask */
   443      if aaa &^ 0b111 != 0 {
   444          panic("EVEX.aaa must be a 3-bit mask")
   445      }
   446  
   447      /* EVEX.v'vvvv must be a 5-bit mask */
   448      if vvvvv &^ 0b11111 != 0 {
   449          panic("EVEX.v'vvvv must be a 5-bit mask")
   450      }
   451  
   452      /* EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7 */
   453      if w1pp &^ 0b10000011 != 0b100 {
   454          panic("EVEX.W____1pp is expected to have no bits set except 0, 1, 2, and 7")
   455      }
   456  
   457      /* extract bits from EVEX.R'R and EVEX.v'vvvv */
   458      r1, r0 := rr >> 1, rr & 1
   459      v1, v0 := vvvvv >> 4, vvvvv & 0b1111
   460  
   461      /* encode the RM bits if any */
   462      if rm != nil {
   463          switch m := rm.(type) {
   464              case *Label         : break
   465              case Register       : b, x = hcode(m), ecode(m)
   466              case MemoryAddress  : b, x, v1 = toHcodeOpt(m.Base), toHcodeOpt(m.Index), toEcodeVMM(m.Index, v1)
   467              case RelativeOffset : break
   468              default             : panic("rm is expected to be a register or a memory address")
   469          }
   470      }
   471  
   472      /* EVEX prefix bytes */
   473      p0 := (r0 << 7) | (x << 6) | (b << 5) | (r1 << 4) | mm
   474      p1 := (v0 << 3) | w1pp
   475      p2 := (zz << 7) | (ll << 5) | (b << 4) | (v1 << 3) | aaa
   476  
   477      /* p0: invert RXBR' (bits 4-7)
   478       * p1: invert vvvv  (bits 3-6)
   479       * p2: invert V'    (bit  3) */
   480      self.emit(0x62)
   481      self.emit(p0 ^ 0xf0)
   482      self.emit(p1 ^ 0x78)
   483      self.emit(p2 ^ 0x08)
   484  }
   485  
   486  // rexm encodes a mandatory REX prefix.
   487  func (self *_Encoding) rexm(w byte, r byte, rm interface{}) {
   488      var b byte
   489      var x byte
   490  
   491      /* REX.R must be 0 or 1 */
   492      if r != 0 && r != 1 {
   493          panic("REX.R must be 0 or 1")
   494      }
   495  
   496      /* REX.W must be 0 or 1 */
   497      if w != 0 && w != 1 {
   498          panic("REX.W must be 0 or 1")
   499      }
   500  
   501      /* encode the RM bits */
   502      switch v := rm.(type) {
   503          case *Label         : break
   504          case MemoryAddress  : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
   505          case RelativeOffset : break
   506          default             : panic("rm is expected to be a register or a memory address")
   507      }
   508  
   509      /* encode the REX prefix */
   510      self.emit(0x40 | (w << 3) | (r << 2) | (x << 1) | b)
   511  }
   512  
   513  // rexo encodes an optional REX prefix.
   514  func (self *_Encoding) rexo(r byte, rm interface{}, force bool) {
   515      var b byte
   516      var x byte
   517  
   518      /* REX.R must be 0 or 1 */
   519      if r != 0 && r != 1 {
   520          panic("REX.R must be 0 or 1")
   521      }
   522  
   523      /* encode the RM bits */
   524      switch v := rm.(type) {
   525          case *Label         : break
   526          case Register       : b = hcode(v)
   527          case MemoryAddress  : b, x = toHcodeOpt(v.Base), toHcodeOpt(v.Index)
   528          case RelativeOffset : break
   529          default             : panic("rm is expected to be a register or a memory address")
   530      }
   531  
   532      /* if REX.R, REX.X, and REX.B are all zeroes, REX prefix can be omitted */
   533      if force || r != 0 || x != 0 || b != 0 {
   534          self.emit(0x40 | (r << 2) | (x << 1) | b)
   535      }
   536  }
   537  
   538  // mrsd encodes ModR/M, SIB and Displacement.
   539  //
   540  //                    ModR/M byte
   541  // +----------------+---------------+---------------+
   542  // | Bits 6-7: Mode | Bits 3-5: Reg | Bits 0-2: R/M |
   543  // +----------------+---------------+---------------+
   544  //
   545  //                         SIB byte
   546  // +-----------------+-----------------+----------------+
   547  // | Bits 6-7: Scale | Bits 3-5: Index | Bits 0-2: Base |
   548  // +-----------------+-----------------+----------------+
   549  //
   550  func (self *_Encoding) mrsd(reg byte, rm interface{}, disp8v int32) {
   551      var ok bool
   552      var mm MemoryAddress
   553      var ro RelativeOffset
   554  
   555      /* ModRM encodes the lower 3-bit of the register */
   556      if reg > 7 {
   557          panic("invalid register bits")
   558      }
   559  
   560      /* check the displacement scale */
   561      switch disp8v {
   562          case  1: break
   563          case  2: break
   564          case  4: break
   565          case  8: break
   566          case 16: break
   567          case 32: break
   568          case 64: break
   569          default: panic("invalid displacement size")
   570      }
   571  
   572      /* special case: unresolved labels, assuming a zero offset */
   573      if _, ok = rm.(*Label); ok {
   574          self.emit(0x05 | (reg << 3))
   575          self.imm4(0)
   576          return
   577      }
   578  
   579      /* special case: RIP-relative offset
   580       * ModRM.Mode == 0 and ModeRM.R/M == 5 indicates (rip + disp32) addressing */
   581      if ro, ok = rm.(RelativeOffset); ok {
   582          self.emit(0x05 | (reg << 3))
   583          self.imm4(int64(ro))
   584          return
   585      }
   586  
   587      /* must be a generic memory address */
   588      if mm, ok = rm.(MemoryAddress); !ok {
   589          panic("rm must be a memory address")
   590      }
   591  
   592      /* absolute addressing, encoded as disp(%rbp,%rsp,1) */
   593      if mm.Base == nil && mm.Index == nil {
   594          self.emit(0x04 | (reg << 3))
   595          self.emit(0x25)
   596          self.imm4(int64(mm.Displacement))
   597          return
   598      }
   599  
   600      /* no SIB byte */
   601      if mm.Index == nil && lcode(mm.Base) != 0b100 {
   602          cc := lcode(mm.Base)
   603          dv := mm.Displacement
   604  
   605          /* ModRM.Mode == 0 (no displacement) */
   606          if dv == 0 && mm.Base != RBP && mm.Base != R13 {
   607              if cc == 0b101 {
   608                  panic("rbp/r13 is not encodable as a base register (interpreted as disp32 address)")
   609              } else {
   610                  self.emit((reg << 3) | cc)
   611                  return
   612              }
   613          }
   614  
   615          /* ModRM.Mode == 1 (8-bit displacement) */
   616          if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv % disp8v == 0 {
   617              self.emit(0x40 | (reg << 3) | cc)
   618              self.imm1(int64(dq))
   619              return
   620          }
   621  
   622          /* ModRM.Mode == 2 (32-bit displacement) */
   623          self.emit(0x80 | (reg << 3) | cc)
   624          self.imm4(int64(mm.Displacement))
   625          return
   626      }
   627  
   628      /* all encodings below use ModRM.R/M = 4 (0b100) to indicate the presence of SIB */
   629      if mm.Index == RSP {
   630          panic("rsp is not encodable as an index register (interpreted as no index)")
   631      }
   632  
   633      /* index = 4 (0b100) denotes no-index encoding */
   634      var scale byte
   635      var index byte = 0x04
   636  
   637      /* encode the scale byte */
   638      if mm.Scale != 0 {
   639          switch mm.Scale {
   640              case 1  : scale = 0
   641              case 2  : scale = 1
   642              case 4  : scale = 2
   643              case 8  : scale = 3
   644              default : panic("invalid scale value")
   645          }
   646      }
   647  
   648      /* encode the index byte */
   649      if mm.Index != nil {
   650          index = lcode(mm.Index)
   651      }
   652  
   653      /* SIB.Base = 5 (0b101) and ModRM.Mode = 0 indicates no-base encoding with disp32 */
   654      if mm.Base == nil {
   655          self.emit((reg << 3) | 0b100)
   656          self.emit((scale << 6) | (index << 3) | 0b101)
   657          self.imm4(int64(mm.Displacement))
   658          return
   659      }
   660  
   661      /* base L-code & displacement value */
   662      cc := lcode(mm.Base)
   663      dv := mm.Displacement
   664  
   665      /* ModRM.Mode == 0 (no displacement) */
   666      if dv == 0 && cc != 0b101 {
   667          self.emit((reg << 3) | 0b100)
   668          self.emit((scale << 6) | (index << 3) | cc)
   669          return
   670      }
   671  
   672      /* ModRM.Mode == 1 (8-bit displacement) */
   673      if dq := dv / disp8v; dq >= math.MinInt8 && dq <= math.MaxInt8 && dv % disp8v == 0 {
   674          self.emit(0x44 | (reg << 3))
   675          self.emit((scale << 6) | (index << 3) | cc)
   676          self.imm1(int64(dq))
   677          return
   678      }
   679  
   680      /* ModRM.Mode == 2 (32-bit displacement) */
   681      self.emit(0x84 | (reg << 3))
   682      self.emit((scale << 6) | (index << 3) | cc)
   683      self.imm4(int64(mm.Displacement))
   684  }
   685  
   686  // encode invokes the encoder to encode this instruction.
   687  func (self *_Encoding) encode(v []interface{}) int {
   688      self.len = 0
   689      self.encoder(self, v)
   690      return self.len
   691  }