cubefs

Форк
0
956 строк · 21.4 Кб
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.
4

5
package x86asm
6

7
import (
8
	"fmt"
9
	"strings"
10
)
11

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.
19

20
	if symname == nil {
21
		symname = func(uint64) (string, uint64) { return "", 0 }
22
	}
23

24
	// Adjust opcode [sic].
25
	switch inst.Op {
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) {
35
			switch inst.Op {
36
			case FDIV:
37
				inst.Op = FDIVR
38
			case FDIVR:
39
				inst.Op = FDIV
40
			case FSUB:
41
				inst.Op = FSUBR
42
			case FSUBR:
43
				inst.Op = FSUB
44
			case FDIVP:
45
				inst.Op = FDIVRP
46
			case FDIVRP:
47
				inst.Op = FDIVP
48
			case FSUBP:
49
				inst.Op = FSUBRP
50
			case FSUBRP:
51
				inst.Op = FSUBP
52
			}
53
		}
54

55
	case MOVNTSD:
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 {
63
			found := false
64
			for i := len(inst.Prefix) - 1; i >= 0; i-- {
65
				switch inst.Prefix[i] & 0xFF {
66
				case 0xF3:
67
					if !found {
68
						found = true
69
						inst.Prefix[i] |= PrefixImplicit
70
					}
71
				case 0xF2:
72
					inst.Prefix[i] &^= PrefixImplicit
73
				}
74
			}
75
			inst.Op = MOVNTSS
76
		}
77
	}
78

79
	// Add implicit arguments.
80
	switch inst.Op {
81
	case MONITOR:
82
		inst.Args[0] = EDX
83
		inst.Args[1] = ECX
84
		inst.Args[2] = EAX
85
		if inst.AddrSize == 16 {
86
			inst.Args[2] = AX
87
		}
88

89
	case MWAIT:
90
		if inst.Mode == 64 {
91
			inst.Args[0] = RCX
92
			inst.Args[1] = RAX
93
		} else {
94
			inst.Args[0] = ECX
95
			inst.Args[1] = EAX
96
		}
97
	}
98

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.
104
	switch inst.Op {
105
	case CRC32:
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)
115
		}
116

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)
123

124
	case CVTSI2SD, CVTSI2SS:
125
		if !isMem(inst.Args[1]) {
126
			markLastImplicit(&inst, PrefixDataSize)
127
		}
128

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)
133

134
	case LOOP, LOOPE, LOOPNE, MONITOR:
135
		markLastImplicit(&inst, PrefixAddrSize)
136

137
	case MOV:
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)
150
		}
151

152
	case MOVDQU:
153
		if countPrefix(&inst, 0xF3) > 1 {
154
			unmarkImplicit(&inst, 0xF3)
155
			markLastImplicit(&inst, 0xF3)
156
		}
157

158
	case MOVQ2DQ:
159
		markLastImplicit(&inst, PrefixDataSize)
160

161
	case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B:
162
		if isMem(inst.Args[0]) {
163
			unmarkImplicit(&inst, PrefixDataSize)
164
		}
165

166
	case SYSEXIT:
167
		unmarkImplicit(&inst, PrefixDataSize)
168
	}
169

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 {
173
				switch p & 0xFFF {
174
				case PrefixPN, PrefixPT:
175
					inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix
176
				}
177
			}
178
		}
179
	}
180

181
	// XACQUIRE/XRELEASE adjustment.
182
	if inst.Op == MOV {
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
185
		// conversion.
186
		haveREPN := false
187
		for i := len(inst.Prefix) - 1; i >= 0; i-- {
188
			switch inst.Prefix[i] &^ PrefixIgnored {
189
			case PrefixREPN:
190
				haveREPN = true
191
			case PrefixXRELEASE:
192
				if haveREPN {
193
					inst.Prefix[i] = PrefixREP
194
				}
195
			}
196
		}
197
	}
198

199
	// We only format the final F2/F3 as XRELEASE/XACQUIRE.
200
	haveXA := false
201
	haveXR := false
202
	for i := len(inst.Prefix) - 1; i >= 0; i-- {
203
		switch inst.Prefix[i] &^ PrefixIgnored {
204
		case PrefixXRELEASE:
205
			if !haveXR {
206
				haveXR = true
207
			} else {
208
				inst.Prefix[i] = PrefixREP
209
			}
210

211
		case PrefixXACQUIRE:
212
			if !haveXA {
213
				haveXA = true
214
			} else {
215
				inst.Prefix[i] = PrefixREPN
216
			}
217
		}
218
	}
219

220
	// Determine opcode.
221
	op := strings.ToLower(inst.Op.String())
222
	if alt := gnuOp[inst.Op]; alt != "" {
223
		op = alt
224
	}
225

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.
233
	needSuffix := true
234
SuffixLoop:
235
	for i, a := range inst.Args {
236
		if a == nil {
237
			break
238
		}
239
		switch a := a.(type) {
240
		case Reg:
241
			switch inst.Op {
242
			case MOVSX, MOVZX:
243
				continue
244

245
			case SHL, SHR, RCL, RCR, ROL, ROR, SAR:
246
				if i == 1 {
247
					// shift count does not tell us operand size
248
					continue
249
				}
250

251
			case CRC32:
252
				// The source argument does tell us operand size,
253
				// but libopcodes still always puts a suffix on crc32.
254
				continue
255

256
			case PUSH, POP:
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 {
261
					continue
262
				}
263

264
			case CVTSI2SD, CVTSI2SS:
265
				// The integer register argument takes priority.
266
				if X0 <= a && a <= X15 {
267
					continue
268
				}
269
			}
270

271
			if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 {
272
				needSuffix = false
273
				break SuffixLoop
274
			}
275
		}
276
	}
277

278
	if needSuffix {
279
		switch inst.Op {
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.
284

285
		case CRC32:
286
			op += byteSizeSuffix(argBytes(&inst, inst.Args[1]))
287

288
		case LGDT, LIDT, SGDT, SIDT:
289
			op += byteSizeSuffix(inst.DataSize / 8)
290

291
		case MOVZX, MOVSX:
292
			// Integer size conversions get two suffixes.
293
			op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0]))
294

295
		case LOOP, LOOPE, LOOPNE:
296
			// Add w suffix to indicate use of CX register instead of ECX.
297
			if inst.AddrSize == 16 {
298
				op += "w"
299
			}
300

301
		case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN:
302
			// Add w suffix to indicate use of 16-bit target.
303
			// Exclude JMP rel8.
304
			if inst.Opcode>>24 == 0xEB {
305
				break
306
			}
307
			if inst.DataSize == 16 && inst.Mode != 16 {
308
				markLastImplicit(&inst, PrefixDataSize)
309
				op += "w"
310
			} else if inst.Mode == 64 {
311
				op += "q"
312
			}
313

314
		case FRSTOR, FNSAVE, FNSTENV, FLDENV:
315
			// Add s suffix to indicate shortened FPU state (I guess).
316
			if inst.DataSize == 16 {
317
				op += "s"
318
			}
319

320
		case PUSH, POP:
321
			if markLastImplicit(&inst, PrefixDataSize) {
322
				op += byteSizeSuffix(inst.DataSize / 8)
323
			} else if inst.Mode == 64 {
324
				op += "q"
325
			} else {
326
				op += byteSizeSuffix(inst.MemBytes)
327
			}
328

329
		default:
330
			if isFloat(inst.Op) {
331
				// I can't explain any of this, but it's what libopcodes does.
332
				switch inst.MemBytes {
333
				default:
334
					if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) {
335
						op += "t"
336
					}
337
				case 4:
338
					if isFloatInt(inst.Op) {
339
						op += "l"
340
					} else {
341
						op += "s"
342
					}
343
				case 8:
344
					if isFloatInt(inst.Op) {
345
						op += "ll"
346
					} else {
347
						op += "l"
348
					}
349
				}
350
				break
351
			}
352

353
			op += byteSizeSuffix(inst.MemBytes)
354
		}
355
	}
356

357
	// Adjust special case opcodes.
358
	switch inst.Op {
359
	case 0:
360
		if inst.Prefix[0] != 0 {
361
			return strings.ToLower(inst.Prefix[0].String())
362
		}
363

364
	case INT:
365
		if inst.Opcode>>24 == 0xCC {
366
			inst.Args[0] = nil
367
			op = "int3"
368
		}
369

370
	case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
371
		imm, ok := inst.Args[2].(Imm)
372
		if ok && 0 <= imm && imm < 8 {
373
			inst.Args[2] = nil
374
			op = cmppsOps[imm] + op[3:]
375
		}
376

377
	case PCLMULQDQ:
378
		imm, ok := inst.Args[2].(Imm)
379
		if ok && imm&^0x11 == 0 {
380
			inst.Args[2] = nil
381
			op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
382
		}
383

384
	case XLATB:
385
		if markLastImplicit(&inst, PrefixAddrSize) {
386
			op = "xlat" // not xlatb
387
		}
388
	}
389

390
	// Build list of argument strings.
391
	var (
392
		usedPrefixes bool     // segment prefixes consumed by Mem formatting
393
		args         []string // formatted arguments
394
	)
395
	for i, a := range inst.Args {
396
		if a == nil {
397
			break
398
		}
399
		switch inst.Op {
400
		case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
401
			if i == 0 {
402
				usedPrefixes = true // disable use of prefixes for first argument
403
			} else {
404
				usedPrefixes = false
405
			}
406
		}
407
		if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
408
			continue
409
		}
410
		args = append(args, gnuArg(&inst, pc, symname, a, &usedPrefixes))
411
	}
412

413
	// The default is to print the arguments in reverse Intel order.
414
	// A few instructions inhibit this behavior.
415
	switch inst.Op {
416
	case BOUND, LCALL, ENTER, LJMP:
417
		// no reverse
418
	default:
419
		// reverse args
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]
422
		}
423
	}
424

425
	// Build prefix string.
426
	// Must be after argument formatting, which can turn off segment prefixes.
427
	var (
428
		prefix       = "" // output string
429
		numAddr      = 0
430
		numData      = 0
431
		implicitData = false
432
	)
433
	for _, p := range inst.Prefix {
434
		if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
435
			implicitData = true
436
		}
437
	}
438
	for _, p := range inst.Prefix {
439
		if p == 0 || p.IsVEX() {
440
			break
441
		}
442
		if p&PrefixImplicit != 0 {
443
			continue
444
		}
445
		switch p &^ (PrefixIgnored | PrefixInvalid) {
446
		default:
447
			if p.IsREX() {
448
				if p&0xFF == PrefixREX {
449
					prefix += "rex "
450
				} else {
451
					prefix += "rex." + p.String()[4:] + " "
452
				}
453
				break
454
			}
455
			prefix += strings.ToLower(p.String()) + " "
456

457
		case PrefixPN:
458
			op += ",pn"
459
			continue
460

461
		case PrefixPT:
462
			op += ",pt"
463
			continue
464

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
469
			// still 16-bit.
470
			n := 32
471
			if inst.Mode == 32 {
472
				n = 16
473
			}
474
			numAddr++
475
			if countPrefix(&inst, PrefixAddrSize) > numAddr {
476
				n = inst.Mode
477
			}
478
			prefix += fmt.Sprintf("addr%d ", n)
479
			continue
480

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).
485
				n := 16
486
				if inst.Mode == 16 {
487
					n = 32
488
				}
489
				numData++
490
				if countPrefix(&inst, PrefixDataSize) > numData {
491
					if inst.Mode == 16 {
492
						n = 16
493
					} else {
494
						n = 32
495
					}
496
				}
497
				prefix += fmt.Sprintf("data%d ", n)
498
				continue
499
			}
500
			prefix += strings.ToLower(p.String()) + " "
501
		}
502
	}
503

504
	// Finally! Put it all together.
505
	text := prefix + op
506
	if args != nil {
507
		text += " "
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])) {
510
			text += "*"
511
		}
512
		text += strings.Join(args, ",")
513
	}
514
	return text
515
}
516

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 {
521
	if x == nil {
522
		return "<nil>"
523
	}
524
	switch x := x.(type) {
525
	case Reg:
526
		switch inst.Op {
527
		case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
528
			if inst.DataSize == 16 && EAX <= x && x <= R15L {
529
				x -= EAX - AX
530
			}
531

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.
534
			if x == DX {
535
				return "(%dx)"
536
			}
537
		case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
538
			return strings.Replace(gccRegName[x], "xmm", "ymm", -1)
539
		}
540
		return gccRegName[x]
541
	case Mem:
542
		if s, disp := memArgToSymbol(x, pc, inst.Len, symname); s != "" {
543
			suffix := ""
544
			if disp != 0 {
545
				suffix = fmt.Sprintf("%+d", disp)
546
			}
547
			return fmt.Sprintf("%s%s", s, suffix)
548
		}
549
		seg := ""
550
		var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
551
		switch x.Segment {
552
		case CS:
553
			haveCS = true
554
		case DS:
555
			haveDS = true
556
		case ES:
557
			haveES = true
558
		case FS:
559
			haveFS = true
560
		case GS:
561
			haveGS = true
562
		case SS:
563
			haveSS = true
564
		}
565
		switch inst.Op {
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.
568
		default:
569
			if *usedPrefixes {
570
				break
571
			}
572
			for i := len(inst.Prefix) - 1; i >= 0; i-- {
573
				p := inst.Prefix[i] &^ PrefixIgnored
574
				if p == 0 {
575
					continue
576
				}
577
				switch p {
578
				case PrefixCS:
579
					if !haveCS {
580
						haveCS = true
581
						inst.Prefix[i] |= PrefixImplicit
582
					}
583
				case PrefixDS:
584
					if !haveDS {
585
						haveDS = true
586
						inst.Prefix[i] |= PrefixImplicit
587
					}
588
				case PrefixES:
589
					if !haveES {
590
						haveES = true
591
						inst.Prefix[i] |= PrefixImplicit
592
					}
593
				case PrefixFS:
594
					if !haveFS {
595
						haveFS = true
596
						inst.Prefix[i] |= PrefixImplicit
597
					}
598
				case PrefixGS:
599
					if !haveGS {
600
						haveGS = true
601
						inst.Prefix[i] |= PrefixImplicit
602
					}
603
				case PrefixSS:
604
					if !haveSS {
605
						haveSS = true
606
						inst.Prefix[i] |= PrefixImplicit
607
					}
608
				}
609
			}
610
			*usedPrefixes = true
611
		}
612
		if haveCS {
613
			seg += "%cs:"
614
		}
615
		if haveDS {
616
			seg += "%ds:"
617
		}
618
		if haveSS {
619
			seg += "%ss:"
620
		}
621
		if haveES {
622
			seg += "%es:"
623
		}
624
		if haveFS {
625
			seg += "%fs:"
626
		}
627
		if haveGS {
628
			seg += "%gs:"
629
		}
630
		disp := ""
631
		if x.Disp != 0 {
632
			disp = fmt.Sprintf("%#x", x.Disp)
633
		}
634
		if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
635
			if x.Base == 0 {
636
				return seg + disp
637
			}
638
			return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
639
		}
640
		base := gccRegName[x.Base]
641
		if x.Base == 0 {
642
			base = ""
643
		}
644
		index := gccRegName[x.Index]
645
		if x.Index == 0 {
646
			if inst.AddrSize == 64 {
647
				index = "%riz"
648
			} else {
649
				index = "%eiz"
650
			}
651
		}
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)
655
		}
656
		return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
657
	case Rel:
658
		if pc == 0 {
659
			return fmt.Sprintf(".%+#x", int64(x))
660
		} else {
661
			addr := pc + uint64(inst.Len) + uint64(x)
662
			if s, base := symname(addr); s != "" && addr == base {
663
				return fmt.Sprintf("%s", s)
664
			} else {
665
				addr := pc + uint64(inst.Len) + uint64(x)
666
				return fmt.Sprintf("%#x", addr)
667
			}
668
		}
669
	case Imm:
670
		if s, base := symname(uint64(x)); s != "" {
671
			suffix := ""
672
			if uint64(x) != base {
673
				suffix = fmt.Sprintf("%+d", uint64(x)-base)
674
			}
675
			return fmt.Sprintf("$%s%s", s, suffix)
676
		}
677
		if inst.Mode == 32 {
678
			return fmt.Sprintf("$%#x", uint32(x))
679
		}
680
		return fmt.Sprintf("$%#x", int64(x))
681
	}
682
	return x.String()
683
}
684

685
var gccRegName = [...]string{
686
	0:    "REG0",
687
	AL:   "%al",
688
	CL:   "%cl",
689
	BL:   "%bl",
690
	DL:   "%dl",
691
	AH:   "%ah",
692
	CH:   "%ch",
693
	BH:   "%bh",
694
	DH:   "%dh",
695
	SPB:  "%spl",
696
	BPB:  "%bpl",
697
	SIB:  "%sil",
698
	DIB:  "%dil",
699
	R8B:  "%r8b",
700
	R9B:  "%r9b",
701
	R10B: "%r10b",
702
	R11B: "%r11b",
703
	R12B: "%r12b",
704
	R13B: "%r13b",
705
	R14B: "%r14b",
706
	R15B: "%r15b",
707
	AX:   "%ax",
708
	CX:   "%cx",
709
	BX:   "%bx",
710
	DX:   "%dx",
711
	SP:   "%sp",
712
	BP:   "%bp",
713
	SI:   "%si",
714
	DI:   "%di",
715
	R8W:  "%r8w",
716
	R9W:  "%r9w",
717
	R10W: "%r10w",
718
	R11W: "%r11w",
719
	R12W: "%r12w",
720
	R13W: "%r13w",
721
	R14W: "%r14w",
722
	R15W: "%r15w",
723
	EAX:  "%eax",
724
	ECX:  "%ecx",
725
	EDX:  "%edx",
726
	EBX:  "%ebx",
727
	ESP:  "%esp",
728
	EBP:  "%ebp",
729
	ESI:  "%esi",
730
	EDI:  "%edi",
731
	R8L:  "%r8d",
732
	R9L:  "%r9d",
733
	R10L: "%r10d",
734
	R11L: "%r11d",
735
	R12L: "%r12d",
736
	R13L: "%r13d",
737
	R14L: "%r14d",
738
	R15L: "%r15d",
739
	RAX:  "%rax",
740
	RCX:  "%rcx",
741
	RDX:  "%rdx",
742
	RBX:  "%rbx",
743
	RSP:  "%rsp",
744
	RBP:  "%rbp",
745
	RSI:  "%rsi",
746
	RDI:  "%rdi",
747
	R8:   "%r8",
748
	R9:   "%r9",
749
	R10:  "%r10",
750
	R11:  "%r11",
751
	R12:  "%r12",
752
	R13:  "%r13",
753
	R14:  "%r14",
754
	R15:  "%r15",
755
	IP:   "%ip",
756
	EIP:  "%eip",
757
	RIP:  "%rip",
758
	F0:   "%st",
759
	F1:   "%st(1)",
760
	F2:   "%st(2)",
761
	F3:   "%st(3)",
762
	F4:   "%st(4)",
763
	F5:   "%st(5)",
764
	F6:   "%st(6)",
765
	F7:   "%st(7)",
766
	M0:   "%mm0",
767
	M1:   "%mm1",
768
	M2:   "%mm2",
769
	M3:   "%mm3",
770
	M4:   "%mm4",
771
	M5:   "%mm5",
772
	M6:   "%mm6",
773
	M7:   "%mm7",
774
	X0:   "%xmm0",
775
	X1:   "%xmm1",
776
	X2:   "%xmm2",
777
	X3:   "%xmm3",
778
	X4:   "%xmm4",
779
	X5:   "%xmm5",
780
	X6:   "%xmm6",
781
	X7:   "%xmm7",
782
	X8:   "%xmm8",
783
	X9:   "%xmm9",
784
	X10:  "%xmm10",
785
	X11:  "%xmm11",
786
	X12:  "%xmm12",
787
	X13:  "%xmm13",
788
	X14:  "%xmm14",
789
	X15:  "%xmm15",
790
	CS:   "%cs",
791
	SS:   "%ss",
792
	DS:   "%ds",
793
	ES:   "%es",
794
	FS:   "%fs",
795
	GS:   "%gs",
796
	GDTR: "%gdtr",
797
	IDTR: "%idtr",
798
	LDTR: "%ldtr",
799
	MSW:  "%msw",
800
	TASK: "%task",
801
	CR0:  "%cr0",
802
	CR1:  "%cr1",
803
	CR2:  "%cr2",
804
	CR3:  "%cr3",
805
	CR4:  "%cr4",
806
	CR5:  "%cr5",
807
	CR6:  "%cr6",
808
	CR7:  "%cr7",
809
	CR8:  "%cr8",
810
	CR9:  "%cr9",
811
	CR10: "%cr10",
812
	CR11: "%cr11",
813
	CR12: "%cr12",
814
	CR13: "%cr13",
815
	CR14: "%cr14",
816
	CR15: "%cr15",
817
	DR0:  "%db0",
818
	DR1:  "%db1",
819
	DR2:  "%db2",
820
	DR3:  "%db3",
821
	DR4:  "%db4",
822
	DR5:  "%db5",
823
	DR6:  "%db6",
824
	DR7:  "%db7",
825
	TR0:  "%tr0",
826
	TR1:  "%tr1",
827
	TR2:  "%tr2",
828
	TR3:  "%tr3",
829
	TR4:  "%tr4",
830
	TR5:  "%tr5",
831
	TR6:  "%tr6",
832
	TR7:  "%tr7",
833
}
834

835
var gnuOp = map[Op]string{
836
	CBW:       "cbtw",
837
	CDQ:       "cltd",
838
	CMPSD:     "cmpsl",
839
	CMPSD_XMM: "cmpsd",
840
	CWD:       "cwtd",
841
	CWDE:      "cwtl",
842
	CQO:       "cqto",
843
	INSD:      "insl",
844
	IRET:      "iretw",
845
	IRETD:     "iret",
846
	IRETQ:     "iretq",
847
	LODSB:     "lods",
848
	LODSD:     "lods",
849
	LODSQ:     "lods",
850
	LODSW:     "lods",
851
	MOVSD:     "movsl",
852
	MOVSD_XMM: "movsd",
853
	OUTSD:     "outsl",
854
	POPA:      "popaw",
855
	POPAD:     "popa",
856
	POPF:      "popfw",
857
	POPFD:     "popf",
858
	PUSHA:     "pushaw",
859
	PUSHAD:    "pusha",
860
	PUSHF:     "pushfw",
861
	PUSHFD:    "pushf",
862
	SCASB:     "scas",
863
	SCASD:     "scas",
864
	SCASQ:     "scas",
865
	SCASW:     "scas",
866
	STOSB:     "stos",
867
	STOSD:     "stos",
868
	STOSQ:     "stos",
869
	STOSW:     "stos",
870
	XLATB:     "xlat",
871
}
872

873
var cmppsOps = []string{
874
	"cmpeq",
875
	"cmplt",
876
	"cmple",
877
	"cmpunord",
878
	"cmpneq",
879
	"cmpnlt",
880
	"cmpnle",
881
	"cmpord",
882
}
883

884
var pclmulqOps = []string{
885
	"pclmullqlqdq",
886
	"pclmulhqlqdq",
887
	"pclmullqhqdq",
888
	"pclmulhqhqdq",
889
}
890

891
func countPrefix(inst *Inst, target Prefix) int {
892
	n := 0
893
	for _, p := range inst.Prefix {
894
		if p&0xFF == target&0xFF {
895
			n++
896
		}
897
	}
898
	return n
899
}
900

901
func markLastImplicit(inst *Inst, prefix Prefix) bool {
902
	for i := len(inst.Prefix) - 1; i >= 0; i-- {
903
		p := inst.Prefix[i]
904
		if p&0xFF == prefix {
905
			inst.Prefix[i] |= PrefixImplicit
906
			return true
907
		}
908
	}
909
	return false
910
}
911

912
func unmarkImplicit(inst *Inst, prefix Prefix) {
913
	for i := len(inst.Prefix) - 1; i >= 0; i-- {
914
		p := inst.Prefix[i]
915
		if p&0xFF == prefix {
916
			inst.Prefix[i] &^= PrefixImplicit
917
		}
918
	}
919
}
920

921
func byteSizeSuffix(b int) string {
922
	switch b {
923
	case 1:
924
		return "b"
925
	case 2:
926
		return "w"
927
	case 4:
928
		return "l"
929
	case 8:
930
		return "q"
931
	}
932
	return ""
933
}
934

935
func argBytes(inst *Inst, arg Arg) int {
936
	if isMem(arg) {
937
		return inst.MemBytes
938
	}
939
	return regBytes(arg)
940
}
941

942
func isFloat(op Op) bool {
943
	switch op {
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:
945
		return true
946
	}
947
	return false
948
}
949

950
func isFloatInt(op Op) bool {
951
	switch op {
952
	case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
953
		return true
954
	}
955
	return false
956
}
957

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.