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