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