Home | History | Annotate | Download | only in objfile
      1 // Copyright 2013 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 objfile reads Go object files for the Go linker, cmd/link.
      6 //
      7 // This package is similar to cmd/internal/objfile which also reads
      8 // Go object files.
      9 package objfile
     10 
     11 import (
     12 	"bufio"
     13 	"bytes"
     14 	"cmd/internal/bio"
     15 	"cmd/internal/dwarf"
     16 	"cmd/internal/objabi"
     17 	"cmd/internal/sys"
     18 	"cmd/link/internal/sym"
     19 	"io"
     20 	"log"
     21 	"strconv"
     22 	"strings"
     23 )
     24 
     25 const (
     26 	startmagic = "\x00\x00go19ld"
     27 	endmagic   = "\xff\xffgo19ld"
     28 )
     29 
     30 var emptyPkg = []byte(`"".`)
     31 
     32 // objReader reads Go object files.
     33 type objReader struct {
     34 	rd              *bufio.Reader
     35 	arch            *sys.Arch
     36 	syms            *sym.Symbols
     37 	lib             *sym.Library
     38 	pn              string
     39 	dupSym          *sym.Symbol
     40 	localSymVersion int
     41 
     42 	// rdBuf is used by readString and readSymName as scratch for reading strings.
     43 	rdBuf []byte
     44 
     45 	// List of symbol references for the file being read.
     46 	refs        []*sym.Symbol
     47 	data        []byte
     48 	reloc       []sym.Reloc
     49 	pcdata      []sym.Pcdata
     50 	autom       []sym.Auto
     51 	funcdata    []*sym.Symbol
     52 	funcdataoff []int64
     53 	file        []*sym.Symbol
     54 }
     55 
     56 // Load loads an object file f into library lib.
     57 // The symbols loaded are added to syms.
     58 func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, length int64, pn string) {
     59 	start := f.Offset()
     60 	r := &objReader{
     61 		rd:              f.Reader,
     62 		lib:             lib,
     63 		arch:            arch,
     64 		syms:            syms,
     65 		pn:              pn,
     66 		dupSym:          &sym.Symbol{Name: ".dup"},
     67 		localSymVersion: syms.IncVersion(),
     68 	}
     69 	r.loadObjFile()
     70 	if f.Offset() != start+length {
     71 		log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
     72 	}
     73 }
     74 
     75 func (r *objReader) loadObjFile() {
     76 	// Magic header
     77 	var buf [8]uint8
     78 	r.readFull(buf[:])
     79 	if string(buf[:]) != startmagic {
     80 		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
     81 	}
     82 
     83 	// Version
     84 	c, err := r.rd.ReadByte()
     85 	if err != nil || c != 1 {
     86 		log.Fatalf("%s: invalid file version number %d", r.pn, c)
     87 	}
     88 
     89 	// Autolib
     90 	for {
     91 		lib := r.readString()
     92 		if lib == "" {
     93 			break
     94 		}
     95 		r.lib.ImportStrings = append(r.lib.ImportStrings, lib)
     96 	}
     97 
     98 	// Symbol references
     99 	r.refs = []*sym.Symbol{nil} // zeroth ref is nil
    100 	for {
    101 		c, err := r.rd.Peek(1)
    102 		if err != nil {
    103 			log.Fatalf("%s: peeking: %v", r.pn, err)
    104 		}
    105 		if c[0] == 0xff {
    106 			r.rd.ReadByte()
    107 			break
    108 		}
    109 		r.readRef()
    110 	}
    111 
    112 	// Lengths
    113 	r.readSlices()
    114 
    115 	// Data section
    116 	r.readFull(r.data)
    117 
    118 	// Defined symbols
    119 	for {
    120 		c, err := r.rd.Peek(1)
    121 		if err != nil {
    122 			log.Fatalf("%s: peeking: %v", r.pn, err)
    123 		}
    124 		if c[0] == 0xff {
    125 			break
    126 		}
    127 		r.readSym()
    128 	}
    129 
    130 	// Magic footer
    131 	buf = [8]uint8{}
    132 	r.readFull(buf[:])
    133 	if string(buf[:]) != endmagic {
    134 		log.Fatalf("%s: invalid file end", r.pn)
    135 	}
    136 }
    137 
    138 func (r *objReader) readSlices() {
    139 	n := r.readInt()
    140 	r.data = make([]byte, n)
    141 	n = r.readInt()
    142 	r.reloc = make([]sym.Reloc, n)
    143 	n = r.readInt()
    144 	r.pcdata = make([]sym.Pcdata, n)
    145 	n = r.readInt()
    146 	r.autom = make([]sym.Auto, n)
    147 	n = r.readInt()
    148 	r.funcdata = make([]*sym.Symbol, n)
    149 	r.funcdataoff = make([]int64, n)
    150 	n = r.readInt()
    151 	r.file = make([]*sym.Symbol, n)
    152 }
    153 
    154 // Symbols are prefixed so their content doesn't get confused with the magic footer.
    155 const symPrefix = 0xfe
    156 
    157 func (r *objReader) readSym() {
    158 	var c byte
    159 	var err error
    160 	if c, err = r.rd.ReadByte(); c != symPrefix || err != nil {
    161 		log.Fatalln("readSym out of sync")
    162 	}
    163 	if c, err = r.rd.ReadByte(); err != nil {
    164 		log.Fatalln("error reading input: ", err)
    165 	}
    166 	t := sym.AbiSymKindToSymKind[c]
    167 	s := r.readSymIndex()
    168 	flags := r.readInt()
    169 	dupok := flags&1 != 0
    170 	local := flags&2 != 0
    171 	makeTypelink := flags&4 != 0
    172 	size := r.readInt()
    173 	typ := r.readSymIndex()
    174 	data := r.readData()
    175 	nreloc := r.readInt()
    176 	pkg := objabi.PathToPrefix(r.lib.Pkg)
    177 	isdup := false
    178 
    179 	var dup *sym.Symbol
    180 	if s.Type != 0 && s.Type != sym.SXREF {
    181 		if (t == sym.SDATA || t == sym.SBSS || t == sym.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
    182 			if s.Size < int64(size) {
    183 				s.Size = int64(size)
    184 			}
    185 			if typ != nil && s.Gotype == nil {
    186 				s.Gotype = typ
    187 			}
    188 			return
    189 		}
    190 
    191 		if (s.Type == sym.SDATA || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
    192 			goto overwrite
    193 		}
    194 		if s.Type != sym.SBSS && s.Type != sym.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
    195 			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
    196 		}
    197 		if len(s.P) > 0 {
    198 			dup = s
    199 			s = r.dupSym
    200 			isdup = true
    201 		}
    202 	}
    203 
    204 overwrite:
    205 	s.File = pkg
    206 	if dupok {
    207 		s.Attr |= sym.AttrDuplicateOK
    208 	}
    209 	if t == sym.SXREF {
    210 		log.Fatalf("bad sxref")
    211 	}
    212 	if t == 0 {
    213 		log.Fatalf("missing type for %s in %s", s.Name, r.pn)
    214 	}
    215 	if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
    216 		t = s.Type
    217 	}
    218 	s.Type = t
    219 	if s.Size < int64(size) {
    220 		s.Size = int64(size)
    221 	}
    222 	s.Attr.Set(sym.AttrLocal, local)
    223 	s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
    224 	if typ != nil {
    225 		s.Gotype = typ
    226 	}
    227 	if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
    228 		dup.Gotype = typ
    229 	}
    230 	s.P = data
    231 	if nreloc > 0 {
    232 		s.R = r.reloc[:nreloc:nreloc]
    233 		if !isdup {
    234 			r.reloc = r.reloc[nreloc:]
    235 		}
    236 
    237 		for i := 0; i < nreloc; i++ {
    238 			s.R[i] = sym.Reloc{
    239 				Off:  r.readInt32(),
    240 				Siz:  r.readUint8(),
    241 				Type: objabi.RelocType(r.readInt32()),
    242 				Add:  r.readInt64(),
    243 				Sym:  r.readSymIndex(),
    244 			}
    245 		}
    246 	}
    247 
    248 	if s.Type == sym.STEXT {
    249 		s.FuncInfo = new(sym.FuncInfo)
    250 		pc := s.FuncInfo
    251 
    252 		pc.Args = r.readInt32()
    253 		pc.Locals = r.readInt32()
    254 		if r.readUint8() != 0 {
    255 			s.Attr |= sym.AttrNoSplit
    256 		}
    257 		flags := r.readInt()
    258 		if flags&(1<<2) != 0 {
    259 			s.Attr |= sym.AttrReflectMethod
    260 		}
    261 		if flags&(1<<3) != 0 {
    262 			s.Attr |= sym.AttrShared
    263 		}
    264 		n := r.readInt()
    265 		pc.Autom = r.autom[:n:n]
    266 		if !isdup {
    267 			r.autom = r.autom[n:]
    268 		}
    269 
    270 		for i := 0; i < n; i++ {
    271 			pc.Autom[i] = sym.Auto{
    272 				Asym:    r.readSymIndex(),
    273 				Aoffset: r.readInt32(),
    274 				Name:    r.readInt16(),
    275 				Gotype:  r.readSymIndex(),
    276 			}
    277 		}
    278 
    279 		pc.Pcsp.P = r.readData()
    280 		pc.Pcfile.P = r.readData()
    281 		pc.Pcline.P = r.readData()
    282 		pc.Pcinline.P = r.readData()
    283 		n = r.readInt()
    284 		pc.Pcdata = r.pcdata[:n:n]
    285 		if !isdup {
    286 			r.pcdata = r.pcdata[n:]
    287 		}
    288 		for i := 0; i < n; i++ {
    289 			pc.Pcdata[i].P = r.readData()
    290 		}
    291 		n = r.readInt()
    292 		pc.Funcdata = r.funcdata[:n:n]
    293 		pc.Funcdataoff = r.funcdataoff[:n:n]
    294 		if !isdup {
    295 			r.funcdata = r.funcdata[n:]
    296 			r.funcdataoff = r.funcdataoff[n:]
    297 		}
    298 		for i := 0; i < n; i++ {
    299 			pc.Funcdata[i] = r.readSymIndex()
    300 		}
    301 		for i := 0; i < n; i++ {
    302 			pc.Funcdataoff[i] = r.readInt64()
    303 		}
    304 		n = r.readInt()
    305 		pc.File = r.file[:n:n]
    306 		if !isdup {
    307 			r.file = r.file[n:]
    308 		}
    309 		for i := 0; i < n; i++ {
    310 			pc.File[i] = r.readSymIndex()
    311 		}
    312 		n = r.readInt()
    313 		pc.InlTree = make([]sym.InlinedCall, n)
    314 		for i := 0; i < n; i++ {
    315 			pc.InlTree[i].Parent = r.readInt32()
    316 			pc.InlTree[i].File = r.readSymIndex()
    317 			pc.InlTree[i].Line = r.readInt32()
    318 			pc.InlTree[i].Func = r.readSymIndex()
    319 		}
    320 
    321 		s.Lib = r.lib
    322 		if !dupok {
    323 			if s.Attr.OnList() {
    324 				log.Fatalf("symbol %s listed multiple times", s.Name)
    325 			}
    326 			s.Attr |= sym.AttrOnList
    327 			r.lib.Textp = append(r.lib.Textp, s)
    328 		} else {
    329 			// there may ba a dup in another package
    330 			// put into a temp list and add to text later
    331 			if !isdup {
    332 				r.lib.DupTextSyms = append(r.lib.DupTextSyms, s)
    333 			} else {
    334 				r.lib.DupTextSyms = append(r.lib.DupTextSyms, dup)
    335 			}
    336 		}
    337 	}
    338 	if s.Type == sym.SDWARFINFO {
    339 		r.patchDWARFName(s)
    340 	}
    341 }
    342 
    343 func (r *objReader) patchDWARFName(s *sym.Symbol) {
    344 	// This is kind of ugly. Really the package name should not
    345 	// even be included here.
    346 	if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
    347 		return
    348 	}
    349 	e := bytes.IndexByte(s.P, 0)
    350 	if e == -1 {
    351 		return
    352 	}
    353 	p := bytes.Index(s.P[:e], emptyPkg)
    354 	if p == -1 {
    355 		return
    356 	}
    357 	pkgprefix := []byte(objabi.PathToPrefix(r.lib.Pkg) + ".")
    358 	patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
    359 
    360 	s.P = append(patched, s.P[e:]...)
    361 	delta := int64(len(s.P)) - s.Size
    362 	s.Size = int64(len(s.P))
    363 	for i := range s.R {
    364 		r := &s.R[i]
    365 		if r.Off > int32(e) {
    366 			r.Off += int32(delta)
    367 		}
    368 	}
    369 }
    370 
    371 func (r *objReader) readFull(b []byte) {
    372 	_, err := io.ReadFull(r.rd, b)
    373 	if err != nil {
    374 		log.Fatalf("%s: error reading %s", r.pn, err)
    375 	}
    376 }
    377 
    378 func (r *objReader) readRef() {
    379 	if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
    380 		log.Fatalf("readSym out of sync")
    381 	}
    382 	name := r.readSymName()
    383 	v := r.readInt()
    384 	if v != 0 && v != 1 {
    385 		log.Fatalf("invalid symbol version for %q: %d", name, v)
    386 	}
    387 	if v == 1 {
    388 		v = r.localSymVersion
    389 	}
    390 	s := r.syms.Lookup(name, v)
    391 	r.refs = append(r.refs, s)
    392 
    393 	if s == nil || v != 0 {
    394 		return
    395 	}
    396 	if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
    397 		x, err := strconv.ParseUint(s.Name[5:], 16, 64)
    398 		if err != nil {
    399 			log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
    400 		}
    401 		s.Type = sym.SRODATA
    402 		s.Attr |= sym.AttrLocal
    403 		switch s.Name[:5] {
    404 		case "$f32.":
    405 			if uint64(uint32(x)) != x {
    406 				log.Panicf("$-symbol %s too large: %d", s.Name, x)
    407 			}
    408 			s.AddUint32(r.arch, uint32(x))
    409 		case "$f64.", "$i64.":
    410 			s.AddUint64(r.arch, x)
    411 		default:
    412 			log.Panicf("unrecognized $-symbol: %s", s.Name)
    413 		}
    414 		s.Attr.Set(sym.AttrReachable, false)
    415 	}
    416 	if strings.HasPrefix(s.Name, "runtime.gcbits.") {
    417 		s.Attr |= sym.AttrLocal
    418 	}
    419 }
    420 
    421 func (r *objReader) readInt64() int64 {
    422 	uv := uint64(0)
    423 	for shift := uint(0); ; shift += 7 {
    424 		if shift >= 64 {
    425 			log.Fatalf("corrupt input")
    426 		}
    427 		c, err := r.rd.ReadByte()
    428 		if err != nil {
    429 			log.Fatalln("error reading input: ", err)
    430 		}
    431 		uv |= uint64(c&0x7F) << shift
    432 		if c&0x80 == 0 {
    433 			break
    434 		}
    435 	}
    436 
    437 	return int64(uv>>1) ^ (int64(uv<<63) >> 63)
    438 }
    439 
    440 func (r *objReader) readInt() int {
    441 	n := r.readInt64()
    442 	if int64(int(n)) != n {
    443 		log.Panicf("%v out of range for int", n)
    444 	}
    445 	return int(n)
    446 }
    447 
    448 func (r *objReader) readInt32() int32 {
    449 	n := r.readInt64()
    450 	if int64(int32(n)) != n {
    451 		log.Panicf("%v out of range for int32", n)
    452 	}
    453 	return int32(n)
    454 }
    455 
    456 func (r *objReader) readInt16() int16 {
    457 	n := r.readInt64()
    458 	if int64(int16(n)) != n {
    459 		log.Panicf("%v out of range for int16", n)
    460 	}
    461 	return int16(n)
    462 }
    463 
    464 func (r *objReader) readUint8() uint8 {
    465 	n := r.readInt64()
    466 	if int64(uint8(n)) != n {
    467 		log.Panicf("%v out of range for uint8", n)
    468 	}
    469 	return uint8(n)
    470 }
    471 
    472 func (r *objReader) readString() string {
    473 	n := r.readInt()
    474 	if cap(r.rdBuf) < n {
    475 		r.rdBuf = make([]byte, 2*n)
    476 	}
    477 	r.readFull(r.rdBuf[:n])
    478 	return string(r.rdBuf[:n])
    479 }
    480 
    481 func (r *objReader) readData() []byte {
    482 	n := r.readInt()
    483 	p := r.data[:n:n]
    484 	r.data = r.data[n:]
    485 	return p
    486 }
    487 
    488 // readSymName reads a symbol name, replacing all "". with pkg.
    489 func (r *objReader) readSymName() string {
    490 	pkg := objabi.PathToPrefix(r.lib.Pkg)
    491 	n := r.readInt()
    492 	if n == 0 {
    493 		r.readInt64()
    494 		return ""
    495 	}
    496 	if cap(r.rdBuf) < n {
    497 		r.rdBuf = make([]byte, 2*n)
    498 	}
    499 	origName, err := r.rd.Peek(n)
    500 	if err == bufio.ErrBufferFull {
    501 		// Long symbol names are rare but exist. One source is type
    502 		// symbols for types with long string forms. See #15104.
    503 		origName = make([]byte, n)
    504 		r.readFull(origName)
    505 	} else if err != nil {
    506 		log.Fatalf("%s: error reading symbol: %v", r.pn, err)
    507 	}
    508 	adjName := r.rdBuf[:0]
    509 	for {
    510 		i := bytes.Index(origName, emptyPkg)
    511 		if i == -1 {
    512 			s := string(append(adjName, origName...))
    513 			// Read past the peeked origName, now that we're done with it,
    514 			// using the rfBuf (also no longer used) as the scratch space.
    515 			// TODO: use bufio.Reader.Discard if available instead?
    516 			if err == nil {
    517 				r.readFull(r.rdBuf[:n])
    518 			}
    519 			r.rdBuf = adjName[:0] // in case 2*n wasn't enough
    520 			return s
    521 		}
    522 		adjName = append(adjName, origName[:i]...)
    523 		adjName = append(adjName, pkg...)
    524 		adjName = append(adjName, '.')
    525 		origName = origName[i+len(emptyPkg):]
    526 	}
    527 }
    528 
    529 // Reads the index of a symbol reference and resolves it to a symbol
    530 func (r *objReader) readSymIndex() *sym.Symbol {
    531 	i := r.readInt()
    532 	return r.refs[i]
    533 }
    534