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 	"bufio"
      9 	"bytes"
     10 	"fmt"
     11 	"io"
     12 	"log"
     13 	"os"
     14 	"strconv"
     15 	"strings"
     16 	"time"
     17 )
     18 
     19 const REG_NONE = 0
     20 
     21 var start time.Time
     22 
     23 func Cputime() float64 {
     24 	if start.IsZero() {
     25 		start = time.Now()
     26 	}
     27 	return time.Since(start).Seconds()
     28 }
     29 
     30 type Biobuf struct {
     31 	f       *os.File
     32 	r       *bufio.Reader
     33 	w       *bufio.Writer
     34 	linelen int
     35 }
     36 
     37 func Bopenw(name string) (*Biobuf, error) {
     38 	f, err := os.Create(name)
     39 	if err != nil {
     40 		return nil, err
     41 	}
     42 	return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
     43 }
     44 
     45 func Bopenr(name string) (*Biobuf, error) {
     46 	f, err := os.Open(name)
     47 	if err != nil {
     48 		return nil, err
     49 	}
     50 	return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
     51 }
     52 
     53 func Binitw(w io.Writer) *Biobuf {
     54 	return &Biobuf{w: bufio.NewWriter(w)}
     55 }
     56 
     57 func (b *Biobuf) Write(p []byte) (int, error) {
     58 	return b.w.Write(p)
     59 }
     60 
     61 func Bwritestring(b *Biobuf, p string) (int, error) {
     62 	return b.w.WriteString(p)
     63 }
     64 
     65 func Bseek(b *Biobuf, offset int64, whence int) int64 {
     66 	if b.w != nil {
     67 		if err := b.w.Flush(); err != nil {
     68 			log.Fatalf("writing output: %v", err)
     69 		}
     70 	} else if b.r != nil {
     71 		if whence == 1 {
     72 			offset -= int64(b.r.Buffered())
     73 		}
     74 	}
     75 	off, err := b.f.Seek(offset, whence)
     76 	if err != nil {
     77 		log.Fatalf("seeking in output: %v", err)
     78 	}
     79 	if b.r != nil {
     80 		b.r.Reset(b.f)
     81 	}
     82 	return off
     83 }
     84 
     85 func Boffset(b *Biobuf) int64 {
     86 	if b.w != nil {
     87 		if err := b.w.Flush(); err != nil {
     88 			log.Fatalf("writing output: %v", err)
     89 		}
     90 	}
     91 	off, err := b.f.Seek(0, 1)
     92 	if err != nil {
     93 		log.Fatalf("seeking in output [0, 1]: %v", err)
     94 	}
     95 	if b.r != nil {
     96 		off -= int64(b.r.Buffered())
     97 	}
     98 	return off
     99 }
    100 
    101 func (b *Biobuf) Flush() error {
    102 	return b.w.Flush()
    103 }
    104 
    105 func Bputc(b *Biobuf, c byte) {
    106 	b.w.WriteByte(c)
    107 }
    108 
    109 const Beof = -1
    110 
    111 func Bread(b *Biobuf, p []byte) int {
    112 	n, err := io.ReadFull(b.r, p)
    113 	if n == 0 {
    114 		if err != nil && err != io.EOF {
    115 			n = -1
    116 		}
    117 	}
    118 	return n
    119 }
    120 
    121 func Bgetc(b *Biobuf) int {
    122 	c, err := b.r.ReadByte()
    123 	if err != nil {
    124 		return -1
    125 	}
    126 	return int(c)
    127 }
    128 
    129 func Bgetrune(b *Biobuf) int {
    130 	r, _, err := b.r.ReadRune()
    131 	if err != nil {
    132 		return -1
    133 	}
    134 	return int(r)
    135 }
    136 
    137 func Bungetrune(b *Biobuf) {
    138 	b.r.UnreadRune()
    139 }
    140 
    141 func (b *Biobuf) Read(p []byte) (int, error) {
    142 	return b.r.Read(p)
    143 }
    144 
    145 func (b *Biobuf) Peek(n int) ([]byte, error) {
    146 	return b.r.Peek(n)
    147 }
    148 
    149 func Brdline(b *Biobuf, delim int) string {
    150 	s, err := b.r.ReadBytes(byte(delim))
    151 	if err != nil {
    152 		log.Fatalf("reading input: %v", err)
    153 	}
    154 	b.linelen = len(s)
    155 	return string(s)
    156 }
    157 
    158 func Brdstr(b *Biobuf, delim int, cut int) string {
    159 	s, err := b.r.ReadString(byte(delim))
    160 	if err != nil {
    161 		log.Fatalf("reading input: %v", err)
    162 	}
    163 	if len(s) > 0 && cut > 0 {
    164 		s = s[:len(s)-1]
    165 	}
    166 	return s
    167 }
    168 
    169 func Access(name string, mode int) int {
    170 	if mode != 0 {
    171 		panic("bad access")
    172 	}
    173 	_, err := os.Stat(name)
    174 	if err != nil {
    175 		return -1
    176 	}
    177 	return 0
    178 }
    179 
    180 func Blinelen(b *Biobuf) int {
    181 	return b.linelen
    182 }
    183 
    184 func Bterm(b *Biobuf) error {
    185 	var err error
    186 	if b.w != nil {
    187 		err = b.w.Flush()
    188 	}
    189 	err1 := b.f.Close()
    190 	if err == nil {
    191 		err = err1
    192 	}
    193 	return err
    194 }
    195 
    196 func envOr(key, value string) string {
    197 	if x := os.Getenv(key); x != "" {
    198 		return x
    199 	}
    200 	return value
    201 }
    202 
    203 func Getgoroot() string {
    204 	return envOr("GOROOT", defaultGOROOT)
    205 }
    206 
    207 func Getgoarch() string {
    208 	return envOr("GOARCH", defaultGOARCH)
    209 }
    210 
    211 func Getgoos() string {
    212 	return envOr("GOOS", defaultGOOS)
    213 }
    214 
    215 func Getgoarm() string {
    216 	switch v := envOr("GOARM", defaultGOARM); v {
    217 	case "5", "6", "7":
    218 		return v
    219 	}
    220 	// Fail here, rather than validate at multiple call sites.
    221 	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
    222 	panic("unreachable")
    223 }
    224 
    225 func Getgo386() string {
    226 	// Validated by cmd/compile.
    227 	return envOr("GO386", defaultGO386)
    228 }
    229 
    230 func Getgoextlinkenabled() string {
    231 	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
    232 }
    233 
    234 func Getgoversion() string {
    235 	return version
    236 }
    237 
    238 func Atoi(s string) int {
    239 	i, _ := strconv.Atoi(s)
    240 	return i
    241 }
    242 
    243 func (p *Prog) Line() string {
    244 	return p.Ctxt.LineHist.LineString(int(p.Lineno))
    245 }
    246 
    247 var armCondCode = []string{
    248 	".EQ",
    249 	".NE",
    250 	".CS",
    251 	".CC",
    252 	".MI",
    253 	".PL",
    254 	".VS",
    255 	".VC",
    256 	".HI",
    257 	".LS",
    258 	".GE",
    259 	".LT",
    260 	".GT",
    261 	".LE",
    262 	"",
    263 	".NV",
    264 }
    265 
    266 /* ARM scond byte */
    267 const (
    268 	C_SCOND     = (1 << 4) - 1
    269 	C_SBIT      = 1 << 4
    270 	C_PBIT      = 1 << 5
    271 	C_WBIT      = 1 << 6
    272 	C_FBIT      = 1 << 7
    273 	C_UBIT      = 1 << 7
    274 	C_SCOND_XOR = 14
    275 )
    276 
    277 // CConv formats ARM condition codes.
    278 func CConv(s uint8) string {
    279 	if s == 0 {
    280 		return ""
    281 	}
    282 	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
    283 	if s&C_SBIT != 0 {
    284 		sc += ".S"
    285 	}
    286 	if s&C_PBIT != 0 {
    287 		sc += ".P"
    288 	}
    289 	if s&C_WBIT != 0 {
    290 		sc += ".W"
    291 	}
    292 	if s&C_UBIT != 0 { /* ambiguous with FBIT */
    293 		sc += ".U"
    294 	}
    295 	return sc
    296 }
    297 
    298 func (p *Prog) String() string {
    299 	if p.Ctxt == nil {
    300 		return "<Prog without ctxt>"
    301 	}
    302 
    303 	sc := CConv(p.Scond)
    304 
    305 	var buf bytes.Buffer
    306 
    307 	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
    308 	sep := "\t"
    309 	if p.From.Type != TYPE_NONE {
    310 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
    311 		sep = ", "
    312 	}
    313 	if p.Reg != REG_NONE {
    314 		// Should not happen but might as well show it if it does.
    315 		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
    316 		sep = ", "
    317 	}
    318 	if p.From3Type() != TYPE_NONE {
    319 		if p.From3.Type == TYPE_CONST && (p.As == ADATA || p.As == ATEXT || p.As == AGLOBL) {
    320 			// Special case - omit $.
    321 			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
    322 		} else {
    323 			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
    324 		}
    325 		sep = ", "
    326 	}
    327 	if p.To.Type != TYPE_NONE {
    328 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
    329 	}
    330 	if p.RegTo2 != REG_NONE {
    331 		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
    332 	}
    333 	return buf.String()
    334 }
    335 
    336 func (ctxt *Link) NewProg() *Prog {
    337 	p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
    338 	p.Ctxt = ctxt
    339 	return p
    340 }
    341 
    342 func (ctxt *Link) Line(n int) string {
    343 	return ctxt.LineHist.LineString(n)
    344 }
    345 
    346 func Getcallerpc(interface{}) uintptr {
    347 	return 1
    348 }
    349 
    350 func (ctxt *Link) Dconv(a *Addr) string {
    351 	return Dconv(nil, a)
    352 }
    353 
    354 func Dconv(p *Prog, a *Addr) string {
    355 	var str string
    356 
    357 	switch a.Type {
    358 	default:
    359 		str = fmt.Sprintf("type=%d", a.Type)
    360 
    361 	case TYPE_NONE:
    362 		str = ""
    363 		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
    364 			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
    365 		}
    366 
    367 	case TYPE_REG:
    368 		// TODO(rsc): This special case is for x86 instructions like
    369 		//	PINSRQ	CX,$1,X6
    370 		// where the $1 is included in the p->to Addr.
    371 		// Move into a new field.
    372 		if a.Offset != 0 {
    373 			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
    374 			break
    375 		}
    376 
    377 		str = Rconv(int(a.Reg))
    378 		if a.Name != TYPE_NONE || a.Sym != nil {
    379 			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
    380 		}
    381 
    382 	case TYPE_BRANCH:
    383 		if a.Sym != nil {
    384 			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
    385 		} else if p != nil && p.Pcond != nil {
    386 			str = fmt.Sprint(p.Pcond.Pc)
    387 		} else if a.Val != nil {
    388 			str = fmt.Sprint(a.Val.(*Prog).Pc)
    389 		} else {
    390 			str = fmt.Sprintf("%d(PC)", a.Offset)
    391 		}
    392 
    393 	case TYPE_INDIR:
    394 		str = fmt.Sprintf("*%s", Mconv(a))
    395 
    396 	case TYPE_MEM:
    397 		str = Mconv(a)
    398 		if a.Index != REG_NONE {
    399 			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
    400 		}
    401 
    402 	case TYPE_CONST:
    403 		if a.Reg != 0 {
    404 			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
    405 		} else {
    406 			str = fmt.Sprintf("$%v", Mconv(a))
    407 		}
    408 
    409 	case TYPE_TEXTSIZE:
    410 		if a.Val.(int32) == ArgsSizeUnknown {
    411 			str = fmt.Sprintf("$%d", a.Offset)
    412 		} else {
    413 			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
    414 		}
    415 
    416 	case TYPE_FCONST:
    417 		str = fmt.Sprintf("%.17g", a.Val.(float64))
    418 		// Make sure 1 prints as 1.0
    419 		if !strings.ContainsAny(str, ".e") {
    420 			str += ".0"
    421 		}
    422 		str = fmt.Sprintf("$(%s)", str)
    423 
    424 	case TYPE_SCONST:
    425 		str = fmt.Sprintf("$%q", a.Val.(string))
    426 
    427 	case TYPE_ADDR:
    428 		str = fmt.Sprintf("$%s", Mconv(a))
    429 
    430 	case TYPE_SHIFT:
    431 		v := int(a.Offset)
    432 		op := string("<<>>->@>"[((v>>5)&3)<<1:])
    433 		if v&(1<<4) != 0 {
    434 			str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
    435 		} else {
    436 			str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
    437 		}
    438 		if a.Reg != 0 {
    439 			str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
    440 		}
    441 
    442 	case TYPE_REGREG:
    443 		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
    444 
    445 	case TYPE_REGREG2:
    446 		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
    447 
    448 	case TYPE_REGLIST:
    449 		str = regListConv(int(a.Offset))
    450 	}
    451 
    452 	return str
    453 }
    454 
    455 func Mconv(a *Addr) string {
    456 	var str string
    457 
    458 	switch a.Name {
    459 	default:
    460 		str = fmt.Sprintf("name=%d", a.Name)
    461 
    462 	case NAME_NONE:
    463 		switch {
    464 		case a.Reg == REG_NONE:
    465 			str = fmt.Sprint(a.Offset)
    466 		case a.Offset == 0:
    467 			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
    468 		case a.Offset != 0:
    469 			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
    470 		}
    471 
    472 	case NAME_EXTERN:
    473 		str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
    474 
    475 	case NAME_GOTREF:
    476 		str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
    477 
    478 	case NAME_STATIC:
    479 		str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
    480 
    481 	case NAME_AUTO:
    482 		if a.Sym != nil {
    483 			str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
    484 		} else {
    485 			str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
    486 		}
    487 
    488 	case NAME_PARAM:
    489 		if a.Sym != nil {
    490 			str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
    491 		} else {
    492 			str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
    493 		}
    494 	}
    495 	return str
    496 }
    497 
    498 func offConv(off int64) string {
    499 	if off == 0 {
    500 		return ""
    501 	}
    502 	return fmt.Sprintf("%+d", off)
    503 }
    504 
    505 type regSet struct {
    506 	lo    int
    507 	hi    int
    508 	Rconv func(int) string
    509 }
    510 
    511 // Few enough architectures that a linear scan is fastest.
    512 // Not even worth sorting.
    513 var regSpace []regSet
    514 
    515 /*
    516 	Each architecture defines a register space as a unique
    517 	integer range.
    518 	Here is the list of architectures and the base of their register spaces.
    519 */
    520 
    521 const (
    522 	// Because of masking operations in the encodings, each register
    523 	// space should start at 0 modulo some power of 2.
    524 	RBase386   = 1 * 1024
    525 	RBaseAMD64 = 2 * 1024
    526 	RBaseARM   = 3 * 1024
    527 	RBasePPC64 = 4 * 1024 // range [4k, 8k)
    528 	RBaseARM64 = 8 * 1024 // range [8k, 12k)
    529 )
    530 
    531 // RegisterRegister binds a pretty-printer (Rconv) for register
    532 // numbers to a given register number range.  Lo is inclusive,
    533 // hi exclusive (valid registers are lo through hi-1).
    534 func RegisterRegister(lo, hi int, Rconv func(int) string) {
    535 	regSpace = append(regSpace, regSet{lo, hi, Rconv})
    536 }
    537 
    538 func Rconv(reg int) string {
    539 	if reg == REG_NONE {
    540 		return "NONE"
    541 	}
    542 	for i := range regSpace {
    543 		rs := &regSpace[i]
    544 		if rs.lo <= reg && reg < rs.hi {
    545 			return rs.Rconv(reg)
    546 		}
    547 	}
    548 	return fmt.Sprintf("R???%d", reg)
    549 }
    550 
    551 func regListConv(list int) string {
    552 	str := ""
    553 
    554 	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
    555 		if list&(1<<uint(i)) != 0 {
    556 			if str == "" {
    557 				str += "["
    558 			} else {
    559 				str += ","
    560 			}
    561 			// This is ARM-specific; R10 is g.
    562 			if i == 10 {
    563 				str += "g"
    564 			} else {
    565 				str += fmt.Sprintf("R%d", i)
    566 			}
    567 		}
    568 	}
    569 
    570 	str += "]"
    571 	return str
    572 }
    573 
    574 /*
    575 	Each architecture defines an instruction (A*) space as a unique
    576 	integer range.
    577 	Global opcodes like CALL start at 0; the architecture-specific ones
    578 	start at a distinct, big-maskable offsets.
    579 	Here is the list of architectures and the base of their opcode spaces.
    580 */
    581 
    582 const (
    583 	ABase386 = (1 + iota) << 12
    584 	ABaseARM
    585 	ABaseAMD64
    586 	ABasePPC64
    587 	ABaseARM64
    588 	AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
    589 )
    590 
    591 type opSet struct {
    592 	lo    int
    593 	names []string
    594 }
    595 
    596 // Not even worth sorting
    597 var aSpace []opSet
    598 
    599 // RegisterOpcode binds a list of instruction names
    600 // to a given instruction number range.
    601 func RegisterOpcode(lo int, Anames []string) {
    602 	aSpace = append(aSpace, opSet{lo, Anames})
    603 }
    604 
    605 func Aconv(a int) string {
    606 	if a < A_ARCHSPECIFIC {
    607 		return Anames[a]
    608 	}
    609 	for i := range aSpace {
    610 		as := &aSpace[i]
    611 		if as.lo <= a && a < as.lo+len(as.names) {
    612 			return as.names[a-as.lo]
    613 		}
    614 	}
    615 	return fmt.Sprintf("A???%d", a)
    616 }
    617 
    618 var Anames = []string{
    619 	"XXX",
    620 	"CALL",
    621 	"CHECKNIL",
    622 	"DATA",
    623 	"DUFFCOPY",
    624 	"DUFFZERO",
    625 	"END",
    626 	"FUNCDATA",
    627 	"GLOBL",
    628 	"JMP",
    629 	"NOP",
    630 	"PCDATA",
    631 	"RET",
    632 	"TEXT",
    633 	"TYPE",
    634 	"UNDEF",
    635 	"USEFIELD",
    636 	"VARDEF",
    637 	"VARKILL",
    638 }
    639 
    640 func Bool2int(b bool) int {
    641 	if b {
    642 		return 1
    643 	}
    644 	return 0
    645 }
    646