github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 10 "fmt" 11 "strings" 12 ) 13 14 const REG_NONE = 0 15 16 // Line returns a string containing the filename and line number for p 17 func (p *Prog) Line() string { 18 return p.Ctxt.OutermostPos(p.Pos).Format(false, true) 19 } 20 func (p *Prog) InnermostLine() string { 21 return p.Ctxt.InnermostPos(p.Pos).Format(false, true) 22 } 23 24 // InnermostLineNumber returns a string containing the line number for the 25 // innermost inlined function (if any inlining) at p's position 26 func (p *Prog) InnermostLineNumber() string { 27 return p.Ctxt.InnermostPos(p.Pos).LineNumber() 28 } 29 30 // InnermostLineNumberHTML returns a string containing the line number for the 31 // innermost inlined function (if any inlining) at p's position 32 func (p *Prog) InnermostLineNumberHTML() string { 33 return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML() 34 } 35 36 // InnermostFilename returns a string containing the innermost 37 // (in inlining) filename at p's position 38 func (p *Prog) InnermostFilename() string { 39 // TODO For now, this is only used for debugging output, and if we need more/better information, it might change. 40 // An example of what we might want to see is the full stack of positions for inlined code, so we get some visibility into what is recorded there. 41 pos := p.Ctxt.InnermostPos(p.Pos) 42 if !pos.IsKnown() { 43 return "<unknown file name>" 44 } 45 return pos.Filename() 46 } 47 48 var armCondCode = []string{ 49 ".EQ", 50 ".NE", 51 ".CS", 52 ".CC", 53 ".MI", 54 ".PL", 55 ".VS", 56 ".VC", 57 ".HI", 58 ".LS", 59 ".GE", 60 ".LT", 61 ".GT", 62 ".LE", 63 "", 64 ".NV", 65 } 66 67 /* ARM scond byte */ 68 const ( 69 C_SCOND = (1 << 4) - 1 70 C_SBIT = 1 << 4 71 C_PBIT = 1 << 5 72 C_WBIT = 1 << 6 73 C_FBIT = 1 << 7 74 C_UBIT = 1 << 7 75 C_SCOND_XOR = 14 76 ) 77 78 // CConv formats opcode suffix bits (Prog.Scond). 79 func CConv(s uint8) string { 80 if s == 0 { 81 return "" 82 } 83 for i := range opSuffixSpace { 84 sset := &opSuffixSpace[i] 85 if sset.arch == objabi.GOARCH { 86 return sset.cconv(s) 87 } 88 } 89 return fmt.Sprintf("SC???%d", s) 90 } 91 92 // CConvARM formats ARM opcode suffix bits (mostly condition codes). 93 func CConvARM(s uint8) string { 94 // TODO: could be great to move suffix-related things into 95 // ARM asm backends some day. 96 // obj/x86 can be used as an example. 97 98 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR] 99 if s&C_SBIT != 0 { 100 sc += ".S" 101 } 102 if s&C_PBIT != 0 { 103 sc += ".P" 104 } 105 if s&C_WBIT != 0 { 106 sc += ".W" 107 } 108 if s&C_UBIT != 0 { /* ambiguous with FBIT */ 109 sc += ".U" 110 } 111 return sc 112 } 113 114 func (p *Prog) String() string { 115 if p == nil { 116 return "<nil Prog>" 117 } 118 if p.Ctxt == nil { 119 return "<Prog without ctxt>" 120 } 121 return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString()) 122 } 123 124 func (p *Prog) InnermostString() string { 125 if p == nil { 126 return "<nil Prog>" 127 } 128 if p.Ctxt == nil { 129 return "<Prog without ctxt>" 130 } 131 return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.InnermostLine(), p.InstructionString()) 132 } 133 134 // InstructionString returns a string representation of the instruction without preceding 135 // program counter or file and line number. 136 func (p *Prog) InstructionString() string { 137 if p == nil { 138 return "<nil Prog>" 139 } 140 141 if p.Ctxt == nil { 142 return "<Prog without ctxt>" 143 } 144 145 sc := CConv(p.Scond) 146 147 var buf bytes.Buffer 148 149 fmt.Fprintf(&buf, "%v%s", p.As, sc) 150 sep := "\t" 151 152 if p.From.Type != TYPE_NONE { 153 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From)) 154 sep = ", " 155 } 156 if p.Reg != REG_NONE { 157 // Should not happen but might as well show it if it does. 158 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg))) 159 sep = ", " 160 } 161 for i := range p.RestArgs { 162 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.RestArgs[i])) 163 sep = ", " 164 } 165 166 if p.As == ATEXT { 167 // If there are attributes, print them. Otherwise, skip the comma. 168 // In short, print one of these two: 169 // TEXT foo(SB), DUPOK|NOSPLIT, $0 170 // TEXT foo(SB), $0 171 s := p.From.Sym.Attribute.TextAttrString() 172 if s != "" { 173 fmt.Fprintf(&buf, "%s%s", sep, s) 174 sep = ", " 175 } 176 } 177 if p.To.Type != TYPE_NONE { 178 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) 179 } 180 if p.RegTo2 != REG_NONE { 181 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2))) 182 } 183 return buf.String() 184 } 185 186 func (ctxt *Link) NewProg() *Prog { 187 p := new(Prog) 188 p.Ctxt = ctxt 189 return p 190 } 191 192 func (ctxt *Link) CanReuseProgs() bool { 193 return ctxt.Debugasm == 0 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 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) { 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 if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg && 224 a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ { 225 str += fmt.Sprintf("[%d]", a.Index) 226 } 227 228 case TYPE_BRANCH: 229 if a.Sym != nil { 230 str = fmt.Sprintf("%s(SB)", a.Sym.Name) 231 } else if p != nil && p.Pcond != nil { 232 str = fmt.Sprint(p.Pcond.Pc) 233 } else if a.Val != nil { 234 str = fmt.Sprint(a.Val.(*Prog).Pc) 235 } else { 236 str = fmt.Sprintf("%d(PC)", a.Offset) 237 } 238 239 case TYPE_INDIR: 240 str = fmt.Sprintf("*%s", Mconv(a)) 241 242 case TYPE_MEM: 243 str = Mconv(a) 244 if a.Index != REG_NONE { 245 if a.Scale == 0 { 246 // arm64 shifted or extended register offset, scale = 0. 247 str += fmt.Sprintf("(%v)", Rconv(int(a.Index))) 248 } else { 249 str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale)) 250 } 251 } 252 253 case TYPE_CONST: 254 if a.Reg != 0 { 255 str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg))) 256 } else { 257 str = fmt.Sprintf("$%v", Mconv(a)) 258 } 259 260 case TYPE_TEXTSIZE: 261 if a.Val.(int32) == objabi.ArgsSizeUnknown { 262 str = fmt.Sprintf("$%d", a.Offset) 263 } else { 264 str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32)) 265 } 266 267 case TYPE_FCONST: 268 str = fmt.Sprintf("%.17g", a.Val.(float64)) 269 // Make sure 1 prints as 1.0 270 if !strings.ContainsAny(str, ".e") { 271 str += ".0" 272 } 273 str = fmt.Sprintf("$(%s)", str) 274 275 case TYPE_SCONST: 276 str = fmt.Sprintf("$%q", a.Val.(string)) 277 278 case TYPE_ADDR: 279 str = fmt.Sprintf("$%s", Mconv(a)) 280 281 case TYPE_SHIFT: 282 v := int(a.Offset) 283 ops := "<<>>->@>" 284 switch objabi.GOARCH { 285 case "arm": 286 op := ops[((v>>5)&3)<<1:] 287 if v&(1<<4) != 0 { 288 str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) 289 } else { 290 str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31) 291 } 292 if a.Reg != 0 { 293 str += fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 294 } 295 case "arm64": 296 op := ops[((v>>22)&3)<<1:] 297 r := (v >> 16) & 31 298 str = fmt.Sprintf("%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63) 299 default: 300 panic("TYPE_SHIFT is not supported on " + objabi.GOARCH) 301 } 302 303 case TYPE_REGREG: 304 str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset))) 305 306 case TYPE_REGREG2: 307 str = fmt.Sprintf("%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg))) 308 309 case TYPE_REGLIST: 310 str = RLconv(a.Offset) 311 } 312 313 return str 314 } 315 316 func Mconv(a *Addr) string { 317 var str string 318 319 switch a.Name { 320 default: 321 str = fmt.Sprintf("name=%d", a.Name) 322 323 case NAME_NONE: 324 switch { 325 case a.Reg == REG_NONE: 326 str = fmt.Sprint(a.Offset) 327 case a.Offset == 0: 328 str = fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 329 case a.Offset != 0: 330 str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg))) 331 } 332 333 // Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type. 334 case NAME_EXTERN: 335 reg := "SB" 336 if a.Reg != REG_NONE { 337 reg = Rconv(int(a.Reg)) 338 } 339 if a.Sym != nil { 340 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 341 } else { 342 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 343 } 344 345 case NAME_GOTREF: 346 reg := "SB" 347 if a.Reg != REG_NONE { 348 reg = Rconv(int(a.Reg)) 349 } 350 if a.Sym != nil { 351 str = fmt.Sprintf("%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg) 352 } else { 353 str = fmt.Sprintf("%s@GOT(%s)", offConv(a.Offset), reg) 354 } 355 356 case NAME_STATIC: 357 reg := "SB" 358 if a.Reg != REG_NONE { 359 reg = Rconv(int(a.Reg)) 360 } 361 if a.Sym != nil { 362 str = fmt.Sprintf("%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 363 } else { 364 str = fmt.Sprintf("<>%s(%s)", offConv(a.Offset), reg) 365 } 366 367 case NAME_AUTO: 368 reg := "SP" 369 if a.Reg != REG_NONE { 370 reg = Rconv(int(a.Reg)) 371 } 372 if a.Sym != nil { 373 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 374 } else { 375 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 376 } 377 378 case NAME_PARAM: 379 reg := "FP" 380 if a.Reg != REG_NONE { 381 reg = Rconv(int(a.Reg)) 382 } 383 if a.Sym != nil { 384 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 385 } else { 386 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 387 } 388 case NAME_TOCREF: 389 reg := "SB" 390 if a.Reg != REG_NONE { 391 reg = Rconv(int(a.Reg)) 392 } 393 if a.Sym != nil { 394 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 395 } else { 396 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 397 } 398 399 } 400 return str 401 } 402 403 func offConv(off int64) string { 404 if off == 0 { 405 return "" 406 } 407 return fmt.Sprintf("%+d", off) 408 } 409 410 // opSuffixSet is like regListSet, but for opcode suffixes. 411 // 412 // Unlike some other similar structures, uint8 space is not 413 // divided by its own values set (because there are only 256 of them). 414 // Instead, every arch may interpret/format all 8 bits as they like, 415 // as long as they register proper cconv function for it. 416 type opSuffixSet struct { 417 arch string 418 cconv func(suffix uint8) string 419 } 420 421 var opSuffixSpace []opSuffixSet 422 423 // RegisterOpSuffix assigns cconv function for formatting opcode suffixes 424 // when compiling for GOARCH=arch. 425 // 426 // cconv is never called with 0 argument. 427 func RegisterOpSuffix(arch string, cconv func(uint8) string) { 428 opSuffixSpace = append(opSuffixSpace, opSuffixSet{ 429 arch: arch, 430 cconv: cconv, 431 }) 432 } 433 434 type regSet struct { 435 lo int 436 hi int 437 Rconv func(int) string 438 } 439 440 // Few enough architectures that a linear scan is fastest. 441 // Not even worth sorting. 442 var regSpace []regSet 443 444 /* 445 Each architecture defines a register space as a unique 446 integer range. 447 Here is the list of architectures and the base of their register spaces. 448 */ 449 450 const ( 451 // Because of masking operations in the encodings, each register 452 // space should start at 0 modulo some power of 2. 453 RBase386 = 1 * 1024 454 RBaseAMD64 = 2 * 1024 455 RBaseARM = 3 * 1024 456 RBasePPC64 = 4 * 1024 // range [4k, 8k) 457 RBaseARM64 = 8 * 1024 // range [8k, 13k) 458 RBaseMIPS = 13 * 1024 // range [13k, 14k) 459 RBaseS390X = 14 * 1024 // range [14k, 15k) 460 RBaseRISCV = 15 * 1024 // range [15k, 16k) 461 RBaseWasm = 16 * 1024 462 ) 463 464 // RegisterRegister binds a pretty-printer (Rconv) for register 465 // numbers to a given register number range. Lo is inclusive, 466 // hi exclusive (valid registers are lo through hi-1). 467 func RegisterRegister(lo, hi int, Rconv func(int) string) { 468 regSpace = append(regSpace, regSet{lo, hi, Rconv}) 469 } 470 471 func Rconv(reg int) string { 472 if reg == REG_NONE { 473 return "NONE" 474 } 475 for i := range regSpace { 476 rs := ®Space[i] 477 if rs.lo <= reg && reg < rs.hi { 478 return rs.Rconv(reg) 479 } 480 } 481 return fmt.Sprintf("R???%d", reg) 482 } 483 484 type regListSet struct { 485 lo int64 486 hi int64 487 RLconv func(int64) string 488 } 489 490 var regListSpace []regListSet 491 492 // Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its 493 // arch-specific register list numbers. 494 const ( 495 RegListARMLo = 0 496 RegListARMHi = 1 << 16 497 498 // arm64 uses the 60th bit to differentiate from other archs 499 RegListARM64Lo = 1 << 60 500 RegListARM64Hi = 1<<61 - 1 501 502 // x86 uses the 61th bit to differentiate from other archs 503 RegListX86Lo = 1 << 61 504 RegListX86Hi = 1<<62 - 1 505 ) 506 507 // RegisterRegisterList binds a pretty-printer (RLconv) for register list 508 // numbers to a given register list number range. Lo is inclusive, 509 // hi exclusive (valid register list are lo through hi-1). 510 func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) { 511 regListSpace = append(regListSpace, regListSet{lo, hi, rlconv}) 512 } 513 514 func RLconv(list int64) string { 515 for i := range regListSpace { 516 rls := ®ListSpace[i] 517 if rls.lo <= list && list < rls.hi { 518 return rls.RLconv(list) 519 } 520 } 521 return fmt.Sprintf("RL???%d", list) 522 } 523 524 type opSet struct { 525 lo As 526 names []string 527 } 528 529 // Not even worth sorting 530 var aSpace []opSet 531 532 // RegisterOpcode binds a list of instruction names 533 // to a given instruction number range. 534 func RegisterOpcode(lo As, Anames []string) { 535 if len(Anames) > AllowedOpCodes { 536 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes)) 537 } 538 aSpace = append(aSpace, opSet{lo, Anames}) 539 } 540 541 func (a As) String() string { 542 if 0 <= a && int(a) < len(Anames) { 543 return Anames[a] 544 } 545 for i := range aSpace { 546 as := &aSpace[i] 547 if as.lo <= a && int(a-as.lo) < len(as.names) { 548 return as.names[a-as.lo] 549 } 550 } 551 return fmt.Sprintf("A???%d", a) 552 } 553 554 var Anames = []string{ 555 "XXX", 556 "CALL", 557 "DUFFCOPY", 558 "DUFFZERO", 559 "END", 560 "FUNCDATA", 561 "JMP", 562 "NOP", 563 "PCALIGN", 564 "PCDATA", 565 "RET", 566 "GETCALLERPC", 567 "TEXT", 568 "UNDEF", 569 } 570 571 func Bool2int(b bool) int { 572 // The compiler currently only optimizes this form. 573 // See issue 6011. 574 var i int 575 if b { 576 i = 1 577 } else { 578 i = 0 579 } 580 return i 581 }