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