util.go 9.9 KB
Newer Older
1
// Copyright 2015 The Go Authors. All rights reserved.
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package obj

import (
8
	"bytes"
9
	"fmt"
10
	"log"
11
	"os"
12
	"strings"
13 14 15
	"time"
)

16 17
const REG_NONE = 0

18 19 20 21 22 23 24 25 26
var start time.Time

func Cputime() float64 {
	if start.IsZero() {
		start = time.Now()
	}
	return time.Since(start).Seconds()
}

27 28 29 30 31 32 33
func envOr(key, value string) string {
	if x := os.Getenv(key); x != "" {
		return x
	}
	return value
}

34 35 36 37 38 39 40 41
var (
	GOROOT  = envOr("GOROOT", defaultGOROOT)
	GOARCH  = envOr("GOARCH", defaultGOARCH)
	GOOS    = envOr("GOOS", defaultGOOS)
	GO386   = envOr("GO386", defaultGO386)
	GOARM   = goarm()
	Version = version
)
42

43
func goarm() int {
44
	switch v := envOr("GOARM", defaultGOARM); v {
45 46 47 48 49 50
	case "5":
		return 5
	case "6":
		return 6
	case "7":
		return 7
51 52 53 54
	}
	// Fail here, rather than validate at multiple call sites.
	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
	panic("unreachable")
55 56
}

57 58 59 60
func Getgoextlinkenabled() string {
	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
}

61
func (p *Prog) Line() string {
62
	return p.Ctxt.OutermostPos(p.Pos).Format(false)
63 64
}

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
var armCondCode = []string{
	".EQ",
	".NE",
	".CS",
	".CC",
	".MI",
	".PL",
	".VS",
	".VC",
	".HI",
	".LS",
	".GE",
	".LT",
	".GT",
	".LE",
	"",
	".NV",
}

/* ARM scond byte */
const (
	C_SCOND     = (1 << 4) - 1
	C_SBIT      = 1 << 4
	C_PBIT      = 1 << 5
	C_WBIT      = 1 << 6
	C_FBIT      = 1 << 7
	C_UBIT      = 1 << 7
	C_SCOND_XOR = 14
)

// CConv formats ARM condition codes.
func CConv(s uint8) string {
	if s == 0 {
		return ""
	}
	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
	if s&C_SBIT != 0 {
		sc += ".S"
	}
	if s&C_PBIT != 0 {
		sc += ".P"
	}
	if s&C_WBIT != 0 {
		sc += ".W"
	}
	if s&C_UBIT != 0 { /* ambiguous with FBIT */
		sc += ".U"
	}
	return sc
}

116
func (p *Prog) String() string {
117 118 119 120
	if p == nil {
		return "<nil Prog>"
	}

121
	if p.Ctxt == nil {
122
		return "<Prog without ctxt>"
123
	}
124 125 126 127 128

	sc := CConv(p.Scond)

	var buf bytes.Buffer

129
	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
130
	sep := "\t"
131 132 133 134 135
	quadOpAmd64 := p.RegTo2 == -1
	if quadOpAmd64 {
		fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
		sep = ", "
	}
136 137 138 139 140 141 142 143 144
	if p.From.Type != TYPE_NONE {
		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
		sep = ", "
	}
	if p.Reg != REG_NONE {
		// Should not happen but might as well show it if it does.
		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
		sep = ", "
	}
145
	if p.From3Type() != TYPE_NONE {
146
		if p.From3.Type == TYPE_CONST && p.As == ATEXT {
147 148
			// Special case - omit $.
			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
149 150
		} else if quadOpAmd64 {
			fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
151
		} else {
152
			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
153 154 155 156 157 158
		}
		sep = ", "
	}
	if p.To.Type != TYPE_NONE {
		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
	}
159
	if p.RegTo2 != REG_NONE && !quadOpAmd64 {
160
		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
161
	}
162
	return buf.String()
163
}
164 165

func (ctxt *Link) NewProg() *Prog {
166
	p := new(Prog)
167 168 169
	p.Ctxt = ctxt
	return p
}
170 171 172

func (ctxt *Link) CanReuseProgs() bool {
	return !ctxt.Debugasm
173
}
174

175
func (ctxt *Link) Dconv(a *Addr) string {
176
	return Dconv(nil, a)
177 178
}

