github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/internal/obj/util.go (about) 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 "fmt" 10 "log" 11 "os" 12 "strings" 13 "time" 14 ) 15 16 const REG_NONE = 0 17 18 var start time.Time 19 20 func Cputime() float64 { 21 if start.IsZero() { 22 start = time.Now() 23 } 24 return time.Since(start).Seconds() 25 } 26 27 func envOr(key, value string) string { 28 if x := os.Getenv(key); x != "" { 29 return x 30 } 31 return value 32 } 33 34 func Getgoroot() string { 35 return envOr("GOROOT", defaultGOROOT) 36 } 37 38 func Getgoarch() string { 39 return envOr("GOARCH", defaultGOARCH) 40 } 41 42 func Getgoos() string { 43 return envOr("GOOS", defaultGOOS) 44 } 45 46 func Getgoarm() int32 { 47 switch v := envOr("GOARM", defaultGOARM); v { 48 case "5": 49 return 5 50 case "6": 51 return 6 52 case "7": 53 return 7 54 } 55 // Fail here, rather than validate at multiple call sites. 56 log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.") 57 panic("unreachable") 58 } 59 60 func Getgo386() string { 61 // Validated by cmd/compile. 62 return envOr("GO386", defaultGO386) 63 } 64 65 func Getgoextlinkenabled() string { 66 return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED) 67 } 68 69 func Getgoversion() string { 70 return version 71 } 72 73 func (p *Prog) Line() string { 74 return p.Ctxt.LineHist.LineString(int(p.Lineno)) 75 } 76 77 var armCondCode = []string{ 78 ".EQ", 79 ".NE", 80 ".CS", 81 ".CC", 82 ".MI", 83 ".PL", 84 ".VS", 85 ".VC", 86 ".HI", 87 ".LS", 88 ".GE", 89 ".LT", 90 ".GT", 91 ".LE", 92 "", 93 ".NV", 94 } 95 96 /* ARM scond byte */ 97 const ( 98 C_SCOND = (1 << 4) - 1 99 C_SBIT = 1 << 4 100 C_PBIT = 1 << 5 101 C_WBIT = 1 << 6 102 C_FBIT = 1 << 7 103 C_UBIT = 1 << 7 104 C_SCOND_XOR = 14 105 ) 106 107 // CConv formats ARM condition codes. 108 func CConv(s uint8) string { 109 if s == 0 { 110 return "" 111 } 112 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR] 113 if s&C_SBIT != 0 { 114 sc += ".S" 115 } 116 if s&C_PBIT != 0 { 117 sc += ".P" 118 } 119 if s&C_WBIT != 0 { 120 sc += ".W" 121 } 122 if s&C_UBIT != 0 { /* ambiguous with FBIT */ 123 sc += ".U" 124 } 125 return sc 126 } 127 128 func (p *Prog) String() string { 129 if p == nil { 130 return "<nil Prog>" 131 } 132 133 if p.Ctxt == nil { 134 return "<Prog without ctxt>" 135 } 136 137 sc := CConv(p.Scond) 138 139 var buf bytes.Buffer 140 141 fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc) 142 sep := "\t" 143 quadOpAmd64 := p.RegTo2 == -1 144 if quadOpAmd64 { 145 fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset) 146 sep = ", " 147 } 148 if p.From.Type != TYPE_NONE { 149 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From)) 150 sep = ", " 151 } 152 if p.Reg != REG_NONE { 153 // Should not happen but might as well show it if it does. 154 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg))) 155 sep = ", " 156 } 157 if p.From3Type() != TYPE_NONE { 158 if p.From3.Type == TYPE_CONST && (p.As == ATEXT || p.As == AGLOBL) { 159 // Special case - omit $. 160 fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset) 161 } else if quadOpAmd64 { 162 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg))) 163 } else { 164 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3)) 165 } 166 sep = ", " 167 } 168 if p.To.Type != TYPE_NONE { 169 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) 170 } 171 if p.RegTo2 != REG_NONE && !quadOpAmd64 { 172 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2))) 173 } 174 return buf.String() 175 } 176 177 func (ctxt *Link) NewProg() *Prog { 178 var p *Prog 179 if i := ctxt.allocIdx; i < len(ctxt.progs) { 180 p = &ctxt.progs[i] 181 ctxt.allocIdx = i + 1 182 } else { 183 p = new(Prog) // should be the only call to this; all others should use ctxt.NewProg 184 } 185 p.Ctxt = ctxt 186 return p 187 } 188 func (ctxt *Link) freeProgs() { 189 s := ctxt.progs[:ctxt.allocIdx] 190 for i := range s { 191 s[i] = Prog{} 192 } 193 ctxt.allocIdx = 0 194 } 195 196 func (ctxt *Link) Line(n int) string { 197 return ctxt.LineHist.LineString(n) 198 } 199 200 func Getcallerpc(interface{}) uintptr { 201 return 1 202 } 203 204 func (ctxt *Link) Dconv(a *Addr) string { 205 return Dconv(nil, a) 206 } 207 208 func Dconv(p *Prog, a *Addr) string { 209 var str string 210 211 switch a.Type { 212 default: 213 str = fmt.Sprintf("type=%d", a.Type) 214 215 case TYPE_NONE: 216 str = "" 217 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil { 218 str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg))) 219 } 220 221 case TYPE_REG: 222 // TODO(rsc): This special case is for x86 instructions like 223 // PINSRQ CX,$1,X6 224 // where the $1 is included in the p->to Addr. 225 // Move into a new field. 226 if a.Offset != 0 { 227 str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg))) 228 break 229 } 230 231 str = Rconv(int(a.Reg)) 232 if a.Name != NAME_NONE || a.Sym != nil { 233 str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg))) 234 } 235 236 case TYPE_BRANCH: 237 if a.Sym != nil { 238 str = fmt.Sprintf("%s(SB)", a.Sym.Name) 239 } else if p != nil && p.Pcond != nil { 240 str = fmt.Sprint(p.Pcond.Pc) 241 } else if a.Val != nil { 242 str = fmt.Sprint(a.Val.(*Prog).Pc) 243 } else { 244 str = fmt.Sprintf("%d(PC)", a.Offset) 245 } 246 247 case TYPE_INDIR: 248 str = fmt.Sprintf("*%s", Mconv(a)) 249 250 case TYPE_MEM: 251 str = Mconv(a) 252 if a.Index != REG_NONE { 253 str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale)) 254 } 255 if p != nil && p.As == ATYPE && a.Gotype != nil { 256 str += fmt.Sprintf("%s", a.Gotype.Name) 257 } 258 259 case TYPE_CONST: 260 if a.Reg != 0 { 261 str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg))) 262 } else { 263 str = fmt.Sprintf("$%v", Mconv(a)) 264 } 265 266 case TYPE_TEXTSIZE: 267 if a.Val.(int32) == ArgsSizeUnknown { 268 str = fmt.Sprintf("$%d", a.Offset) 269 } else { 270 str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32)) 271 } 272 273 case TYPE_FCONST: 274 str = fmt.Sprintf("%.17g", a.Val.(float64)) 275 // Make sure 1 prints as 1.0 276 if !strings.ContainsAny(str, ".e") { 277 str += ".0" 278 } 279 str = fmt.Sprintf("$(%s)", str) 280 281 case TYPE_SCONST: 282 str = fmt.Sprintf("$%q", a.Val.(string)) 283 284 case TYPE_ADDR: 285 str = fmt.Sprintf("$%s", Mconv(a)) 286 287 case TYPE_SHIFT: 288 v := int(a.Offset) 289 ops := "<<>>->@>" 290 switch goarch := Getgoarch(); goarch { 291 case "arm": 292 op := ops[((v>>5)&3)<<1:] 293 if v&(1<<4) != 0 { 294 str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) 295 } else { 296 str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31) 297 } 298 if a.Reg != 0 { 299 str += fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 300 } 301 case "arm64": 302 op := ops[((v>>22)&3)<<1:] 303 str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63) 304 default: 305 panic("TYPE_SHIFT is not supported on " + goarch) 306 } 307 308 case TYPE_REGREG: 309 str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset))) 310 311 case TYPE_REGREG2: 312 str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset))) 313 314 case TYPE_REGLIST: 315 str = regListConv(int(a.Offset)) 316 } 317 318 return str 319 } 320 321 func Mconv(a *Addr) string { 322 var str string 323 324 switch a.Name { 325 default: 326 str = fmt.Sprintf("name=%d", a.Name) 327 328 case NAME_NONE: 329 switch { 330 case a.Reg == REG_NONE: 331 str = fmt.Sprint(a.Offset) 332 case a.Offset == 0: 333 str = fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 334 case a.Offset != 0: 335 str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg))) 336 } 337 338 case NAME_EXTERN: 339 if a.Sym != nil { 340 str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset)) 341 } else { 342 str = fmt.Sprintf("%s(SB)", offConv(a.Offset)) 343 } 344 345 case NAME_GOTREF: 346 if a.Sym != nil { 347 str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset)) 348 } else { 349 str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset)) 350 } 351 352 case NAME_STATIC: 353 if a.Sym != nil { 354 str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset)) 355 } else { 356 str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset)) 357 } 358 359 case NAME_AUTO: 360 if a.Sym != nil { 361 str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset)) 362 } else { 363 str = fmt.Sprintf("%s(SP)", offConv(a.Offset)) 364 } 365 366 case NAME_PARAM: 367 if a.Sym != nil { 368 str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset)) 369 } else { 370 str = fmt.Sprintf("%s(FP)", offConv(a.Offset)) 371 } 372 } 373 return str 374 } 375 376 func offConv(off int64) string { 377 if off == 0 { 378 return "" 379 } 380 return fmt.Sprintf("%+d", off) 381 } 382 383 type regSet struct { 384 lo int 385 hi int 386 Rconv func(int) string 387 } 388 389 // Few enough architectures that a linear scan is fastest. 390 // Not even worth sorting. 391 var regSpace []regSet 392 393 /* 394 Each architecture defines a register space as a unique 395 integer range. 396 Here is the list of architectures and the base of their register spaces. 397 */ 398 399 const ( 400 // Because of masking operations in the encodings, each register 401 // space should start at 0 modulo some power of 2. 402 RBase386 = 1 * 1024 403 RBaseAMD64 = 2 * 1024 404 RBaseARM = 3 * 1024 405 RBasePPC64 = 4 * 1024 // range [4k, 8k) 406 RBaseARM64 = 8 * 1024 // range [8k, 13k) 407 RBaseMIPS64 = 13 * 1024 // range [13k, 14k) 408 RBaseS390X = 14 * 1024 // range [14k, 15k) 409 ) 410 411 // RegisterRegister binds a pretty-printer (Rconv) for register 412 // numbers to a given register number range. Lo is inclusive, 413 // hi exclusive (valid registers are lo through hi-1). 414 func RegisterRegister(lo, hi int, Rconv func(int) string) { 415 regSpace = append(regSpace, regSet{lo, hi, Rconv}) 416 } 417 418 func Rconv(reg int) string { 419 if reg == REG_NONE { 420 return "NONE" 421 } 422 for i := range regSpace { 423 rs := ®Space[i] 424 if rs.lo <= reg && reg < rs.hi { 425 return rs.Rconv(reg) 426 } 427 } 428 return fmt.Sprintf("R???%d", reg) 429 } 430 431 func regListConv(list int) string { 432 str := "" 433 434 for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific. 435 if list&(1<<uint(i)) != 0 { 436 if str == "" { 437 str += "[" 438 } else { 439 str += "," 440 } 441 // This is ARM-specific; R10 is g. 442 if i == 10 { 443 str += "g" 444 } else { 445 str += fmt.Sprintf("R%d", i) 446 } 447 } 448 } 449 450 str += "]" 451 return str 452 } 453 454 type opSet struct { 455 lo As 456 names []string 457 } 458 459 // Not even worth sorting 460 var aSpace []opSet 461 462 // RegisterOpcode binds a list of instruction names 463 // to a given instruction number range. 464 func RegisterOpcode(lo As, Anames []string) { 465 if len(Anames) > AllowedOpCodes { 466 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes)) 467 } 468 aSpace = append(aSpace, opSet{lo, Anames}) 469 } 470 471 func (a As) String() string { 472 if 0 <= a && int(a) < len(Anames) { 473 return Anames[a] 474 } 475 for i := range aSpace { 476 as := &aSpace[i] 477 if as.lo <= a && int(a-as.lo) < len(as.names) { 478 return as.names[a-as.lo] 479 } 480 } 481 return fmt.Sprintf("A???%d", a) 482 } 483 484 var Anames = []string{ 485 "XXX", 486 "CALL", 487 "CHECKNIL", 488 "DUFFCOPY", 489 "DUFFZERO", 490 "END", 491 "FUNCDATA", 492 "GLOBL", 493 "JMP", 494 "NOP", 495 "PCDATA", 496 "RET", 497 "TEXT", 498 "TYPE", 499 "UNDEF", 500 "USEFIELD", 501 "VARDEF", 502 "VARKILL", 503 "VARLIVE", 504 } 505 506 func Bool2int(b bool) int { 507 // The compiler currently only optimizes this form. 508 // See issue 6011. 509 var i int 510 if b { 511 i = 1 512 } else { 513 i = 0 514 } 515 return i 516 }