github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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 "bytes" 9 "cmd/internal/objabi" 10 "fmt" 11 "strings" 12 ) 13 14 const REG_NONE = 0 15 16 func (p *Prog) Line() string { 17 return p.Ctxt.OutermostPos(p.Pos).Format(false) 18 } 19 20 var armCondCode = []string{ 21 ".EQ", 22 ".NE", 23 ".CS", 24 ".CC", 25 ".MI", 26 ".PL", 27 ".VS", 28 ".VC", 29 ".HI", 30 ".LS", 31 ".GE", 32 ".LT", 33 ".GT", 34 ".LE", 35 "", 36 ".NV", 37 } 38 39 /* ARM scond byte */ 40 const ( 41 C_SCOND = (1 << 4) - 1 42 C_SBIT = 1 << 4 43 C_PBIT = 1 << 5 44 C_WBIT = 1 << 6 45 C_FBIT = 1 << 7 46 C_UBIT = 1 << 7 47 C_SCOND_XOR = 14 48 ) 49 50 // CConv formats ARM condition codes. 51 func CConv(s uint8) string { 52 if s == 0 { 53 return "" 54 } 55 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR] 56 if s&C_SBIT != 0 { 57 sc += ".S" 58 } 59 if s&C_PBIT != 0 { 60 sc += ".P" 61 } 62 if s&C_WBIT != 0 { 63 sc += ".W" 64 } 65 if s&C_UBIT != 0 { /* ambiguous with FBIT */ 66 sc += ".U" 67 } 68 return sc 69 } 70 71 func (p *Prog) String() string { 72 if p == nil { 73 return "<nil Prog>" 74 } 75 76 if p.Ctxt == nil { 77 return "<Prog without ctxt>" 78 } 79 80 sc := CConv(p.Scond) 81 82 var buf bytes.Buffer 83 84 fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc) 85 sep := "\t" 86 quadOpAmd64 := p.RegTo2 == -1 87 if quadOpAmd64 { 88 fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset) 89 sep = ", " 90 } 91 if p.From.Type != TYPE_NONE { 92 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From)) 93 sep = ", " 94 } 95 if p.Reg != REG_NONE { 96 // Should not happen but might as well show it if it does. 97 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg))) 98 sep = ", " 99 } 100 if p.From3Type() != TYPE_NONE { 101 if quadOpAmd64 { 102 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg))) 103 } else { 104 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3)) 105 } 106 sep = ", " 107 } 108 if p.As == ATEXT { 109 // If there are attributes, print them. Otherwise, skip the comma. 110 // In short, print one of these two: 111 // TEXT foo(SB), DUPOK|NOSPLIT, $0 112 // TEXT foo(SB), $0 113 s := p.From.Sym.Attribute.TextAttrString() 114 if s != "" { 115 fmt.Fprintf(&buf, "%s%s", sep, s) 116 sep = ", " 117 } 118 } 119 if p.To.Type != TYPE_NONE { 120 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) 121 } 122 if p.RegTo2 != REG_NONE && !quadOpAmd64 { 123 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2))) 124 } 125 return buf.String() 126 } 127 128 func (ctxt *Link) NewProg() *Prog { 129 p := new(Prog) 130 p.Ctxt = ctxt 131 return p 132 } 133 134 func (ctxt *Link) CanReuseProgs() bool { 135 return !ctxt.Debugasm 136 } 137 138 func (ctxt *Link) Dconv(a *Addr) string { 139 return Dconv(nil, a) 140 } 141 142 func Dconv(p *Prog, a *Addr) string { 143 var str string 144 145 switch a.Type { 146 default: 147 str = fmt.Sprintf("type=%d", a.Type) 148 149 case TYPE_NONE: 150 str = "" 151 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil { 152 str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg))) 153 } 154 155 case TYPE_REG: 156 // TODO(rsc): This special case is for x86 instructions like 157 // PINSRQ CX,$1,X6 158 // where the $1 is included in the p->to Addr. 159 // Move into a new field. 160 if a.Offset != 0 { 161 str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg))) 162 break 163 } 164 165 str = Rconv(int(a.Reg)) 166 if a.Name != NAME_NONE || a.Sym != nil { 167 str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg))) 168 } 169 170 case TYPE_BRANCH: 171 if a.Sym != nil { 172 str = fmt.Sprintf("%s(SB)", a.Sym.Name) 173 } else if p != nil && p.Pcond != nil { 174 str = fmt.Sprint(p.Pcond.Pc) 175 } else if a.Val != nil { 176 str = fmt.Sprint(a.Val.(*Prog).Pc) 177 } else { 178 str = fmt.Sprintf("%d(PC)", a.Offset) 179 } 180 181 case TYPE_INDIR: 182 str = fmt.Sprintf("*%s", Mconv(a)) 183 184 case TYPE_MEM: 185 str = Mconv(a) 186 if a.Index != REG_NONE { 187 str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale)) 188 } 189 190 case TYPE_CONST: 191 if a.Reg != 0 { 192 str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg))) 193 } else { 194 str = fmt.Sprintf("$%v", Mconv(a)) 195 } 196 197 case TYPE_TEXTSIZE: 198 if a.Val.(int32) == objabi.ArgsSizeUnknown { 199 str = fmt.Sprintf("$%d", a.Offset) 200 } else { 201 str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32)) 202 } 203 204 case TYPE_FCONST: 205 str = fmt.Sprintf("%.17g", a.Val.(float64)) 206 // Make sure 1 prints as 1.0 207 if !strings.ContainsAny(str, ".e") { 208 str += ".0" 209 } 210 str = fmt.Sprintf("$(%s)", str) 211 212 case TYPE_SCONST: 213 str = fmt.Sprintf("$%q", a.Val.(string)) 214 215 case TYPE_ADDR: 216 str = fmt.Sprintf("$%s", Mconv(a)) 217 218 case TYPE_SHIFT: 219 v := int(a.Offset) 220 ops := "<<>>->@>" 221 switch objabi.GOARCH { 222 case "arm": 223 op := ops[((v>>5)&3)<<1:] 224 if v&(1<<4) != 0 { 225 str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) 226 } else { 227 str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31) 228 } 229 if a.Reg != 0 { 230 str += fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 231 } 232 case "arm64": 233 op := ops[((v>>22)&3)<<1:] 234 str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63) 235 default: 236 panic("TYPE_SHIFT is not supported on " + objabi.GOARCH) 237 } 238 239 case TYPE_REGREG: 240 str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset))) 241 242 case TYPE_REGREG2: 243 str = fmt.Sprintf("%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg))) 244 245 case TYPE_REGLIST: 246 str = regListConv(int(a.Offset)) 247 } 248 249 return str 250 } 251 252 func Mconv(a *Addr) string { 253 var str string 254 255 switch a.Name { 256 default: 257 str = fmt.Sprintf("name=%d", a.Name) 258 259 case NAME_NONE: 260 switch { 261 case a.Reg == REG_NONE: 262 str = fmt.Sprint(a.Offset) 263 case a.Offset == 0: 264 str = fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 265 case a.Offset != 0: 266 str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg))) 267 } 268 269 // Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type. 270 case NAME_EXTERN: 271 reg := "SB" 272 if a.Reg != REG_NONE { 273 reg = Rconv(int(a.Reg)) 274 } 275 if a.Sym != nil { 276 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 277 } else { 278 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 279 } 280 281 case NAME_GOTREF: 282 reg := "SB" 283 if a.Reg != REG_NONE { 284 reg = Rconv(int(a.Reg)) 285 } 286 if a.Sym != nil { 287 str = fmt.Sprintf("%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg) 288 } else { 289 str = fmt.Sprintf("%s@GOT(%s)", offConv(a.Offset), reg) 290 } 291 292 case NAME_STATIC: 293 reg := "SB" 294 if a.Reg != REG_NONE { 295 reg = Rconv(int(a.Reg)) 296 } 297 if a.Sym != nil { 298 str = fmt.Sprintf("%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 299 } else { 300 str = fmt.Sprintf("<>%s(%s)", offConv(a.Offset), reg) 301 } 302 303 case NAME_AUTO: 304 reg := "SP" 305 if a.Reg != REG_NONE { 306 reg = Rconv(int(a.Reg)) 307 } 308 if a.Sym != nil { 309 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 310 } else { 311 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 312 } 313 314 case NAME_PARAM: 315 reg := "FP" 316 if a.Reg != REG_NONE { 317 reg = Rconv(int(a.Reg)) 318 } 319 if a.Sym != nil { 320 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 321 } else { 322 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 323 } 324 } 325 return str 326 } 327 328 func offConv(off int64) string { 329 if off == 0 { 330 return "" 331 } 332 return fmt.Sprintf("%+d", off) 333 } 334 335 type regSet struct { 336 lo int 337 hi int 338 Rconv func(int) string 339 } 340 341 // Few enough architectures that a linear scan is fastest. 342 // Not even worth sorting. 343 var regSpace []regSet 344 345 /* 346 Each architecture defines a register space as a unique 347 integer range. 348 Here is the list of architectures and the base of their register spaces. 349 */ 350 351 const ( 352 // Because of masking operations in the encodings, each register 353 // space should start at 0 modulo some power of 2. 354 RBase386 = 1 * 1024 355 RBaseAMD64 = 2 * 1024 356 RBaseARM = 3 * 1024 357 RBasePPC64 = 4 * 1024 // range [4k, 8k) 358 RBaseARM64 = 8 * 1024 // range [8k, 13k) 359 RBaseMIPS = 13 * 1024 // range [13k, 14k) 360 RBaseS390X = 14 * 1024 // range [14k, 15k) 361 ) 362 363 // RegisterRegister binds a pretty-printer (Rconv) for register 364 // numbers to a given register number range. Lo is inclusive, 365 // hi exclusive (valid registers are lo through hi-1). 366 func RegisterRegister(lo, hi int, Rconv func(int) string) { 367 regSpace = append(regSpace, regSet{lo, hi, Rconv}) 368 } 369 370 func Rconv(reg int) string { 371 if reg == REG_NONE { 372 return "NONE" 373 } 374 for i := range regSpace { 375 rs := ®Space[i] 376 if rs.lo <= reg && reg < rs.hi { 377 return rs.Rconv(reg) 378 } 379 } 380 return fmt.Sprintf("R???%d", reg) 381 } 382 383 func regListConv(list int) string { 384 str := "" 385 386 for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific. 387 if list&(1<<uint(i)) != 0 { 388 if str == "" { 389 str += "[" 390 } else { 391 str += "," 392 } 393 // This is ARM-specific; R10 is g. 394 if i == 10 { 395 str += "g" 396 } else { 397 str += fmt.Sprintf("R%d", i) 398 } 399 } 400 } 401 402 str += "]" 403 return str 404 } 405 406 type opSet struct { 407 lo As 408 names []string 409 } 410 411 // Not even worth sorting 412 var aSpace []opSet 413 414 // RegisterOpcode binds a list of instruction names 415 // to a given instruction number range. 416 func RegisterOpcode(lo As, Anames []string) { 417 if len(Anames) > AllowedOpCodes { 418 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes)) 419 } 420 aSpace = append(aSpace, opSet{lo, Anames}) 421 } 422 423 func (a As) String() string { 424 if 0 <= a && int(a) < len(Anames) { 425 return Anames[a] 426 } 427 for i := range aSpace { 428 as := &aSpace[i] 429 if as.lo <= a && int(a-as.lo) < len(as.names) { 430 return as.names[a-as.lo] 431 } 432 } 433 return fmt.Sprintf("A???%d", a) 434 } 435 436 var Anames = []string{ 437 "XXX", 438 "CALL", 439 "DUFFCOPY", 440 "DUFFZERO", 441 "END", 442 "FUNCDATA", 443 "JMP", 444 "NOP", 445 "PCDATA", 446 "RET", 447 "TEXT", 448 "UNDEF", 449 } 450 451 func Bool2int(b bool) int { 452 // The compiler currently only optimizes this form. 453 // See issue 6011. 454 var i int 455 if b { 456 i = 1 457 } else { 458 i = 0 459 } 460 return i 461 }