179
func Dconv(p *Prog, a *Addr) string {
180 181 182 183 184 185 186 187 188
	var str string

	switch a.Type {
	default:
		str = fmt.Sprintf("type=%d", a.Type)

	case TYPE_NONE:
		str = ""
		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
189
			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
190 191 192 193 194 195 196 197 198 199 200 201
		}

	case TYPE_REG:
		// TODO(rsc): This special case is for x86 instructions like
		//	PINSRQ	CX,$1,X6
		// where the $1 is included in the p->to Addr.
		// Move into a new field.
		if a.Offset != 0 {
			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
			break
		}

202
		str = Rconv(int(a.Reg))
203
		if a.Name != NAME_NONE || a.Sym != nil {
204
			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
205 206 207 208 209 210
		}

	case TYPE_BRANCH:
		if a.Sym != nil {
			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
		} else if p != nil && p.Pcond != nil {
211
			str = fmt.Sprint(p.Pcond.Pc)
212
		} else if a.Val != nil {
213
			str = fmt.Sprint(a.Val.(*Prog).Pc)
214 215 216 217
		} else {
			str = fmt.Sprintf("%d(PC)", a.Offset)
		}

218
	case TYPE_INDIR:
219
		str = fmt.Sprintf("*%s", Mconv(a))
220

221
	case TYPE_MEM:
222
		str = Mconv(a)
223 224 225 226 227 228
		if a.Index != REG_NONE {
			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
		}

	case TYPE_CONST:
		if a.Reg != 0 {
229
			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
230
		} else {
231
			str = fmt.Sprintf("$%v", Mconv(a))
232 233 234
		}

	case TYPE_TEXTSIZE:
235
		if a.Val.(int32) == ArgsSizeUnknown {
236 237
			str = fmt.Sprintf("$%d", a.Offset)
		} else {
238
			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
239 240 241
		}

	case TYPE_FCONST:
242
		str = fmt.Sprintf("%.17g", a.Val.(float64))
243 244 245 246 247 248 249
		// Make sure 1 prints as 1.0
		if !strings.ContainsAny(str, ".e") {
			str += ".0"
		}
		str = fmt.Sprintf("$(%s)", str)

	case TYPE_SCONST:
250
		str = fmt.Sprintf("$%q", a.Val.(string))
251 252

	case TYPE_ADDR:
253
		str = fmt.Sprintf("$%s", Mconv(a))
254 255 256

	case TYPE_SHIFT:
		v := int(a.Offset)
257
		ops := "<<>>->@>"
258
		switch GOARCH {
259 260 261 262 263 264 265 266 267 268 269 270 271 272
		case "arm":
			op := ops[((v>>5)&3)<<1:]
			if v&(1<<4) != 0 {
				str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
			} else {
				str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
			}
			if a.Reg != 0 {
				str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
			}
		case "arm64":
			op := ops[((v>>22)&3)<<1:]
			str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63)
		default:
273
			panic("TYPE_SHIFT is not supported on " + GOARCH)
274 275 276 277 278 279 280
		}

	case TYPE_REGREG:
		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))

	case TYPE_REGREG2:
		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
281 282 283

	case TYPE_REGLIST:
		str = regListConv(int(a.Offset))
284 285 286 287 288
	}

	return str
}

