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