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