289
func Mconv(a *Addr) string {
290 291 292 293 294 295 296 297 298
	var str string

	switch a.Name {
	default:
		str = fmt.Sprintf("name=%d", a.Name)

	case NAME_NONE:
		switch {
		case a.Reg == REG_NONE:
299
			str = fmt.Sprint(a.Offset)
300 301 302 303 304 305
		case a.Offset == 0:
			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
		case a.Offset != 0:
			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
		}

306
		// Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.
307
	case NAME_EXTERN:
308 309 310 311
		reg := "SB"
		if a.Reg != REG_NONE {
			reg = Rconv(int(a.Reg))
		}
312
		if a.Sym != nil {
313
			str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
314
		} else {
315
			str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
316
		}
317

318
	case NAME_GOTREF:
319 320 321 322
		reg := "SB"
		if a.Reg != REG_NONE {
			reg = Rconv(int(a.Reg))
		}
323
		if a.Sym != nil {
324
			str = fmt.Sprintf("%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
325
		} else {
326
			str = fmt.Sprintf("%s@GOT(%s)", offConv(a.Offset), reg)
327
		}
328

329
	case NAME_STATIC:
330 331 332 333
		reg := "SB"
		if a.Reg != REG_NONE {
			reg = Rconv(int(a.Reg))
		}
334
		if a.Sym != nil {
335
			str = fmt.Sprintf("%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
336
		} else {
337
			str = fmt.Sprintf("<>%s(%s)", offConv(a.Offset), reg)
338
		}
339 340

	case NAME_AUTO:
341 342 343 344
		reg := "SP"
		if a.Reg != REG_NONE {
			reg = Rconv(int(a.Reg))
		}
345
		if a.Sym != nil {
346
			str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
347
		} else {
348
			str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
349 350 351
		}

	case NAME_PARAM:
352 353 354 355
		reg := "FP"
		if a.Reg != REG_NONE {
			reg = Rconv(int(a.Reg))
		}
356
		if a.Sym != nil {
357
			str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
358
		} else {
359
			str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
360 361 362 363 364 365 366 367 368 369 370
		}
	}
	return str
}

func offConv(off int64) string {
	if off == 0 {
		return ""
	}
	return fmt.Sprintf("%+d", off)
}
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390

type regSet struct {
	lo    int
	hi    int
	Rconv func(int) string
}

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

/*
	Each architecture defines a register space as a unique
	integer range.
	Here is the list of architectures and the base of their register spaces.
*/

const (
	// Because of masking operations in the encodings, each register
	// space should start at 0 modulo some power of 2.
391 392 393 394 395 396 397
	RBase386   = 1 * 1024
	RBaseAMD64 = 2 * 1024
	RBaseARM   = 3 * 1024
	RBasePPC64 = 4 * 1024  // range [4k, 8k)
	RBaseARM64 = 8 * 1024  // range [8k, 13k)
	RBaseMIPS  = 13 * 1024 // range [13k, 14k)
	RBaseS390X = 14 * 1024 // range [14k, 15k)
398 399 400
)

// RegisterRegister binds a pretty-printer (Rconv) for register
401
// numbers to a given register number range. Lo is inclusive,
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
// hi exclusive (valid registers are lo through hi-1).
func RegisterRegister(lo, hi int, Rconv func(int) string) {
	regSpace = append(regSpace, regSet{lo, hi, Rconv})
}

func Rconv(reg int) string {
	if reg == REG_NONE {
		return "NONE"
	}
	for i := range regSpace {
		rs := &regSpace[i]
		if rs.lo <= reg && reg < rs.hi {
			return rs.Rconv(reg)
		}
	}
	return fmt.Sprintf("R???%d", reg)
}
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441

func regListConv(list int) string {
	str := ""

	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
		if list&(1<<uint(i)) != 0 {
			if str == "" {
				str += "["
			} else {
				str += ","
			}
			// This is ARM-specific; R10 is g.
			if i == 10 {
				str += "g"
			} else {
				str += fmt.Sprintf("R%d", i)
			}
		}
	}

	str += "]"
	return str
}
442 443

type opSet struct {
444
	lo    As
445 446 447 448 449 450 451 452
	names []string
}

// Not even worth sorting
var aSpace []opSet

// RegisterOpcode binds a list of instruction names
// to a given instruction number range.
453
func RegisterOpcode(lo As, Anames []string) {
454 455 456
	if len(Anames) > AllowedOpCodes {
		panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
	}
457 458 459
	aSpace = append(aSpace, opSet{lo, Anames})
}

460
func (a As) String() string {
461
	if 0 <= a && int(a) < len(Anames) {
462 463 464 465
		return Anames[a]
	}
	for i := range aSpace {
		as := &aSpace[i]
466
		if as.lo <= a && int(a-as.lo) < len(as.names) {
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
			return as.names[a-as.lo]
		}
	}
	return fmt.Sprintf("A???%d", a)
}

var Anames = []string{
	"XXX",
	"CALL",
	"DUFFCOPY",
	"DUFFZERO",
	"END",
	"FUNCDATA",
	"JMP",
	"NOP",
	"PCDATA",
	"RET",
	"TEXT",
	"UNDEF",
}
487 488

func Bool2int(b bool) int {
489 490 491
	// The compiler currently only optimizes this form.
	// See issue 6011.
	var i int
492
	if b {
493 494 495
		i = 1
	} else {
		i = 0
496
	}
497
	return i
498
}