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