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