123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958 |
- // Copyright 2014 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package x86asm
- import (
- "fmt"
- "strings"
- )
- // GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
- // This general form is often called “AT&T syntax” as a reference to AT&T System V Unix.
- func GNUSyntax(inst Inst, pc uint64, symname SymLookup) string {
- // Rewrite instruction to mimic GNU peculiarities.
- // Note that inst has been passed by value and contains
- // no pointers, so any changes we make here are local
- // and will not propagate back out to the caller.
- if symname == nil {
- symname = func(uint64) (string, uint64) { return "", 0 }
- }
- // Adjust opcode [sic].
- switch inst.Op {
- case FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, FSUBRP:
- // DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least
- // if you believe the Intel manual is correct (the encoding is irregular as given;
- // libopcodes uses the more regular expected encoding).
- // TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers?
- // NOTE: iant thinks this is deliberate, but we can't find the history.
- _, reg1 := inst.Args[0].(Reg)
- _, reg2 := inst.Args[1].(Reg)
- if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) {
- switch inst.Op {
- case FDIV:
- inst.Op = FDIVR
- case FDIVR:
- inst.Op = FDIV
- case FSUB:
- inst.Op = FSUBR
- case FSUBR:
- inst.Op = FSUB
- case FDIVP:
- inst.Op = FDIVRP
- case FDIVRP:
- inst.Op = FDIVP
- case FSUBP:
- inst.Op = FSUBRP
- case FSUBRP:
- inst.Op = FSUBP
- }
- }
- case MOVNTSD:
- // MOVNTSD is F2 0F 2B /r.
- // MOVNTSS is F3 0F 2B /r (supposedly; not in manuals).
- // Usually inner prefixes win for display,
- // so that F3 F2 0F 2B 11 is REP MOVNTSD
- // and F2 F3 0F 2B 11 is REPN MOVNTSS.
- // Libopcodes always prefers MOVNTSS regardless of prefix order.
- if countPrefix(&inst, 0xF3) > 0 {
- found := false
- for i := len(inst.Prefix) - 1; i >= 0; i-- {
- switch inst.Prefix[i] & 0xFF {
- case 0xF3:
- if !found {
- found = true
- inst.Prefix[i] |= PrefixImplicit
- }
- case 0xF2:
- inst.Prefix[i] &^= PrefixImplicit
- }
- }
- inst.Op = MOVNTSS
- }
- }
- // Add implicit arguments.
- switch inst.Op {
- case MONITOR:
- inst.Args[0] = EDX
- inst.Args[1] = ECX
- inst.Args[2] = EAX
- if inst.AddrSize == 16 {
- inst.Args[2] = AX
- }
- case MWAIT:
- if inst.Mode == 64 {
- inst.Args[0] = RCX
- inst.Args[1] = RAX
- } else {
- inst.Args[0] = ECX
- inst.Args[1] = EAX
- }
- }
- // Adjust which prefixes will be displayed.
- // The rule is to display all the prefixes not implied by
- // the usual instruction display, that is, all the prefixes
- // except the ones with PrefixImplicit set.
- // However, of course, there are exceptions to the rule.
- switch inst.Op {
- case CRC32:
- // CRC32 has a mandatory F2 prefix.
- // If there are multiple F2s and no F3s, the extra F2s do not print.
- // (And Decode has already marked them implicit.)
- // However, if there is an F3 anywhere, then the extra F2s do print.
- // If there are multiple F2 prefixes *and* an (ignored) F3,
- // then libopcodes prints the extra F2s as REPNs.
- if countPrefix(&inst, 0xF2) > 1 {
- unmarkImplicit(&inst, 0xF2)
- markLastImplicit(&inst, 0xF2)
- }
- // An unused data size override should probably be shown,
- // to distinguish DATA16 CRC32B from plain CRC32B,
- // but libopcodes always treats the final override as implicit
- // and the others as explicit.
- unmarkImplicit(&inst, PrefixDataSize)
- markLastImplicit(&inst, PrefixDataSize)
- case CVTSI2SD, CVTSI2SS:
- if !isMem(inst.Args[1]) {
- markLastImplicit(&inst, PrefixDataSize)
- }
- case CVTSD2SI, CVTSS2SI, CVTTSD2SI, CVTTSS2SI,
- ENTER, FLDENV, FNSAVE, FNSTENV, FRSTOR, LGDT, LIDT, LRET,
- POP, PUSH, RET, SGDT, SIDT, SYSRET, XBEGIN:
- markLastImplicit(&inst, PrefixDataSize)
- case LOOP, LOOPE, LOOPNE, MONITOR:
- markLastImplicit(&inst, PrefixAddrSize)
- case MOV:
- // The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg
- // cannot be distinguished when src or dst refers to memory, because
- // Sreg is always a 16-bit value, even when we're doing a 32-bit
- // instruction. Because the instruction tables distinguished these two,
- // any operand size prefix has been marked as used (to decide which
- // branch to take). Unmark it, so that it will show up in disassembly,
- // so that the reader can tell the size of memory operand.
- // up with the same arguments
- dst, _ := inst.Args[0].(Reg)
- src, _ := inst.Args[1].(Reg)
- if ES <= src && src <= GS && isMem(inst.Args[0]) || ES <= dst && dst <= GS && isMem(inst.Args[1]) {
- unmarkImplicit(&inst, PrefixDataSize)
- }
- case MOVDQU:
- if countPrefix(&inst, 0xF3) > 1 {
- unmarkImplicit(&inst, 0xF3)
- markLastImplicit(&inst, 0xF3)
- }
- case MOVQ2DQ:
- markLastImplicit(&inst, PrefixDataSize)
- case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B:
- if isMem(inst.Args[0]) {
- unmarkImplicit(&inst, PrefixDataSize)
- }
- case SYSEXIT:
- unmarkImplicit(&inst, PrefixDataSize)
- }
- if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
- if countPrefix(&inst, PrefixCS) > 0 && countPrefix(&inst, PrefixDS) > 0 {
- for i, p := range inst.Prefix {
- switch p & 0xFFF {
- case PrefixPN, PrefixPT:
- inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix
- }
- }
- }
- }
- // XACQUIRE/XRELEASE adjustment.
- if inst.Op == MOV {
- // MOV into memory is a candidate for turning REP into XRELEASE.
- // However, if the REP is followed by a REPN, that REPN blocks the
- // conversion.
- haveREPN := false
- for i := len(inst.Prefix) - 1; i >= 0; i-- {
- switch inst.Prefix[i] &^ PrefixIgnored {
- case PrefixREPN:
- haveREPN = true
- case PrefixXRELEASE:
- if haveREPN {
- inst.Prefix[i] = PrefixREP
- }
- }
- }
- }
- // We only format the final F2/F3 as XRELEASE/XACQUIRE.
- haveXA := false
- haveXR := false
- for i := len(inst.Prefix) - 1; i >= 0; i-- {
- switch inst.Prefix[i] &^ PrefixIgnored {
- case PrefixXRELEASE:
- if !haveXR {
- haveXR = true
- } else {
- inst.Prefix[i] = PrefixREP
- }
- case PrefixXACQUIRE:
- if !haveXA {
- haveXA = true
- } else {
- inst.Prefix[i] = PrefixREPN
- }
- }
- }
- // Determine opcode.
- op := strings.ToLower(inst.Op.String())
- if alt := gnuOp[inst.Op]; alt != "" {
- op = alt
- }
- // Determine opcode suffix.
- // Libopcodes omits the suffix if the width of the operation
- // can be inferred from a register arguments. For example,
- // add $1, %ebx has no suffix because you can tell from the
- // 32-bit register destination that it is a 32-bit add,
- // but in addl $1, (%ebx), the destination is memory, so the
- // size is not evident without the l suffix.
- needSuffix := true
- SuffixLoop:
- for i, a := range inst.Args {
- if a == nil {
- break
- }
- switch a := a.(type) {
- case Reg:
- switch inst.Op {
- case MOVSX, MOVZX:
- continue
- case SHL, SHR, RCL, RCR, ROL, ROR, SAR:
- if i == 1 {
- // shift count does not tell us operand size
- continue
- }
- case CRC32:
- // The source argument does tell us operand size,
- // but libopcodes still always puts a suffix on crc32.
- continue
- case PUSH, POP:
- // Even though segment registers are 16-bit, push and pop
- // can save/restore them from 32-bit slots, so they
- // do not imply operand size.
- if ES <= a && a <= GS {
- continue
- }
- case CVTSI2SD, CVTSI2SS:
- // The integer register argument takes priority.
- if X0 <= a && a <= X15 {
- continue
- }
- }
- if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 {
- needSuffix = false
- break SuffixLoop
- }
- }
- }
- if needSuffix {
- switch inst.Op {
- case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ,
- SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS,
- SLDT, SMSW, STMXCSR, STR, VERR, VERW:
- // For various reasons, libopcodes emits no suffix for these instructions.
- case CRC32:
- op += byteSizeSuffix(argBytes(&inst, inst.Args[1]))
- case LGDT, LIDT, SGDT, SIDT:
- op += byteSizeSuffix(inst.DataSize / 8)
- case MOVZX, MOVSX:
- // Integer size conversions get two suffixes.
- op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0]))
- case LOOP, LOOPE, LOOPNE:
- // Add w suffix to indicate use of CX register instead of ECX.
- if inst.AddrSize == 16 {
- op += "w"
- }
- case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN:
- // Add w suffix to indicate use of 16-bit target.
- // Exclude JMP rel8.
- if inst.Opcode>>24 == 0xEB {
- break
- }
- if inst.DataSize == 16 && inst.Mode != 16 {
- markLastImplicit(&inst, PrefixDataSize)
- op += "w"
- } else if inst.Mode == 64 {
- op += "q"
- }
- case FRSTOR, FNSAVE, FNSTENV, FLDENV:
- // Add s suffix to indicate shortened FPU state (I guess).
- if inst.DataSize == 16 {
- op += "s"
- }
- case PUSH, POP:
- if markLastImplicit(&inst, PrefixDataSize) {
- op += byteSizeSuffix(inst.DataSize / 8)
- } else if inst.Mode == 64 {
- op += "q"
- } else {
- op += byteSizeSuffix(inst.MemBytes)
- }
- default:
- if isFloat(inst.Op) {
- // I can't explain any of this, but it's what libopcodes does.
- switch inst.MemBytes {
- default:
- if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) {
- op += "t"
- }
- case 4:
- if isFloatInt(inst.Op) {
- op += "l"
- } else {
- op += "s"
- }
- case 8:
- if isFloatInt(inst.Op) {
- op += "ll"
- } else {
- op += "l"
- }
- }
- break
- }
- op += byteSizeSuffix(inst.MemBytes)
- }
- }
- // Adjust special case opcodes.
- switch inst.Op {
- case 0:
- if inst.Prefix[0] != 0 {
- return strings.ToLower(inst.Prefix[0].String())
- }
- case INT:
- if inst.Opcode>>24 == 0xCC {
- inst.Args[0] = nil
- op = "int3"
- }
- case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
- imm, ok := inst.Args[2].(Imm)
- if ok && 0 <= imm && imm < 8 {
- inst.Args[2] = nil
- op = cmppsOps[imm] + op[3:]
- }
- case PCLMULQDQ:
- imm, ok := inst.Args[2].(Imm)
- if ok && imm&^0x11 == 0 {
- inst.Args[2] = nil
- op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
- }
- case XLATB:
- if markLastImplicit(&inst, PrefixAddrSize) {
- op = "xlat" // not xlatb
- }
- }
- // Build list of argument strings.
- var (
- usedPrefixes bool // segment prefixes consumed by Mem formatting
- args []string // formatted arguments
- )
- for i, a := range inst.Args {
- if a == nil {
- break
- }
- switch inst.Op {
- case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
- if i == 0 {
- usedPrefixes = true // disable use of prefixes for first argument
- } else {
- usedPrefixes = false
- }
- }
- if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
- continue
- }
- args = append(args, gnuArg(&inst, pc, symname, a, &usedPrefixes))
- }
- // The default is to print the arguments in reverse Intel order.
- // A few instructions inhibit this behavior.
- switch inst.Op {
- case BOUND, LCALL, ENTER, LJMP:
- // no reverse
- default:
- // reverse args
- for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
- args[i], args[j] = args[j], args[i]
- }
- }
- // Build prefix string.
- // Must be after argument formatting, which can turn off segment prefixes.
- var (
- prefix = "" // output string
- numAddr = 0
- numData = 0
- implicitData = false
- )
- for _, p := range inst.Prefix {
- if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
- implicitData = true
- }
- }
- for _, p := range inst.Prefix {
- if p == 0 || p.IsVEX() {
- break
- }
- if p&PrefixImplicit != 0 {
- continue
- }
- switch p &^ (PrefixIgnored | PrefixInvalid) {
- default:
- if p.IsREX() {
- if p&0xFF == PrefixREX {
- prefix += "rex "
- } else {
- prefix += "rex." + p.String()[4:] + " "
- }
- break
- }
- prefix += strings.ToLower(p.String()) + " "
- case PrefixPN:
- op += ",pn"
- continue
- case PrefixPT:
- op += ",pt"
- continue
- case PrefixAddrSize, PrefixAddr16, PrefixAddr32:
- // For unknown reasons, if the addr16 prefix is repeated,
- // libopcodes displays all but the last as addr32, even though
- // the addressing form used in a memory reference is clearly
- // still 16-bit.
- n := 32
- if inst.Mode == 32 {
- n = 16
- }
- numAddr++
- if countPrefix(&inst, PrefixAddrSize) > numAddr {
- n = inst.Mode
- }
- prefix += fmt.Sprintf("addr%d ", n)
- continue
- case PrefixData16, PrefixData32:
- if implicitData && countPrefix(&inst, PrefixDataSize) > 1 {
- // Similar to the addr32 logic above, but it only kicks in
- // when something used the data size prefix (one is implicit).
- n := 16
- if inst.Mode == 16 {
- n = 32
- }
- numData++
- if countPrefix(&inst, PrefixDataSize) > numData {
- if inst.Mode == 16 {
- n = 16
- } else {
- n = 32
- }
- }
- prefix += fmt.Sprintf("data%d ", n)
- continue
- }
- prefix += strings.ToLower(p.String()) + " "
- }
- }
- // Finally! Put it all together.
- text := prefix + op
- if args != nil {
- text += " "
- // Indirect call/jmp gets a star to distinguish from direct jump address.
- if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) {
- text += "*"
- }
- text += strings.Join(args, ",")
- }
- return text
- }
- // gnuArg returns the GNU syntax for the argument x from the instruction inst.
- // If *usedPrefixes is false and x is a Mem, then the formatting
- // includes any segment prefixes and sets *usedPrefixes to true.
- func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool) string {
- if x == nil {
- return "<nil>"
- }
- switch x := x.(type) {
- case Reg:
- switch inst.Op {
- case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
- if inst.DataSize == 16 && EAX <= x && x <= R15L {
- x -= EAX - AX
- }
- case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD:
- // DX is the port, but libopcodes prints it as if it were a memory reference.
- if x == DX {
- return "(%dx)"
- }
- case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
- return strings.Replace(gccRegName[x], "xmm", "ymm", -1)
- }
- return gccRegName[x]
- case Mem:
- if s, disp := memArgToSymbol(x, pc, inst.Len, symname); s != "" {
- suffix := ""
- if disp != 0 {
- suffix = fmt.Sprintf("%+d", disp)
- }
- return fmt.Sprintf("%s%s", s, suffix)
- }
- seg := ""
- var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
- switch x.Segment {
- case CS:
- haveCS = true
- case DS:
- haveDS = true
- case ES:
- haveES = true
- case FS:
- haveFS = true
- case GS:
- haveGS = true
- case SS:
- haveSS = true
- }
- switch inst.Op {
- case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
- // These do not accept segment prefixes, at least in the GNU rendering.
- default:
- if *usedPrefixes {
- break
- }
- for i := len(inst.Prefix) - 1; i >= 0; i-- {
- p := inst.Prefix[i] &^ PrefixIgnored
- if p == 0 {
- continue
- }
- switch p {
- case PrefixCS:
- if !haveCS {
- haveCS = true
- inst.Prefix[i] |= PrefixImplicit
- }
- case PrefixDS:
- if !haveDS {
- haveDS = true
- inst.Prefix[i] |= PrefixImplicit
- }
- case PrefixES:
- if !haveES {
- haveES = true
- inst.Prefix[i] |= PrefixImplicit
- }
- case PrefixFS:
- if !haveFS {
- haveFS = true
- inst.Prefix[i] |= PrefixImplicit
- }
- case PrefixGS:
- if !haveGS {
- haveGS = true
- inst.Prefix[i] |= PrefixImplicit
- }
- case PrefixSS:
- if !haveSS {
- haveSS = true
- inst.Prefix[i] |= PrefixImplicit
- }
- }
- }
- *usedPrefixes = true
- }
- if haveCS {
- seg += "%cs:"
- }
- if haveDS {
- seg += "%ds:"
- }
- if haveSS {
- seg += "%ss:"
- }
- if haveES {
- seg += "%es:"
- }
- if haveFS {
- seg += "%fs:"
- }
- if haveGS {
- seg += "%gs:"
- }
- disp := ""
- if x.Disp != 0 {
- disp = fmt.Sprintf("%#x", x.Disp)
- }
- if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
- if x.Base == 0 {
- return seg + disp
- }
- return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
- }
- base := gccRegName[x.Base]
- if x.Base == 0 {
- base = ""
- }
- index := gccRegName[x.Index]
- if x.Index == 0 {
- if inst.AddrSize == 64 {
- index = "%riz"
- } else {
- index = "%eiz"
- }
- }
- if AX <= x.Base && x.Base <= DI {
- // 16-bit addressing - no scale
- return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
- }
- return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
- case Rel:
- if pc == 0 {
- return fmt.Sprintf(".%+#x", int64(x))
- } else {
- addr := pc + uint64(inst.Len) + uint64(x)
- if s, base := symname(addr); s != "" && addr == base {
- return fmt.Sprintf("%s", s)
- } else {
- addr := pc + uint64(inst.Len) + uint64(x)
- return fmt.Sprintf("%#x", addr)
- }
- }
- case Imm:
- if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 { // See comment in plan9x.go.
- if s, base := symname(uint64(x)); s != "" {
- suffix := ""
- if uint64(x) != base {
- suffix = fmt.Sprintf("%+d", uint64(x)-base)
- }
- return fmt.Sprintf("$%s%s", s, suffix)
- }
- }
- if inst.Mode == 32 {
- return fmt.Sprintf("$%#x", uint32(x))
- }
- return fmt.Sprintf("$%#x", int64(x))
- }
- return x.String()
- }
- var gccRegName = [...]string{
- 0: "REG0",
- AL: "%al",
- CL: "%cl",
- BL: "%bl",
- DL: "%dl",
- AH: "%ah",
- CH: "%ch",
- BH: "%bh",
- DH: "%dh",
- SPB: "%spl",
- BPB: "%bpl",
- SIB: "%sil",
- DIB: "%dil",
- R8B: "%r8b",
- R9B: "%r9b",
- R10B: "%r10b",
- R11B: "%r11b",
- R12B: "%r12b",
- R13B: "%r13b",
- R14B: "%r14b",
- R15B: "%r15b",
- AX: "%ax",
- CX: "%cx",
- BX: "%bx",
- DX: "%dx",
- SP: "%sp",
- BP: "%bp",
- SI: "%si",
- DI: "%di",
- R8W: "%r8w",
- R9W: "%r9w",
- R10W: "%r10w",
- R11W: "%r11w",
- R12W: "%r12w",
- R13W: "%r13w",
- R14W: "%r14w",
- R15W: "%r15w",
- EAX: "%eax",
- ECX: "%ecx",
- EDX: "%edx",
- EBX: "%ebx",
- ESP: "%esp",
- EBP: "%ebp",
- ESI: "%esi",
- EDI: "%edi",
- R8L: "%r8d",
- R9L: "%r9d",
- R10L: "%r10d",
- R11L: "%r11d",
- R12L: "%r12d",
- R13L: "%r13d",
- R14L: "%r14d",
- R15L: "%r15d",
- RAX: "%rax",
- RCX: "%rcx",
- RDX: "%rdx",
- RBX: "%rbx",
- RSP: "%rsp",
- RBP: "%rbp",
- RSI: "%rsi",
- RDI: "%rdi",
- R8: "%r8",
- R9: "%r9",
- R10: "%r10",
- R11: "%r11",
- R12: "%r12",
- R13: "%r13",
- R14: "%r14",
- R15: "%r15",
- IP: "%ip",
- EIP: "%eip",
- RIP: "%rip",
- F0: "%st",
- F1: "%st(1)",
- F2: "%st(2)",
- F3: "%st(3)",
- F4: "%st(4)",
- F5: "%st(5)",
- F6: "%st(6)",
- F7: "%st(7)",
- M0: "%mm0",
- M1: "%mm1",
- M2: "%mm2",
- M3: "%mm3",
- M4: "%mm4",
- M5: "%mm5",
- M6: "%mm6",
- M7: "%mm7",
- X0: "%xmm0",
- X1: "%xmm1",
- X2: "%xmm2",
- X3: "%xmm3",
- X4: "%xmm4",
- X5: "%xmm5",
- X6: "%xmm6",
- X7: "%xmm7",
- X8: "%xmm8",
- X9: "%xmm9",
- X10: "%xmm10",
- X11: "%xmm11",
- X12: "%xmm12",
- X13: "%xmm13",
- X14: "%xmm14",
- X15: "%xmm15",
- CS: "%cs",
- SS: "%ss",
- DS: "%ds",
- ES: "%es",
- FS: "%fs",
- GS: "%gs",
- GDTR: "%gdtr",
- IDTR: "%idtr",
- LDTR: "%ldtr",
- MSW: "%msw",
- TASK: "%task",
- CR0: "%cr0",
- CR1: "%cr1",
- CR2: "%cr2",
- CR3: "%cr3",
- CR4: "%cr4",
- CR5: "%cr5",
- CR6: "%cr6",
- CR7: "%cr7",
- CR8: "%cr8",
- CR9: "%cr9",
- CR10: "%cr10",
- CR11: "%cr11",
- CR12: "%cr12",
- CR13: "%cr13",
- CR14: "%cr14",
- CR15: "%cr15",
- DR0: "%db0",
- DR1: "%db1",
- DR2: "%db2",
- DR3: "%db3",
- DR4: "%db4",
- DR5: "%db5",
- DR6: "%db6",
- DR7: "%db7",
- TR0: "%tr0",
- TR1: "%tr1",
- TR2: "%tr2",
- TR3: "%tr3",
- TR4: "%tr4",
- TR5: "%tr5",
- TR6: "%tr6",
- TR7: "%tr7",
- }
- var gnuOp = map[Op]string{
- CBW: "cbtw",
- CDQ: "cltd",
- CMPSD: "cmpsl",
- CMPSD_XMM: "cmpsd",
- CWD: "cwtd",
- CWDE: "cwtl",
- CQO: "cqto",
- INSD: "insl",
- IRET: "iretw",
- IRETD: "iret",
- IRETQ: "iretq",
- LODSB: "lods",
- LODSD: "lods",
- LODSQ: "lods",
- LODSW: "lods",
- MOVSD: "movsl",
- MOVSD_XMM: "movsd",
- OUTSD: "outsl",
- POPA: "popaw",
- POPAD: "popa",
- POPF: "popfw",
- POPFD: "popf",
- PUSHA: "pushaw",
- PUSHAD: "pusha",
- PUSHF: "pushfw",
- PUSHFD: "pushf",
- SCASB: "scas",
- SCASD: "scas",
- SCASQ: "scas",
- SCASW: "scas",
- STOSB: "stos",
- STOSD: "stos",
- STOSQ: "stos",
- STOSW: "stos",
- XLATB: "xlat",
- }
- var cmppsOps = []string{
- "cmpeq",
- "cmplt",
- "cmple",
- "cmpunord",
- "cmpneq",
- "cmpnlt",
- "cmpnle",
- "cmpord",
- }
- var pclmulqOps = []string{
- "pclmullqlqdq",
- "pclmulhqlqdq",
- "pclmullqhqdq",
- "pclmulhqhqdq",
- }
- func countPrefix(inst *Inst, target Prefix) int {
- n := 0
- for _, p := range inst.Prefix {
- if p&0xFF == target&0xFF {
- n++
- }
- }
- return n
- }
- func markLastImplicit(inst *Inst, prefix Prefix) bool {
- for i := len(inst.Prefix) - 1; i >= 0; i-- {
- p := inst.Prefix[i]
- if p&0xFF == prefix {
- inst.Prefix[i] |= PrefixImplicit
- return true
- }
- }
- return false
- }
- func unmarkImplicit(inst *Inst, prefix Prefix) {
- for i := len(inst.Prefix) - 1; i >= 0; i-- {
- p := inst.Prefix[i]
- if p&0xFF == prefix {
- inst.Prefix[i] &^= PrefixImplicit
- }
- }
- }
- func byteSizeSuffix(b int) string {
- switch b {
- case 1:
- return "b"
- case 2:
- return "w"
- case 4:
- return "l"
- case 8:
- return "q"
- }
- return ""
- }
- func argBytes(inst *Inst, arg Arg) int {
- if isMem(arg) {
- return inst.MemBytes
- }
- return regBytes(arg)
- }
- func isFloat(op Op) bool {
- switch op {
- case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
- return true
- }
- return false
- }
- func isFloatInt(op Op) bool {
- switch op {
- case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
- return true
- }
- return false
- }
|