github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/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.assembler file. 4 5 package obj 6 7 import ( 8 "bytes" 9 "fmt" 10 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/abi" 11 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/buildcfg" 12 "io" 13 "strings" 14 ) 15 16 const REG_NONE = 0 17 18 19 func (p *Prog) Line() string { 20 return p.Ctxt.OutermostPos(p.Pos).Format(false, true) 21 } 22 func (p *Prog) InnermostLine(w io.Writer) { 23 p.Ctxt.InnermostPos(p.Pos).WriteTo(w, false, true) 24 } 25 26 27 28 func (p *Prog) InnermostLineNumber() string { 29 return p.Ctxt.InnermostPos(p.Pos).LineNumber() 30 } 31 32 33 34 func (p *Prog) InnermostLineNumberHTML() string { 35 return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML() 36 } 37 38 39 40 func (p *Prog) InnermostFilename() string { 41 42 43 pos := p.Ctxt.InnermostPos(p.Pos) 44 if !pos.IsKnown() { 45 return "<unknown file name>" 46 } 47 return pos.Filename() 48 } 49 50 var armCondCode = []string{ 51 ".EQ", 52 ".NE", 53 ".CS", 54 ".CC", 55 ".MI", 56 ".PL", 57 ".VS", 58 ".VC", 59 ".HI", 60 ".LS", 61 ".GE", 62 ".LT", 63 ".GT", 64 ".LE", 65 "", 66 ".NV", 67 } 68 69 70 const ( 71 C_SCOND = (1 << 4) - 1 72 C_SBIT = 1 << 4 73 C_PBIT = 1 << 5 74 C_WBIT = 1 << 6 75 C_FBIT = 1 << 7 76 C_UBIT = 1 << 7 77 C_SCOND_XOR = 14 78 ) 79 80 81 func CConv(s uint8) string { 82 if s == 0 { 83 return "" 84 } 85 for i := range opSuffixSpace { 86 sset := &opSuffixSpace[i] 87 if sset.arch == buildcfg.GOARCH { 88 return sset.cconv(s) 89 } 90 } 91 return fmt.Sprintf("SC???%d", s) 92 } 93 94 95 func CConvARM(s uint8) string { 96 97 98 99 100 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR] 101 if s&C_SBIT != 0 { 102 sc += ".S" 103 } 104 if s&C_PBIT != 0 { 105 sc += ".P" 106 } 107 if s&C_WBIT != 0 { 108 sc += ".W" 109 } 110 if s&C_UBIT != 0 { 111 sc += ".U" 112 } 113 return sc 114 } 115 116 func (p *Prog) String() string { 117 if p == nil { 118 return "<nil Prog>" 119 } 120 if p.Ctxt == nil { 121 return "<Prog without ctxt>" 122 } 123 return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString()) 124 } 125 126 func (p *Prog) InnermostString(w io.Writer) { 127 if p == nil { 128 io.WriteString(w, "<nil Prog>") 129 return 130 } 131 if p.Ctxt == nil { 132 io.WriteString(w, "<Prog without ctxt>") 133 return 134 } 135 fmt.Fprintf(w, "%.5d (", p.Pc) 136 p.InnermostLine(w) 137 io.WriteString(w, ")\t") 138 p.WriteInstructionString(w) 139 } 140 141 142 143 func (p *Prog) InstructionString() string { 144 buf := new(bytes.Buffer) 145 p.WriteInstructionString(buf) 146 return buf.String() 147 } 148 149 150 151 func (p *Prog) WriteInstructionString(w io.Writer) { 152 if p == nil { 153 io.WriteString(w, "<nil Prog>") 154 return 155 } 156 157 if p.Ctxt == nil { 158 io.WriteString(w, "<Prog without ctxt>") 159 return 160 } 161 162 sc := CConv(p.Scond) 163 164 io.WriteString(w, p.As.String()) 165 io.WriteString(w, sc) 166 sep := "\t" 167 168 if p.From.Type != TYPE_NONE { 169 io.WriteString(w, sep) 170 WriteDconv(w, p, &p.From) 171 sep = ", " 172 } 173 if p.Reg != REG_NONE { 174 175 fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg))) 176 sep = ", " 177 } 178 for i := range p.RestArgs { 179 if p.RestArgs[i].Pos == Source { 180 io.WriteString(w, sep) 181 WriteDconv(w, p, &p.RestArgs[i].Addr) 182 sep = ", " 183 } 184 } 185 186 if p.As == ATEXT { 187 188 189 190 191 s := p.From.Sym.TextAttrString() 192 if s != "" { 193 fmt.Fprintf(w, "%s%s", sep, s) 194 sep = ", " 195 } 196 } 197 if p.To.Type != TYPE_NONE { 198 io.WriteString(w, sep) 199 WriteDconv(w, p, &p.To) 200 sep = ", " 201 } 202 if p.RegTo2 != REG_NONE { 203 fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2))) 204 } 205 for i := range p.RestArgs { 206 if p.RestArgs[i].Pos == Destination { 207 io.WriteString(w, sep) 208 WriteDconv(w, p, &p.RestArgs[i].Addr) 209 sep = ", " 210 } 211 } 212 } 213 214 func (ctxt *Link) NewProg() *Prog { 215 p := new(Prog) 216 p.Ctxt = ctxt 217 return p 218 } 219 220 func (ctxt *Link) CanReuseProgs() bool { 221 return ctxt.Debugasm == 0 222 } 223 224 225 226 func Dconv(p *Prog, a *Addr) string { 227 buf := new(bytes.Buffer) 228 writeDconv(buf, p, a, false) 229 return buf.String() 230 } 231 232 233 234 235 func DconvWithABIDetail(p *Prog, a *Addr) string { 236 buf := new(bytes.Buffer) 237 writeDconv(buf, p, a, true) 238 return buf.String() 239 } 240 241 242 243 func WriteDconv(w io.Writer, p *Prog, a *Addr) { 244 writeDconv(w, p, a, false) 245 } 246 247 func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) { 248 switch a.Type { 249 default: 250 fmt.Fprintf(w, "type=%d", a.Type) 251 252 case TYPE_NONE: 253 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil { 254 a.WriteNameTo(w) 255 fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg))) 256 } 257 258 case TYPE_REG: 259 260 261 262 263 if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) { 264 fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg))) 265 return 266 } 267 268 if a.Name != NAME_NONE || a.Sym != nil { 269 a.WriteNameTo(w) 270 fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg))) 271 } else { 272 io.WriteString(w, Rconv(int(a.Reg))) 273 } 274 if (RBaseARM64+1<<10+1<<9) <= a.Reg && 275 a.Reg < (RBaseARM64+1<<11) { 276 fmt.Fprintf(w, "[%d]", a.Index) 277 } 278 279 case TYPE_BRANCH: 280 if a.Sym != nil { 281 fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail)) 282 } else if a.Target() != nil { 283 fmt.Fprint(w, a.Target().Pc) 284 } else { 285 fmt.Fprintf(w, "%d(PC)", a.Offset) 286 } 287 288 case TYPE_INDIR: 289 io.WriteString(w, "*") 290 a.writeNameTo(w, abiDetail) 291 292 case TYPE_MEM: 293 a.WriteNameTo(w) 294 if a.Index != REG_NONE { 295 if a.Scale == 0 { 296 297 fmt.Fprintf(w, "(%v)", Rconv(int(a.Index))) 298 } else { 299 fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale)) 300 } 301 } 302 303 case TYPE_CONST: 304 io.WriteString(w, "$") 305 a.WriteNameTo(w) 306 if a.Reg != 0 { 307 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg))) 308 } 309 310 case TYPE_TEXTSIZE: 311 if a.Val.(int32) == abi.ArgsSizeUnknown { 312 fmt.Fprintf(w, "$%d", a.Offset) 313 } else { 314 fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32)) 315 } 316 317 case TYPE_FCONST: 318 str := fmt.Sprintf("%.17g", a.Val.(float64)) 319 320 if !strings.ContainsAny(str, ".e") { 321 str += ".0" 322 } 323 fmt.Fprintf(w, "$(%s)", str) 324 325 case TYPE_SCONST: 326 fmt.Fprintf(w, "$%q", a.Val.(string)) 327 328 case TYPE_ADDR: 329 io.WriteString(w, "$") 330 a.writeNameTo(w, abiDetail) 331 332 case TYPE_SHIFT: 333 v := int(a.Offset) 334 ops := "<<>>->@>" 335 switch buildcfg.GOARCH { 336 case "arm": 337 op := ops[((v>>5)&3)<<1:] 338 if v&(1<<4) != 0 { 339 fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) 340 } else { 341 fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31) 342 } 343 if a.Reg != 0 { 344 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg))) 345 } 346 case "arm64": 347 op := ops[((v>>22)&3)<<1:] 348 r := (v >> 16) & 31 349 fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63) 350 default: 351 panic("TYPE_SHIFT is not supported on " + buildcfg.GOARCH) 352 } 353 354 case TYPE_REGREG: 355 fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset))) 356 357 case TYPE_REGREG2: 358 fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg))) 359 360 case TYPE_REGLIST: 361 io.WriteString(w, RLconv(a.Offset)) 362 363 case TYPE_SPECIAL: 364 io.WriteString(w, SPCconv(a.Offset)) 365 } 366 } 367 368 func (a *Addr) WriteNameTo(w io.Writer) { 369 a.writeNameTo(w, false) 370 } 371 372 func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) { 373 374 switch a.Name { 375 default: 376 fmt.Fprintf(w, "name=%d", a.Name) 377 378 case NAME_NONE: 379 switch { 380 case a.Reg == REG_NONE: 381 fmt.Fprint(w, a.Offset) 382 case a.Offset == 0: 383 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg))) 384 case a.Offset != 0: 385 fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg))) 386 } 387 388 389 case NAME_EXTERN: 390 reg := "SB" 391 if a.Reg != REG_NONE { 392 reg = Rconv(int(a.Reg)) 393 } 394 if a.Sym != nil { 395 fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg) 396 } else { 397 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) 398 } 399 400 case NAME_GOTREF: 401 reg := "SB" 402 if a.Reg != REG_NONE { 403 reg = Rconv(int(a.Reg)) 404 } 405 if a.Sym != nil { 406 fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg) 407 } else { 408 fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg) 409 } 410 411 case NAME_STATIC: 412 reg := "SB" 413 if a.Reg != REG_NONE { 414 reg = Rconv(int(a.Reg)) 415 } 416 if a.Sym != nil { 417 fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 418 } else { 419 fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg) 420 } 421 422 case NAME_AUTO: 423 reg := "SP" 424 if a.Reg != REG_NONE { 425 reg = Rconv(int(a.Reg)) 426 } 427 if a.Sym != nil { 428 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 429 } else { 430 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) 431 } 432 433 case NAME_PARAM: 434 reg := "FP" 435 if a.Reg != REG_NONE { 436 reg = Rconv(int(a.Reg)) 437 } 438 if a.Sym != nil { 439 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 440 } else { 441 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) 442 } 443 case NAME_TOCREF: 444 reg := "SB" 445 if a.Reg != REG_NONE { 446 reg = Rconv(int(a.Reg)) 447 } 448 if a.Sym != nil { 449 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 450 } else { 451 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg) 452 } 453 } 454 } 455 456 func offConv(off int64) string { 457 if off == 0 { 458 return "" 459 } 460 return fmt.Sprintf("%+d", off) 461 } 462 463 464 465 466 467 468 469 type opSuffixSet struct { 470 arch string 471 cconv func(suffix uint8) string 472 } 473 474 var opSuffixSpace []opSuffixSet 475 476 477 478 479 480 func RegisterOpSuffix(arch string, cconv func(uint8) string) { 481 opSuffixSpace = append(opSuffixSpace, opSuffixSet{ 482 arch: arch, 483 cconv: cconv, 484 }) 485 } 486 487 type regSet struct { 488 lo int 489 hi int 490 Rconv func(int) string 491 } 492 493 494 495 var regSpace []regSet 496 497 498 499 const ( 500 501 502 RBase386 = 1 * 1024 503 RBaseAMD64 = 2 * 1024 504 RBaseARM = 3 * 1024 505 RBasePPC64 = 4 * 1024 506 RBaseARM64 = 8 * 1024 507 RBaseMIPS = 13 * 1024 508 RBaseS390X = 14 * 1024 509 RBaseRISCV = 15 * 1024 510 RBaseWasm = 16 * 1024 511 RBaseLOONG64 = 17 * 1024 512 ) 513 514 515 516 517 func RegisterRegister(lo, hi int, Rconv func(int) string) { 518 regSpace = append(regSpace, regSet{lo, hi, Rconv}) 519 } 520 521 func Rconv(reg int) string { 522 if reg == REG_NONE { 523 return "NONE" 524 } 525 for i := range regSpace { 526 rs := ®Space[i] 527 if rs.lo <= reg && reg < rs.hi { 528 return rs.Rconv(reg) 529 } 530 } 531 return fmt.Sprintf("R???%d", reg) 532 } 533 534 type regListSet struct { 535 lo int64 536 hi int64 537 RLconv func(int64) string 538 } 539 540 var regListSpace []regListSet 541 542 543 544 const ( 545 RegListARMLo = 0 546 RegListARMHi = 1 << 16 547 548 549 RegListARM64Lo = 1 << 60 550 RegListARM64Hi = 1<<61 - 1 551 552 553 RegListX86Lo = 1 << 61 554 RegListX86Hi = 1<<62 - 1 555 ) 556 557 558 559 560 func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) { 561 regListSpace = append(regListSpace, regListSet{lo, hi, rlconv}) 562 } 563 564 func RLconv(list int64) string { 565 for i := range regListSpace { 566 rls := ®ListSpace[i] 567 if rls.lo <= list && list < rls.hi { 568 return rls.RLconv(list) 569 } 570 } 571 return fmt.Sprintf("RL???%d", list) 572 } 573 574 575 type spcSet struct { 576 lo int64 577 hi int64 578 SPCconv func(int64) string 579 } 580 581 var spcSpace []spcSet 582 583 584 585 586 func RegisterSpecialOperands(lo, hi int64, rlconv func(int64) string) { 587 spcSpace = append(spcSpace, spcSet{lo, hi, rlconv}) 588 } 589 590 591 func SPCconv(spc int64) string { 592 for i := range spcSpace { 593 spcs := &spcSpace[i] 594 if spcs.lo <= spc && spc < spcs.hi { 595 return spcs.SPCconv(spc) 596 } 597 } 598 return fmt.Sprintf("SPC???%d", spc) 599 } 600 601 type opSet struct { 602 lo As 603 names []string 604 } 605 606 607 var aSpace []opSet 608 609 610 611 func RegisterOpcode(lo As, Anames []string) { 612 if len(Anames) > AllowedOpCodes { 613 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes)) 614 } 615 aSpace = append(aSpace, opSet{lo, Anames}) 616 } 617 618 func (a As) String() string { 619 if 0 <= a && int(a) < len(Anames) { 620 return Anames[a] 621 } 622 for i := range aSpace { 623 as := &aSpace[i] 624 if as.lo <= a && int(a-as.lo) < len(as.names) { 625 return as.names[a-as.lo] 626 } 627 } 628 return fmt.Sprintf("A???%d", a) 629 } 630 631 var Anames = []string{ 632 "XXX", 633 "CALL", 634 "DUFFCOPY", 635 "DUFFZERO", 636 "END", 637 "FUNCDATA", 638 "JMP", 639 "NOP", 640 "PCALIGN", 641 "PCDATA", 642 "RET", 643 "GETCALLERPC", 644 "TEXT", 645 "UNDEF", 646 } 647 648 func Bool2int(b bool) int { 649 650 651 var i int 652 if b { 653 i = 1 654 } else { 655 i = 0 656 } 657 return i 658 } 659 660 func abiDecorate(a *Addr, abiDetail bool) string { 661 if !abiDetail || a.Sym == nil { 662 return "" 663 } 664 return fmt.Sprintf("<%s>", a.Sym.ABI()) 665 }