1
// Copyright 2014 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
12
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
13
// This general form is often called ``AT&T syntax'' as a reference to AT&T System V Unix.
14
func GNUSyntax(inst Inst, pc uint64, symname SymLookup) string {
15
// Rewrite instruction to mimic GNU peculiarities.
16
// Note that inst has been passed by value and contains
17
// no pointers, so any changes we make here are local
18
// and will not propagate back out to the caller.
21
symname = func(uint64) (string, uint64) { return "", 0 }
24
// Adjust opcode [sic].
26
case FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, FSUBRP:
27
// DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least
28
// if you believe the Intel manual is correct (the encoding is irregular as given;
29
// libopcodes uses the more regular expected encoding).
30
// TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers?
31
// NOTE: iant thinks this is deliberate, but we can't find the history.
32
_, reg1 := inst.Args[0].(Reg)
33
_, reg2 := inst.Args[1].(Reg)
34
if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) {
56
// MOVNTSD is F2 0F 2B /r.
57
// MOVNTSS is F3 0F 2B /r (supposedly; not in manuals).
58
// Usually inner prefixes win for display,
59
// so that F3 F2 0F 2B 11 is REP MOVNTSD
60
// and F2 F3 0F 2B 11 is REPN MOVNTSS.
61
// Libopcodes always prefers MOVNTSS regardless of prefix order.
62
if countPrefix(&inst, 0xF3) > 0 {
64
for i := len(inst.Prefix) - 1; i >= 0; i-- {
65
switch inst.Prefix[i] & 0xFF {
69
inst.Prefix[i] |= PrefixImplicit
72
inst.Prefix[i] &^= PrefixImplicit
79
// Add implicit arguments.
85
if inst.AddrSize == 16 {
99
// Adjust which prefixes will be displayed.
100
// The rule is to display all the prefixes not implied by
101
// the usual instruction display, that is, all the prefixes
102
// except the ones with PrefixImplicit set.
103
// However, of course, there are exceptions to the rule.
106
// CRC32 has a mandatory F2 prefix.
107
// If there are multiple F2s and no F3s, the extra F2s do not print.
108
// (And Decode has already marked them implicit.)
109
// However, if there is an F3 anywhere, then the extra F2s do print.
110
// If there are multiple F2 prefixes *and* an (ignored) F3,
111
// then libopcodes prints the extra F2s as REPNs.
112
if countPrefix(&inst, 0xF2) > 1 {
113
unmarkImplicit(&inst, 0xF2)
114
markLastImplicit(&inst, 0xF2)
117
// An unused data size override should probably be shown,
118
// to distinguish DATA16 CRC32B from plain CRC32B,
119
// but libopcodes always treats the final override as implicit
120
// and the others as explicit.
121
unmarkImplicit(&inst, PrefixDataSize)
122
markLastImplicit(&inst, PrefixDataSize)
124
case CVTSI2SD, CVTSI2SS:
125
if !isMem(inst.Args[1]) {
126
markLastImplicit(&inst, PrefixDataSize)
129
case CVTSD2SI, CVTSS2SI, CVTTSD2SI, CVTTSS2SI,
130
ENTER, FLDENV, FNSAVE, FNSTENV, FRSTOR, LGDT, LIDT, LRET,
131
POP, PUSH, RET, SGDT, SIDT, SYSRET, XBEGIN:
132
markLastImplicit(&inst, PrefixDataSize)
134
case LOOP, LOOPE, LOOPNE, MONITOR:
135
markLastImplicit(&inst, PrefixAddrSize)
138
// The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg
139
// cannot be distinguished when src or dst refers to memory, because
140
// Sreg is always a 16-bit value, even when we're doing a 32-bit
141
// instruction. Because the instruction tables distinguished these two,
142
// any operand size prefix has been marked as used (to decide which
143
// branch to take). Unmark it, so that it will show up in disassembly,
144
// so that the reader can tell the size of memory operand.
145
// up with the same arguments
146
dst, _ := inst.Args[0].(Reg)
147
src, _ := inst.Args[1].(Reg)
148
if ES <= src && src <= GS && isMem(inst.Args[0]) || ES <= dst && dst <= GS && isMem(inst.Args[1]) {
149
unmarkImplicit(&inst, PrefixDataSize)
153
if countPrefix(&inst, 0xF3) > 1 {
154
unmarkImplicit(&inst, 0xF3)
155
markLastImplicit(&inst, 0xF3)
159
markLastImplicit(&inst, PrefixDataSize)
161
case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B:
162
if isMem(inst.Args[0]) {
163
unmarkImplicit(&inst, PrefixDataSize)
167
unmarkImplicit(&inst, PrefixDataSize)
170
if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
171
if countPrefix(&inst, PrefixCS) > 0 && countPrefix(&inst, PrefixDS) > 0 {
172
for i, p := range inst.Prefix {
174
case PrefixPN, PrefixPT:
175
inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix
181
// XACQUIRE/XRELEASE adjustment.
183
// MOV into memory is a candidate for turning REP into XRELEASE.
184
// However, if the REP is followed by a REPN, that REPN blocks the
187
for i := len(inst.Prefix) - 1; i >= 0; i-- {
188
switch inst.Prefix[i] &^ PrefixIgnored {
193
inst.Prefix[i] = PrefixREP
199
// We only format the final F2/F3 as XRELEASE/XACQUIRE.
202
for i := len(inst.Prefix) - 1; i >= 0; i-- {
203
switch inst.Prefix[i] &^ PrefixIgnored {
208
inst.Prefix[i] = PrefixREP
215
inst.Prefix[i] = PrefixREPN
221
op := strings.ToLower(inst.Op.String())
222
if alt := gnuOp[inst.Op]; alt != "" {
226
// Determine opcode suffix.
227
// Libopcodes omits the suffix if the width of the operation
228
// can be inferred from a register arguments. For example,
229
// add $1, %ebx has no suffix because you can tell from the
230
// 32-bit register destination that it is a 32-bit add,
231
// but in addl $1, (%ebx), the destination is memory, so the
232
// size is not evident without the l suffix.
235
for i, a := range inst.Args {
239
switch a := a.(type) {
245
case SHL, SHR, RCL, RCR, ROL, ROR, SAR:
247
// shift count does not tell us operand size
252
// The source argument does tell us operand size,
253
// but libopcodes still always puts a suffix on crc32.
257
// Even though segment registers are 16-bit, push and pop
258
// can save/restore them from 32-bit slots, so they
259
// do not imply operand size.
260
if ES <= a && a <= GS {
264
case CVTSI2SD, CVTSI2SS:
265
// The integer register argument takes priority.
266
if X0 <= a && a <= X15 {
271
if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 {
280
case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ,
281
SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS,
282
SLDT, SMSW, STMXCSR, STR, VERR, VERW:
283
// For various reasons, libopcodes emits no suffix for these instructions.
286
op += byteSizeSuffix(argBytes(&inst, inst.Args[1]))
288
case LGDT, LIDT, SGDT, SIDT:
289
op += byteSizeSuffix(inst.DataSize / 8)
292
// Integer size conversions get two suffixes.
293
op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0]))
295
case LOOP, LOOPE, LOOPNE:
296
// Add w suffix to indicate use of CX register instead of ECX.
297
if inst.AddrSize == 16 {
301
case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN:
302
// Add w suffix to indicate use of 16-bit target.
304
if inst.Opcode>>24 == 0xEB {
307
if inst.DataSize == 16 && inst.Mode != 16 {
308
markLastImplicit(&inst, PrefixDataSize)
310
} else if inst.Mode == 64 {
314
case FRSTOR, FNSAVE, FNSTENV, FLDENV:
315
// Add s suffix to indicate shortened FPU state (I guess).
316
if inst.DataSize == 16 {
321
if markLastImplicit(&inst, PrefixDataSize) {
322
op += byteSizeSuffix(inst.DataSize / 8)
323
} else if inst.Mode == 64 {
326
op += byteSizeSuffix(inst.MemBytes)
330
if isFloat(inst.Op) {
331
// I can't explain any of this, but it's what libopcodes does.
332
switch inst.MemBytes {
334
if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) {
338
if isFloatInt(inst.Op) {
344
if isFloatInt(inst.Op) {
353
op += byteSizeSuffix(inst.MemBytes)
357
// Adjust special case opcodes.
360
if inst.Prefix[0] != 0 {
361
return strings.ToLower(inst.Prefix[0].String())
365
if inst.Opcode>>24 == 0xCC {
370
case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
371
imm, ok := inst.Args[2].(Imm)
372
if ok && 0 <= imm && imm < 8 {
374
op = cmppsOps[imm] + op[3:]
378
imm, ok := inst.Args[2].(Imm)
379
if ok && imm&^0x11 == 0 {
381
op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
385
if markLastImplicit(&inst, PrefixAddrSize) {
386
op = "xlat" // not xlatb
390
// Build list of argument strings.
392
usedPrefixes bool // segment prefixes consumed by Mem formatting
393
args []string // formatted arguments
395
for i, a := range inst.Args {
400
case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
402
usedPrefixes = true // disable use of prefixes for first argument
407
if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
410
args = append(args, gnuArg(&inst, pc, symname, a, &usedPrefixes))
413
// The default is to print the arguments in reverse Intel order.
414
// A few instructions inhibit this behavior.
416
case BOUND, LCALL, ENTER, LJMP:
420
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
421
args[i], args[j] = args[j], args[i]
425
// Build prefix string.
426
// Must be after argument formatting, which can turn off segment prefixes.
428
prefix = "" // output string
433
for _, p := range inst.Prefix {
434
if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
438
for _, p := range inst.Prefix {
439
if p == 0 || p.IsVEX() {
442
if p&PrefixImplicit != 0 {
445
switch p &^ (PrefixIgnored | PrefixInvalid) {
448
if p&0xFF == PrefixREX {
451
prefix += "rex." + p.String()[4:] + " "
455
prefix += strings.ToLower(p.String()) + " "
465
case PrefixAddrSize, PrefixAddr16, PrefixAddr32:
466
// For unknown reasons, if the addr16 prefix is repeated,
467
// libopcodes displays all but the last as addr32, even though
468
// the addressing form used in a memory reference is clearly
475
if countPrefix(&inst, PrefixAddrSize) > numAddr {
478
prefix += fmt.Sprintf("addr%d ", n)
481
case PrefixData16, PrefixData32:
482
if implicitData && countPrefix(&inst, PrefixDataSize) > 1 {
483
// Similar to the addr32 logic above, but it only kicks in
484
// when something used the data size prefix (one is implicit).
490
if countPrefix(&inst, PrefixDataSize) > numData {
497
prefix += fmt.Sprintf("data%d ", n)
500
prefix += strings.ToLower(p.String()) + " "
504
// Finally! Put it all together.
508
// Indirect call/jmp gets a star to distinguish from direct jump address.
509
if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) {
512
text += strings.Join(args, ",")
517
// gnuArg returns the GNU syntax for the argument x from the instruction inst.
518
// If *usedPrefixes is false and x is a Mem, then the formatting
519
// includes any segment prefixes and sets *usedPrefixes to true.
520
func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool) string {
524
switch x := x.(type) {
527
case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
528
if inst.DataSize == 16 && EAX <= x && x <= R15L {
532
case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD:
533
// DX is the port, but libopcodes prints it as if it were a memory reference.
537
case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
538
return strings.Replace(gccRegName[x], "xmm", "ymm", -1)
542
if s, disp := memArgToSymbol(x, pc, inst.Len, symname); s != "" {
545
suffix = fmt.Sprintf("%+d", disp)
547
return fmt.Sprintf("%s%s", s, suffix)
550
var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
566
case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
567
// These do not accept segment prefixes, at least in the GNU rendering.
572
for i := len(inst.Prefix) - 1; i >= 0; i-- {
573
p := inst.Prefix[i] &^ PrefixIgnored
581
inst.Prefix[i] |= PrefixImplicit
586
inst.Prefix[i] |= PrefixImplicit
591
inst.Prefix[i] |= PrefixImplicit
596
inst.Prefix[i] |= PrefixImplicit
601
inst.Prefix[i] |= PrefixImplicit
606
inst.Prefix[i] |= PrefixImplicit
632
disp = fmt.Sprintf("%#x", x.Disp)
634
if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
638
return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
640
base := gccRegName[x.Base]
644
index := gccRegName[x.Index]
646
if inst.AddrSize == 64 {
652
if AX <= x.Base && x.Base <= DI {
653
// 16-bit addressing - no scale
654
return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
656
return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
659
return fmt.Sprintf(".%+#x", int64(x))
661
addr := pc + uint64(inst.Len) + uint64(x)
662
if s, base := symname(addr); s != "" && addr == base {
663
return fmt.Sprintf("%s", s)
665
addr := pc + uint64(inst.Len) + uint64(x)
666
return fmt.Sprintf("%#x", addr)
670
if s, base := symname(uint64(x)); s != "" {
672
if uint64(x) != base {
673
suffix = fmt.Sprintf("%+d", uint64(x)-base)
675
return fmt.Sprintf("$%s%s", s, suffix)
678
return fmt.Sprintf("$%#x", uint32(x))
680
return fmt.Sprintf("$%#x", int64(x))
685
var gccRegName = [...]string{
835
var gnuOp = map[Op]string{
873
var cmppsOps = []string{
884
var pclmulqOps = []string{
891
func countPrefix(inst *Inst, target Prefix) int {
893
for _, p := range inst.Prefix {
894
if p&0xFF == target&0xFF {
901
func markLastImplicit(inst *Inst, prefix Prefix) bool {
902
for i := len(inst.Prefix) - 1; i >= 0; i-- {
904
if p&0xFF == prefix {
905
inst.Prefix[i] |= PrefixImplicit
912
func unmarkImplicit(inst *Inst, prefix Prefix) {
913
for i := len(inst.Prefix) - 1; i >= 0; i-- {
915
if p&0xFF == prefix {
916
inst.Prefix[i] &^= PrefixImplicit
921
func byteSizeSuffix(b int) string {
935
func argBytes(inst *Inst, arg Arg) int {
942
func isFloat(op Op) bool {
944
case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
950
func isFloatInt(op Op) bool {
952
case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR: