podman

Форк
0
598 строк · 13.5 Кб
1
// Copyright 2015 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 obj
6

7
import (
8
	"bytes"
9
	"github.com/twitchyliquid64/golang-asm/objabi"
10
	"fmt"
11
	"io"
12
	"strings"
13
)
14

15
const REG_NONE = 0
16

17
// Line returns a string containing the filename and line number for p
18
func (p *Prog) Line() string {
19
	return p.Ctxt.OutermostPos(p.Pos).Format(false, true)
20
}
21
func (p *Prog) InnermostLine(w io.Writer) {
22
	p.Ctxt.InnermostPos(p.Pos).WriteTo(w, false, true)
23
}
24

25
// InnermostLineNumber returns a string containing the line number for the
26
// innermost inlined function (if any inlining) at p's position
27
func (p *Prog) InnermostLineNumber() string {
28
	return p.Ctxt.InnermostPos(p.Pos).LineNumber()
29
}
30

31
// InnermostLineNumberHTML returns a string containing the line number for the
32
// innermost inlined function (if any inlining) at p's position
33
func (p *Prog) InnermostLineNumberHTML() string {
34
	return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML()
35
}
36

37
// InnermostFilename returns a string containing the innermost
38
// (in inlining) filename at p's position
39
func (p *Prog) InnermostFilename() string {
40
	// TODO For now, this is only used for debugging output, and if we need more/better information, it might change.
41
	// An example of what we might want to see is the full stack of positions for inlined code, so we get some visibility into what is recorded there.
42
	pos := p.Ctxt.InnermostPos(p.Pos)
43
	if !pos.IsKnown() {
44
		return "<unknown file name>"
45
	}
46
	return pos.Filename()
47
}
48

49
var armCondCode = []string{
50
	".EQ",
51
	".NE",
52
	".CS",
53
	".CC",
54
	".MI",
55
	".PL",
56
	".VS",
57
	".VC",
58
	".HI",
59
	".LS",
60
	".GE",
61
	".LT",
62
	".GT",
63
	".LE",
64
	"",
65
	".NV",
66
}
67

68
/* ARM scond byte */
69
const (
70
	C_SCOND     = (1 << 4) - 1
71
	C_SBIT      = 1 << 4
72
	C_PBIT      = 1 << 5
73
	C_WBIT      = 1 << 6
74
	C_FBIT      = 1 << 7
75
	C_UBIT      = 1 << 7
76
	C_SCOND_XOR = 14
77
)
78

79
// CConv formats opcode suffix bits (Prog.Scond).
80
func CConv(s uint8) string {
81
	if s == 0 {
82
		return ""
83
	}
84
	for i := range opSuffixSpace {
85
		sset := &opSuffixSpace[i]
86
		if sset.arch == objabi.GOARCH {
87
			return sset.cconv(s)
88
		}
89
	}
90
	return fmt.Sprintf("SC???%d", s)
91
}
92

93
// CConvARM formats ARM opcode suffix bits (mostly condition codes).
94
func CConvARM(s uint8) string {
95
	// TODO: could be great to move suffix-related things into
96
	// ARM asm backends some day.
97
	// obj/x86 can be used as an example.
98

99
	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
100
	if s&C_SBIT != 0 {
101
		sc += ".S"
102
	}
103
	if s&C_PBIT != 0 {
104
		sc += ".P"
105
	}
106
	if s&C_WBIT != 0 {
107
		sc += ".W"
108
	}
109
	if s&C_UBIT != 0 { /* ambiguous with FBIT */
110
		sc += ".U"
111
	}
112
	return sc
113
}
114

115
func (p *Prog) String() string {
116
	if p == nil {
117
		return "<nil Prog>"
118
	}
119
	if p.Ctxt == nil {
120
		return "<Prog without ctxt>"
121
	}
122
	return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString())
123
}
124

125
func (p *Prog) InnermostString(w io.Writer) {
126
	if p == nil {
127
		io.WriteString(w, "<nil Prog>")
128
		return
129
	}
130
	if p.Ctxt == nil {
131
		io.WriteString(w, "<Prog without ctxt>")
132
		return
133
	}
134
	fmt.Fprintf(w, "%.5d (", p.Pc)
135
	p.InnermostLine(w)
136
	io.WriteString(w, ")\t")
137
	p.WriteInstructionString(w)
138
}
139

140
// InstructionString returns a string representation of the instruction without preceding
141
// program counter or file and line number.
142
func (p *Prog) InstructionString() string {
143
	buf := new(bytes.Buffer)
144
	p.WriteInstructionString(buf)
145
	return buf.String()
146
}
147

148
// WriteInstructionString writes a string representation of the instruction without preceding
149
// program counter or file and line number.
150
func (p *Prog) WriteInstructionString(w io.Writer) {
151
	if p == nil {
152
		io.WriteString(w, "<nil Prog>")
153
		return
154
	}
155

156
	if p.Ctxt == nil {
157
		io.WriteString(w, "<Prog without ctxt>")
158
		return
159
	}
160

161
	sc := CConv(p.Scond)
162

163
	io.WriteString(w, p.As.String())
164
	io.WriteString(w, sc)
165
	sep := "\t"
166

167
	if p.From.Type != TYPE_NONE {
168
		io.WriteString(w, sep)
169
		WriteDconv(w, p, &p.From)
170
		sep = ", "
171
	}
172
	if p.Reg != REG_NONE {
173
		// Should not happen but might as well show it if it does.
174
		fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg)))
175
		sep = ", "
176
	}
177
	for i := range p.RestArgs {
178
		io.WriteString(w, sep)
179
		WriteDconv(w, p, &p.RestArgs[i])
180
		sep = ", "
181
	}
182

183
	if p.As == ATEXT {
184
		// If there are attributes, print them. Otherwise, skip the comma.
185
		// In short, print one of these two:
186
		// TEXT	foo(SB), DUPOK|NOSPLIT, $0
187
		// TEXT	foo(SB), $0
188
		s := p.From.Sym.Attribute.TextAttrString()
189
		if s != "" {
190
			fmt.Fprintf(w, "%s%s", sep, s)
191
			sep = ", "
192
		}
193
	}
194
	if p.To.Type != TYPE_NONE {
195
		io.WriteString(w, sep)
196
		WriteDconv(w, p, &p.To)
197
	}
198
	if p.RegTo2 != REG_NONE {
199
		fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
200
	}
201
}
202

203
func (ctxt *Link) NewProg() *Prog {
204
	p := new(Prog)
205
	p.Ctxt = ctxt
206
	return p
207
}
208

209
func (ctxt *Link) CanReuseProgs() bool {
210
	return ctxt.Debugasm == 0
211
}
212

213
func Dconv(p *Prog, a *Addr) string {
214
	buf := new(bytes.Buffer)
215
	WriteDconv(buf, p, a)
216
	return buf.String()
217
}
218

219
func WriteDconv(w io.Writer, p *Prog, a *Addr) {
220
	switch a.Type {
221
	default:
222
		fmt.Fprintf(w, "type=%d", a.Type)
223

224
	case TYPE_NONE:
225
		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
226
			a.WriteNameTo(w)
227
			fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
228
		}
229

230
	case TYPE_REG:
231
		// TODO(rsc): This special case is for x86 instructions like
232
		//	PINSRQ	CX,$1,X6
233
		// where the $1 is included in the p->to Addr.
234
		// Move into a new field.
235
		if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
236
			fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
237
			return
238
		}
239

240
		if a.Name != NAME_NONE || a.Sym != nil {
241
			a.WriteNameTo(w)
242
			fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
243
		} else {
244
			io.WriteString(w, Rconv(int(a.Reg)))
245
		}
246
		if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg &&
247
			a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ {
248
			fmt.Fprintf(w, "[%d]", a.Index)
249
		}
250

251
	case TYPE_BRANCH:
252
		if a.Sym != nil {
253
			fmt.Fprintf(w, "%s(SB)", a.Sym.Name)
254
		} else if a.Target() != nil {
255
			fmt.Fprint(w, a.Target().Pc)
256
		} else {
257
			fmt.Fprintf(w, "%d(PC)", a.Offset)
258
		}
259

260
	case TYPE_INDIR:
261
		io.WriteString(w, "*")
262
		a.WriteNameTo(w)
263

264
	case TYPE_MEM:
265
		a.WriteNameTo(w)
266
		if a.Index != REG_NONE {
267
			if a.Scale == 0 {
268
				// arm64 shifted or extended register offset, scale = 0.
269
				fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
270
			} else {
271
				fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
272
			}
273
		}
274

275
	case TYPE_CONST:
276
		io.WriteString(w, "$")
277
		a.WriteNameTo(w)
278
		if a.Reg != 0 {
279
			fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
280
		}
281

282
	case TYPE_TEXTSIZE:
283
		if a.Val.(int32) == objabi.ArgsSizeUnknown {
284
			fmt.Fprintf(w, "$%d", a.Offset)
285
		} else {
286
			fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
287
		}
288

289
	case TYPE_FCONST:
290
		str := fmt.Sprintf("%.17g", a.Val.(float64))
291
		// Make sure 1 prints as 1.0
292
		if !strings.ContainsAny(str, ".e") {
293
			str += ".0"
294
		}
295
		fmt.Fprintf(w, "$(%s)", str)
296

297
	case TYPE_SCONST:
298
		fmt.Fprintf(w, "$%q", a.Val.(string))
299

300
	case TYPE_ADDR:
301
		io.WriteString(w, "$")
302
		a.WriteNameTo(w)
303

304
	case TYPE_SHIFT:
305
		v := int(a.Offset)
306
		ops := "<<>>->@>"
307
		switch objabi.GOARCH {
308
		case "arm":
309
			op := ops[((v>>5)&3)<<1:]
310
			if v&(1<<4) != 0 {
311
				fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
312
			} else {
313
				fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
314
			}
315
			if a.Reg != 0 {
316
				fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
317
			}
318
		case "arm64":
319
			op := ops[((v>>22)&3)<<1:]
320
			r := (v >> 16) & 31
321
			fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
322
		default:
323
			panic("TYPE_SHIFT is not supported on " + objabi.GOARCH)
324
		}
325

326
	case TYPE_REGREG:
327
		fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
328

329
	case TYPE_REGREG2:
330
		fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
331

332
	case TYPE_REGLIST:
333
		io.WriteString(w, RLconv(a.Offset))
334
	}
335
}
336

337
func (a *Addr) WriteNameTo(w io.Writer) {
338
	switch a.Name {
339
	default:
340
		fmt.Fprintf(w, "name=%d", a.Name)
341

342
	case NAME_NONE:
343
		switch {
344
		case a.Reg == REG_NONE:
345
			fmt.Fprint(w, a.Offset)
346
		case a.Offset == 0:
347
			fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
348
		case a.Offset != 0:
349
			fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
350
		}
351

352
		// Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.
353
	case NAME_EXTERN:
354
		reg := "SB"
355
		if a.Reg != REG_NONE {
356
			reg = Rconv(int(a.Reg))
357
		}
358
		if a.Sym != nil {
359
			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
360
		} else {
361
			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
362
		}
363

364
	case NAME_GOTREF:
365
		reg := "SB"
366
		if a.Reg != REG_NONE {
367
			reg = Rconv(int(a.Reg))
368
		}
369
		if a.Sym != nil {
370
			fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
371
		} else {
372
			fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
373
		}
374

375
	case NAME_STATIC:
376
		reg := "SB"
377
		if a.Reg != REG_NONE {
378
			reg = Rconv(int(a.Reg))
379
		}
380
		if a.Sym != nil {
381
			fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
382
		} else {
383
			fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
384
		}
385

386
	case NAME_AUTO:
387
		reg := "SP"
388
		if a.Reg != REG_NONE {
389
			reg = Rconv(int(a.Reg))
390
		}
391
		if a.Sym != nil {
392
			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
393
		} else {
394
			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
395
		}
396

397
	case NAME_PARAM:
398
		reg := "FP"
399
		if a.Reg != REG_NONE {
400
			reg = Rconv(int(a.Reg))
401
		}
402
		if a.Sym != nil {
403
			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
404
		} else {
405
			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
406
		}
407
	case NAME_TOCREF:
408
		reg := "SB"
409
		if a.Reg != REG_NONE {
410
			reg = Rconv(int(a.Reg))
411
		}
412
		if a.Sym != nil {
413
			fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
414
		} else {
415
			fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
416
		}
417
	}
418
}
419

420
func offConv(off int64) string {
421
	if off == 0 {
422
		return ""
423
	}
424
	return fmt.Sprintf("%+d", off)
425
}
426

427
// opSuffixSet is like regListSet, but for opcode suffixes.
428
//
429
// Unlike some other similar structures, uint8 space is not
430
// divided by its own values set (because there are only 256 of them).
431
// Instead, every arch may interpret/format all 8 bits as they like,
432
// as long as they register proper cconv function for it.
433
type opSuffixSet struct {
434
	arch  string
435
	cconv func(suffix uint8) string
436
}
437

438
var opSuffixSpace []opSuffixSet
439

440
// RegisterOpSuffix assigns cconv function for formatting opcode suffixes
441
// when compiling for GOARCH=arch.
442
//
443
// cconv is never called with 0 argument.
444
func RegisterOpSuffix(arch string, cconv func(uint8) string) {
445
	opSuffixSpace = append(opSuffixSpace, opSuffixSet{
446
		arch:  arch,
447
		cconv: cconv,
448
	})
449
}
450

451
type regSet struct {
452
	lo    int
453
	hi    int
454
	Rconv func(int) string
455
}
456

457
// Few enough architectures that a linear scan is fastest.
458
// Not even worth sorting.
459
var regSpace []regSet
460

461
/*
462
	Each architecture defines a register space as a unique
463
	integer range.
464
	Here is the list of architectures and the base of their register spaces.
465
*/
466

467
const (
468
	// Because of masking operations in the encodings, each register
469
	// space should start at 0 modulo some power of 2.
470
	RBase386   = 1 * 1024
471
	RBaseAMD64 = 2 * 1024
472
	RBaseARM   = 3 * 1024
473
	RBasePPC64 = 4 * 1024  // range [4k, 8k)
474
	RBaseARM64 = 8 * 1024  // range [8k, 13k)
475
	RBaseMIPS  = 13 * 1024 // range [13k, 14k)
476
	RBaseS390X = 14 * 1024 // range [14k, 15k)
477
	RBaseRISCV = 15 * 1024 // range [15k, 16k)
478
	RBaseWasm  = 16 * 1024
479
)
480

481
// RegisterRegister binds a pretty-printer (Rconv) for register
482
// numbers to a given register number range. Lo is inclusive,
483
// hi exclusive (valid registers are lo through hi-1).
484
func RegisterRegister(lo, hi int, Rconv func(int) string) {
485
	regSpace = append(regSpace, regSet{lo, hi, Rconv})
486
}
487

488
func Rconv(reg int) string {
489
	if reg == REG_NONE {
490
		return "NONE"
491
	}
492
	for i := range regSpace {
493
		rs := &regSpace[i]
494
		if rs.lo <= reg && reg < rs.hi {
495
			return rs.Rconv(reg)
496
		}
497
	}
498
	return fmt.Sprintf("R???%d", reg)
499
}
500

501
type regListSet struct {
502
	lo     int64
503
	hi     int64
504
	RLconv func(int64) string
505
}
506

507
var regListSpace []regListSet
508

509
// Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its
510
// arch-specific register list numbers.
511
const (
512
	RegListARMLo = 0
513
	RegListARMHi = 1 << 16
514

515
	// arm64 uses the 60th bit to differentiate from other archs
516
	RegListARM64Lo = 1 << 60
517
	RegListARM64Hi = 1<<61 - 1
518

519
	// x86 uses the 61th bit to differentiate from other archs
520
	RegListX86Lo = 1 << 61
521
	RegListX86Hi = 1<<62 - 1
522
)
523

524
// RegisterRegisterList binds a pretty-printer (RLconv) for register list
525
// numbers to a given register list number range. Lo is inclusive,
526
// hi exclusive (valid register list are lo through hi-1).
527
func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
528
	regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
529
}
530

531
func RLconv(list int64) string {
532
	for i := range regListSpace {
533
		rls := &regListSpace[i]
534
		if rls.lo <= list && list < rls.hi {
535
			return rls.RLconv(list)
536
		}
537
	}
538
	return fmt.Sprintf("RL???%d", list)
539
}
540

541
type opSet struct {
542
	lo    As
543
	names []string
544
}
545

546
// Not even worth sorting
547
var aSpace []opSet
548

549
// RegisterOpcode binds a list of instruction names
550
// to a given instruction number range.
551
func RegisterOpcode(lo As, Anames []string) {
552
	if len(Anames) > AllowedOpCodes {
553
		panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
554
	}
555
	aSpace = append(aSpace, opSet{lo, Anames})
556
}
557

558
func (a As) String() string {
559
	if 0 <= a && int(a) < len(Anames) {
560
		return Anames[a]
561
	}
562
	for i := range aSpace {
563
		as := &aSpace[i]
564
		if as.lo <= a && int(a-as.lo) < len(as.names) {
565
			return as.names[a-as.lo]
566
		}
567
	}
568
	return fmt.Sprintf("A???%d", a)
569
}
570

571
var Anames = []string{
572
	"XXX",
573
	"CALL",
574
	"DUFFCOPY",
575
	"DUFFZERO",
576
	"END",
577
	"FUNCDATA",
578
	"JMP",
579
	"NOP",
580
	"PCALIGN",
581
	"PCDATA",
582
	"RET",
583
	"GETCALLERPC",
584
	"TEXT",
585
	"UNDEF",
586
}
587

588
func Bool2int(b bool) int {
589
	// The compiler currently only optimizes this form.
590
	// See issue 6011.
591
	var i int
592
	if b {
593
		i = 1
594
	} else {
595
		i = 0
596
	}
597
	return i
598
}
599

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

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

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

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