2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
2015-02-27 22:57:28 -05:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package ld
|
|
|
|
|
|
2016-03-14 22:57:58 +02:00
|
|
|
// Reading of Go object files.
|
2015-05-18 15:50:00 -04:00
|
|
|
//
|
|
|
|
|
// Originally, Go object files were Plan 9 object files, but no longer.
|
|
|
|
|
// Now they are more like standard object files, in that each symbol is defined
|
|
|
|
|
// by an associated memory image (bytes) and a list of relocations to apply
|
|
|
|
|
// during linking. We do not (yet?) use a standard file format, however.
|
|
|
|
|
// For now, the format is chosen to be as simple as possible to read and write.
|
|
|
|
|
// It may change for reasons of efficiency, or we may even switch to a
|
|
|
|
|
// standard file format if there are compelling benefits to doing so.
|
|
|
|
|
// See golang.org/s/go13linker for more background.
|
|
|
|
|
//
|
|
|
|
|
// The file format is:
|
|
|
|
|
//
|
2016-05-02 17:32:14 -04:00
|
|
|
// - magic header: "\x00\x00go17ld"
|
2015-05-18 15:50:00 -04:00
|
|
|
// - byte 1 - version number
|
|
|
|
|
// - sequence of strings giving dependencies (imported packages)
|
|
|
|
|
// - empty string (marks end of sequence)
|
2016-03-23 00:44:07 +02:00
|
|
|
// - sequence of symbol references used by the defined symbols
|
2016-03-14 22:57:58 +02:00
|
|
|
// - byte 0xff (marks end of sequence)
|
2016-03-23 00:44:07 +02:00
|
|
|
// - sequence of integer lengths:
|
|
|
|
|
// - total data length
|
|
|
|
|
// - total number of relocations
|
|
|
|
|
// - total number of pcdata
|
|
|
|
|
// - total number of automatics
|
|
|
|
|
// - total number of funcdata
|
|
|
|
|
// - total number of files
|
2016-03-21 10:55:20 +13:00
|
|
|
// - data, the content of the defined symbols
|
2015-05-18 15:50:00 -04:00
|
|
|
// - sequence of defined symbols
|
|
|
|
|
// - byte 0xff (marks end of sequence)
|
2016-05-02 17:32:14 -04:00
|
|
|
// - magic footer: "\xff\xffgo17ld"
|
2015-05-18 15:50:00 -04:00
|
|
|
//
|
|
|
|
|
// All integers are stored in a zigzag varint format.
|
|
|
|
|
// See golang.org/s/go12symtab for a definition.
|
|
|
|
|
//
|
|
|
|
|
// Data blocks and strings are both stored as an integer
|
|
|
|
|
// followed by that many bytes.
|
|
|
|
|
//
|
|
|
|
|
// A symbol reference is a string name followed by a version.
|
2016-03-14 22:57:58 +02:00
|
|
|
//
|
|
|
|
|
// A symbol points to other symbols using an index into the symbol
|
|
|
|
|
// reference sequence. Index 0 corresponds to a nil LSym* pointer.
|
|
|
|
|
// In the symbol layout described below "symref index" stands for this
|
|
|
|
|
// index.
|
2015-05-18 15:50:00 -04:00
|
|
|
//
|
|
|
|
|
// Each symbol is laid out as the following fields (taken from LSym*):
|
|
|
|
|
//
|
|
|
|
|
// - byte 0xfe (sanity check for synchronization)
|
|
|
|
|
// - type [int]
|
2016-03-14 22:57:58 +02:00
|
|
|
// - name & version [symref index]
|
2015-05-18 15:50:00 -04:00
|
|
|
// - flags [int]
|
|
|
|
|
// 1 dupok
|
|
|
|
|
// - size [int]
|
2016-03-14 22:57:58 +02:00
|
|
|
// - gotype [symref index]
|
2015-05-18 15:50:00 -04:00
|
|
|
// - p [data block]
|
|
|
|
|
// - nr [int]
|
|
|
|
|
// - r [nr relocations, sorted by off]
|
|
|
|
|
//
|
|
|
|
|
// If type == STEXT, there are a few more fields:
|
|
|
|
|
//
|
|
|
|
|
// - args [int]
|
|
|
|
|
// - locals [int]
|
|
|
|
|
// - nosplit [int]
|
|
|
|
|
// - flags [int]
|
2016-03-10 16:15:26 -05:00
|
|
|
// 1<<0 leaf
|
|
|
|
|
// 1<<1 C function
|
|
|
|
|
// 1<<2 function may call reflect.Type.Method
|
2015-05-18 15:50:00 -04:00
|
|
|
// - nlocal [int]
|
|
|
|
|
// - local [nlocal automatics]
|
|
|
|
|
// - pcln [pcln table]
|
|
|
|
|
//
|
|
|
|
|
// Each relocation has the encoding:
|
|
|
|
|
//
|
|
|
|
|
// - off [int]
|
|
|
|
|
// - siz [int]
|
|
|
|
|
// - type [int]
|
|
|
|
|
// - add [int]
|
2016-03-14 22:57:58 +02:00
|
|
|
// - sym [symref index]
|
2015-05-18 15:50:00 -04:00
|
|
|
//
|
|
|
|
|
// Each local has the encoding:
|
|
|
|
|
//
|
2016-03-14 22:57:58 +02:00
|
|
|
// - asym [symref index]
|
2015-05-18 15:50:00 -04:00
|
|
|
// - offset [int]
|
|
|
|
|
// - type [int]
|
2016-03-14 22:57:58 +02:00
|
|
|
// - gotype [symref index]
|
2015-05-18 15:50:00 -04:00
|
|
|
//
|
|
|
|
|
// The pcln table has the encoding:
|
|
|
|
|
//
|
|
|
|
|
// - pcsp [data block]
|
|
|
|
|
// - pcfile [data block]
|
|
|
|
|
// - pcline [data block]
|
|
|
|
|
// - npcdata [int]
|
|
|
|
|
// - pcdata [npcdata data blocks]
|
|
|
|
|
// - nfuncdata [int]
|
2016-03-14 22:57:58 +02:00
|
|
|
// - funcdata [nfuncdata symref index]
|
2015-05-18 15:50:00 -04:00
|
|
|
// - funcdatasym [nfuncdata ints]
|
|
|
|
|
// - nfile [int]
|
2016-03-14 22:57:58 +02:00
|
|
|
// - file [nfile symref index]
|
2015-05-18 15:50:00 -04:00
|
|
|
//
|
|
|
|
|
// The file layout and meaning of type integers are architecture-independent.
|
|
|
|
|
//
|
|
|
|
|
// TODO(rsc): The file format is good for a first pass but needs work.
|
|
|
|
|
// - There are SymID in the object file that should really just be strings.
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
import (
|
2016-03-31 18:34:02 +03:00
|
|
|
"bufio"
|
2015-02-27 22:57:28 -05:00
|
|
|
"bytes"
|
2016-04-06 21:45:29 -07:00
|
|
|
"cmd/internal/bio"
|
2015-04-19 19:33:58 -07:00
|
|
|
"cmd/internal/obj"
|
2016-04-06 13:09:06 -04:00
|
|
|
"crypto/sha1"
|
|
|
|
|
"encoding/base64"
|
2016-03-31 18:34:02 +03:00
|
|
|
"io"
|
2015-02-27 22:57:28 -05:00
|
|
|
"log"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
2015-03-06 11:42:53 -08:00
|
|
|
const (
|
2016-05-02 17:32:14 -04:00
|
|
|
startmagic = "\x00\x00go17ld"
|
|
|
|
|
endmagic = "\xff\xffgo17ld"
|
2015-03-06 11:42:53 -08:00
|
|
|
)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
var emptyPkg = []byte(`"".`)
|
|
|
|
|
|
|
|
|
|
// objReader reads Go object files.
|
|
|
|
|
type objReader struct {
|
|
|
|
|
rd *bufio.Reader
|
|
|
|
|
ctxt *Link
|
|
|
|
|
pkg string
|
|
|
|
|
pn string
|
|
|
|
|
// List of symbol references for the file being read.
|
|
|
|
|
dupSym *LSym
|
|
|
|
|
|
|
|
|
|
// rdBuf is used by readString and readSymName as scratch for reading strings.
|
|
|
|
|
rdBuf []byte
|
|
|
|
|
|
|
|
|
|
refs []*LSym
|
|
|
|
|
data []byte
|
|
|
|
|
reloc []Reloc
|
|
|
|
|
pcdata []Pcdata
|
|
|
|
|
autom []Auto
|
|
|
|
|
funcdata []*LSym
|
|
|
|
|
funcdataoff []int64
|
|
|
|
|
file []*LSym
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 19:14:03 +10:00
|
|
|
func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
|
|
|
|
start := f.Offset()
|
2016-03-31 18:34:02 +03:00
|
|
|
r := &objReader{
|
2016-04-08 20:37:54 +10:00
|
|
|
rd: f.Reader,
|
2016-03-31 18:34:02 +03:00
|
|
|
pkg: pkg,
|
|
|
|
|
ctxt: ctxt,
|
|
|
|
|
pn: pn,
|
|
|
|
|
dupSym: &LSym{Name: ".dup"},
|
|
|
|
|
}
|
|
|
|
|
r.loadObjFile()
|
2016-04-08 19:14:03 +10:00
|
|
|
if f.Offset() != start+length {
|
|
|
|
|
log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
|
2016-03-31 18:34:02 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *objReader) loadObjFile() {
|
|
|
|
|
// Increment context version, versions are used to differentiate static files in different packages
|
|
|
|
|
r.ctxt.IncVersion()
|
|
|
|
|
|
|
|
|
|
// Magic header
|
2015-03-02 14:22:05 -05:00
|
|
|
var buf [8]uint8
|
2016-03-31 18:34:02 +03:00
|
|
|
r.readFull(buf[:])
|
2015-02-27 22:57:28 -05:00
|
|
|
if string(buf[:]) != startmagic {
|
2016-03-31 18:34:02 +03:00
|
|
|
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])
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
|
|
|
|
|
// Version
|
|
|
|
|
c, err := r.rd.ReadByte()
|
|
|
|
|
if err != nil || c != 1 {
|
|
|
|
|
log.Fatalf("%s: invalid file version number %d", r.pn, c)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Autolib
|
2015-02-27 22:57:28 -05:00
|
|
|
for {
|
2016-03-31 18:34:02 +03:00
|
|
|
lib := r.readString()
|
2015-02-27 22:57:28 -05:00
|
|
|
if lib == "" {
|
|
|
|
|
break
|
|
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
addlib(r.ctxt, r.pkg, r.pn, lib)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Symbol references
|
|
|
|
|
r.refs = []*LSym{nil} // zeroth ref is nil
|
2016-03-14 22:57:58 +02:00
|
|
|
for {
|
2016-03-31 18:34:02 +03:00
|
|
|
c, err := r.rd.Peek(1)
|
2016-03-14 22:57:58 +02:00
|
|
|
if err != nil {
|
2016-03-31 18:34:02 +03:00
|
|
|
log.Fatalf("%s: peeking: %v", r.pn, err)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
|
|
|
|
if c[0] == 0xff {
|
2016-03-31 18:34:02 +03:00
|
|
|
r.rd.ReadByte()
|
2016-03-14 22:57:58 +02:00
|
|
|
break
|
|
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
r.readRef()
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Lengths
|
|
|
|
|
r.readSlices()
|
2016-03-23 00:44:07 +02:00
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Data section
|
|
|
|
|
r.readFull(r.data)
|
2016-03-21 10:55:20 +13:00
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Defined symbols
|
2015-02-27 22:57:28 -05:00
|
|
|
for {
|
2016-03-31 18:34:02 +03:00
|
|
|
c, err := r.rd.Peek(1)
|
2015-04-27 12:53:34 -04:00
|
|
|
if err != nil {
|
2016-03-31 18:34:02 +03:00
|
|
|
log.Fatalf("%s: peeking: %v", r.pn, err)
|
2015-04-27 12:53:34 -04:00
|
|
|
}
|
|
|
|
|
if c[0] == 0xff {
|
2015-02-27 22:57:28 -05:00
|
|
|
break
|
|
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
r.readSym()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Magic footer
|
2015-02-27 22:57:28 -05:00
|
|
|
buf = [8]uint8{}
|
2016-03-31 18:34:02 +03:00
|
|
|
r.readFull(buf[:])
|
2015-02-27 22:57:28 -05:00
|
|
|
if string(buf[:]) != endmagic {
|
2016-03-31 18:34:02 +03:00
|
|
|
log.Fatalf("%s: invalid file end", r.pn)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readSlices() {
|
|
|
|
|
n := r.readInt()
|
|
|
|
|
r.data = make([]byte, n)
|
|
|
|
|
n = r.readInt()
|
|
|
|
|
r.reloc = make([]Reloc, n)
|
|
|
|
|
n = r.readInt()
|
|
|
|
|
r.pcdata = make([]Pcdata, n)
|
|
|
|
|
n = r.readInt()
|
|
|
|
|
r.autom = make([]Auto, n)
|
|
|
|
|
n = r.readInt()
|
|
|
|
|
r.funcdata = make([]*LSym, n)
|
|
|
|
|
r.funcdataoff = make([]int64, n)
|
|
|
|
|
n = r.readInt()
|
|
|
|
|
r.file = make([]*LSym, n)
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Symbols are prefixed so their content doesn't get confused with the magic footer.
|
|
|
|
|
const symPrefix = 0xfe
|
2016-03-23 00:44:07 +02:00
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readSym() {
|
|
|
|
|
if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
|
|
|
|
|
log.Fatalln("readSym out of sync")
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
t := r.readInt()
|
|
|
|
|
s := r.readSymIndex()
|
|
|
|
|
flags := r.readInt()
|
2016-03-02 07:59:49 -05:00
|
|
|
dupok := flags&1 != 0
|
|
|
|
|
local := flags&2 != 0
|
2016-03-31 18:34:02 +03:00
|
|
|
size := r.readInt()
|
|
|
|
|
typ := r.readSymIndex()
|
|
|
|
|
data := r.readData()
|
|
|
|
|
nreloc := r.readInt()
|
2016-03-23 00:44:07 +02:00
|
|
|
isdup := false
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2015-03-02 14:22:05 -05:00
|
|
|
var dup *LSym
|
2015-04-19 19:33:58 -07:00
|
|
|
if s.Type != 0 && s.Type != obj.SXREF {
|
|
|
|
|
if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
|
2015-02-27 22:57:28 -05:00
|
|
|
if s.Size < int64(size) {
|
|
|
|
|
s.Size = int64(size)
|
|
|
|
|
}
|
|
|
|
|
if typ != nil && s.Gotype == nil {
|
|
|
|
|
s.Gotype = typ
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-19 19:33:58 -07:00
|
|
|
if (s.Type == obj.SDATA || s.Type == obj.SBSS || s.Type == obj.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
|
2015-02-27 22:57:28 -05:00
|
|
|
goto overwrite
|
|
|
|
|
}
|
2016-03-02 07:59:49 -05:00
|
|
|
if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
|
2016-03-31 18:34:02 +03:00
|
|
|
log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
if len(s.P) > 0 {
|
|
|
|
|
dup = s
|
2016-03-31 18:34:02 +03:00
|
|
|
s = r.dupSym
|
2016-03-23 00:44:07 +02:00
|
|
|
isdup = true
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
overwrite:
|
2016-03-31 18:34:02 +03:00
|
|
|
s.File = r.pkg
|
2016-03-02 07:59:49 -05:00
|
|
|
if dupok {
|
|
|
|
|
s.Attr |= AttrDuplicateOK
|
|
|
|
|
}
|
2015-04-19 19:33:58 -07:00
|
|
|
if t == obj.SXREF {
|
2015-02-27 22:57:28 -05:00
|
|
|
log.Fatalf("bad sxref")
|
|
|
|
|
}
|
|
|
|
|
if t == 0 {
|
2016-03-31 18:34:02 +03:00
|
|
|
log.Fatalf("missing type for %s in %s", s.Name, r.pn)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2015-04-19 19:33:58 -07:00
|
|
|
if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
|
2015-02-27 22:57:28 -05:00
|
|
|
t = int(s.Type)
|
|
|
|
|
}
|
|
|
|
|
s.Type = int16(t)
|
|
|
|
|
if s.Size < int64(size) {
|
|
|
|
|
s.Size = int64(size)
|
|
|
|
|
}
|
2016-03-02 07:59:49 -05:00
|
|
|
s.Attr.Set(AttrLocal, local)
|
2016-03-21 17:29:29 +13:00
|
|
|
if typ != nil {
|
2015-02-27 22:57:28 -05:00
|
|
|
s.Gotype = typ
|
|
|
|
|
}
|
2016-03-23 00:44:07 +02:00
|
|
|
if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
|
2015-02-27 22:57:28 -05:00
|
|
|
dup.Gotype = typ
|
|
|
|
|
}
|
|
|
|
|
s.P = data
|
|
|
|
|
if nreloc > 0 {
|
2016-03-31 18:34:02 +03:00
|
|
|
s.R = r.reloc[:nreloc:nreloc]
|
2016-03-23 00:44:07 +02:00
|
|
|
if !isdup {
|
2016-03-31 18:34:02 +03:00
|
|
|
r.reloc = r.reloc[nreloc:]
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < nreloc; i++ {
|
2016-03-31 18:34:02 +03:00
|
|
|
s.R[i] = Reloc{
|
|
|
|
|
Off: r.readInt32(),
|
|
|
|
|
Siz: r.readUint8(),
|
|
|
|
|
Type: r.readInt32(),
|
|
|
|
|
Add: r.readInt64(),
|
|
|
|
|
Sym: r.readSymIndex(),
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-19 19:33:58 -07:00
|
|
|
if s.Type == obj.STEXT {
|
2016-04-12 23:18:47 +03:00
|
|
|
s.FuncInfo = new(FuncInfo)
|
|
|
|
|
pc := s.FuncInfo
|
2016-04-11 22:19:34 +03:00
|
|
|
|
|
|
|
|
pc.Args = r.readInt32()
|
|
|
|
|
pc.Locals = r.readInt32()
|
2016-03-31 18:34:02 +03:00
|
|
|
if r.readUint8() != 0 {
|
2016-03-02 07:59:49 -05:00
|
|
|
s.Attr |= AttrNoSplit
|
|
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
flags := r.readInt()
|
2016-03-10 16:15:26 -05:00
|
|
|
if flags&(1<<2) != 0 {
|
|
|
|
|
s.Attr |= AttrReflectMethod
|
|
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
n := r.readInt()
|
2016-04-11 22:19:34 +03:00
|
|
|
pc.Autom = r.autom[:n:n]
|
2016-03-23 00:44:07 +02:00
|
|
|
if !isdup {
|
2016-03-31 18:34:02 +03:00
|
|
|
r.autom = r.autom[n:]
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < n; i++ {
|
2016-04-11 22:19:34 +03:00
|
|
|
pc.Autom[i] = Auto{
|
2016-03-31 18:34:02 +03:00
|
|
|
Asym: r.readSymIndex(),
|
|
|
|
|
Aoffset: r.readInt32(),
|
|
|
|
|
Name: r.readInt16(),
|
|
|
|
|
Gotype: r.readSymIndex(),
|
2016-03-02 22:38:42 -05:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
pc.Pcsp.P = r.readData()
|
|
|
|
|
pc.Pcfile.P = r.readData()
|
|
|
|
|
pc.Pcline.P = r.readData()
|
|
|
|
|
n = r.readInt()
|
|
|
|
|
pc.Pcdata = r.pcdata[:n:n]
|
2016-03-23 00:44:07 +02:00
|
|
|
if !isdup {
|
2016-03-31 18:34:02 +03:00
|
|
|
r.pcdata = r.pcdata[n:]
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < n; i++ {
|
2016-03-31 18:34:02 +03:00
|
|
|
pc.Pcdata[i].P = r.readData()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
n = r.readInt()
|
|
|
|
|
pc.Funcdata = r.funcdata[:n:n]
|
|
|
|
|
pc.Funcdataoff = r.funcdataoff[:n:n]
|
2016-03-23 00:44:07 +02:00
|
|
|
if !isdup {
|
2016-03-31 18:34:02 +03:00
|
|
|
r.funcdata = r.funcdata[n:]
|
|
|
|
|
r.funcdataoff = r.funcdataoff[n:]
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < n; i++ {
|
2016-03-31 18:34:02 +03:00
|
|
|
pc.Funcdata[i] = r.readSymIndex()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < n; i++ {
|
2016-03-31 18:34:02 +03:00
|
|
|
pc.Funcdataoff[i] = r.readInt64()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
n = r.readInt()
|
|
|
|
|
pc.File = r.file[:n:n]
|
2016-03-23 00:44:07 +02:00
|
|
|
if !isdup {
|
2016-03-31 18:34:02 +03:00
|
|
|
r.file = r.file[n:]
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < n; i++ {
|
2016-03-31 18:34:02 +03:00
|
|
|
pc.File[i] = r.readSymIndex()
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-23 00:44:07 +02:00
|
|
|
if !isdup {
|
2016-03-02 07:59:49 -05:00
|
|
|
if s.Attr.OnList() {
|
2015-02-27 22:57:28 -05:00
|
|
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
|
|
|
|
}
|
2016-03-02 07:59:49 -05:00
|
|
|
s.Attr |= AttrOnList
|
2016-04-19 14:02:21 -04:00
|
|
|
r.ctxt.Textp = append(r.ctxt.Textp, s)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readFull(b []byte) {
|
|
|
|
|
_, err := io.ReadFull(r.rd, b)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("%s: error reading %s", r.pn, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *objReader) readRef() {
|
|
|
|
|
if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
|
|
|
|
|
log.Fatalf("readSym out of sync")
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
name := r.readSymName()
|
|
|
|
|
v := r.readInt()
|
2016-03-14 22:57:58 +02:00
|
|
|
if v != 0 && v != 1 {
|
|
|
|
|
log.Fatalf("invalid symbol version %d", v)
|
|
|
|
|
}
|
|
|
|
|
if v == 1 {
|
2016-03-31 18:34:02 +03:00
|
|
|
v = r.ctxt.Version
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
s := Linklookup(r.ctxt, name, v)
|
|
|
|
|
r.refs = append(r.refs, s)
|
2016-03-20 17:22:57 +02:00
|
|
|
|
|
|
|
|
if s == nil || v != 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
|
|
|
|
|
x, err := strconv.ParseUint(s.Name[5:], 16, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
|
|
|
|
|
}
|
|
|
|
|
s.Type = obj.SRODATA
|
|
|
|
|
s.Attr |= AttrLocal
|
|
|
|
|
switch s.Name[:5] {
|
|
|
|
|
case "$f32.":
|
|
|
|
|
if uint64(uint32(x)) != x {
|
|
|
|
|
log.Panicf("$-symbol %s too large: %d", s.Name, x)
|
|
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
Adduint32(r.ctxt, s, uint32(x))
|
2016-03-20 17:22:57 +02:00
|
|
|
case "$f64.", "$i64.":
|
2016-03-31 18:34:02 +03:00
|
|
|
Adduint64(r.ctxt, s, x)
|
2016-03-20 17:22:57 +02:00
|
|
|
default:
|
|
|
|
|
log.Panicf("unrecognized $-symbol: %s", s.Name)
|
|
|
|
|
}
|
|
|
|
|
s.Attr.Set(AttrReachable, false)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(s.Name, "runtime.gcbits.") {
|
|
|
|
|
s.Attr |= AttrLocal
|
|
|
|
|
}
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readInt64() int64 {
|
2015-03-02 12:35:15 -05:00
|
|
|
uv := uint64(0)
|
2016-03-19 23:27:41 +02:00
|
|
|
for shift := uint(0); ; shift += 7 {
|
2015-02-27 22:57:28 -05:00
|
|
|
if shift >= 64 {
|
|
|
|
|
log.Fatalf("corrupt input")
|
|
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
c, err := r.rd.ReadByte()
|
2016-03-19 23:27:41 +02:00
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalln("error reading input: ", err)
|
|
|
|
|
}
|
|
|
|
|
uv |= uint64(c&0x7F) << shift
|
2015-02-27 22:57:28 -05:00
|
|
|
if c&0x80 == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-14 19:04:45 -07:00
|
|
|
return int64(uv>>1) ^ (int64(uv<<63) >> 63)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readInt() int {
|
|
|
|
|
n := r.readInt64()
|
2015-07-10 14:38:35 -07:00
|
|
|
if int64(int(n)) != n {
|
|
|
|
|
log.Panicf("%v out of range for int", n)
|
|
|
|
|
}
|
|
|
|
|
return int(n)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readInt32() int32 {
|
|
|
|
|
n := r.readInt64()
|
2015-07-10 14:38:35 -07:00
|
|
|
if int64(int32(n)) != n {
|
|
|
|
|
log.Panicf("%v out of range for int32", n)
|
|
|
|
|
}
|
|
|
|
|
return int32(n)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readInt16() int16 {
|
|
|
|
|
n := r.readInt64()
|
2015-07-10 14:38:35 -07:00
|
|
|
if int64(int16(n)) != n {
|
|
|
|
|
log.Panicf("%v out of range for int16", n)
|
|
|
|
|
}
|
|
|
|
|
return int16(n)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readUint8() uint8 {
|
|
|
|
|
n := r.readInt64()
|
2015-07-10 14:38:35 -07:00
|
|
|
if int64(uint8(n)) != n {
|
|
|
|
|
log.Panicf("%v out of range for uint8", n)
|
|
|
|
|
}
|
|
|
|
|
return uint8(n)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readString() string {
|
|
|
|
|
n := r.readInt()
|
2016-04-04 22:36:43 +03:00
|
|
|
if cap(r.rdBuf) < n {
|
|
|
|
|
r.rdBuf = make([]byte, 2*n)
|
2016-02-28 15:59:33 -09:00
|
|
|
}
|
2016-03-31 18:34:02 +03:00
|
|
|
r.readFull(r.rdBuf[:n])
|
|
|
|
|
return string(r.rdBuf[:n])
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
func (r *objReader) readData() []byte {
|
|
|
|
|
n := r.readInt()
|
|
|
|
|
p := r.data[:n:n]
|
|
|
|
|
r.data = r.data[n:]
|
2015-04-24 20:24:49 -07:00
|
|
|
return p
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// readSymName reads a symbol name, replacing all "". with pkg.
|
|
|
|
|
func (r *objReader) readSymName() string {
|
|
|
|
|
pkg := r.pkg
|
|
|
|
|
n := r.readInt()
|
2015-02-27 22:57:28 -05:00
|
|
|
if n == 0 {
|
2016-03-31 18:34:02 +03:00
|
|
|
r.readInt64()
|
2016-02-28 15:59:33 -09:00
|
|
|
return ""
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-04-04 22:36:43 +03:00
|
|
|
if cap(r.rdBuf) < n {
|
|
|
|
|
r.rdBuf = make([]byte, 2*n)
|
2016-04-03 18:27:17 +00:00
|
|
|
}
|
2016-04-06 07:11:24 -04:00
|
|
|
origName, err := r.rd.Peek(n)
|
|
|
|
|
if err == bufio.ErrBufferFull {
|
|
|
|
|
// Long symbol names are rare but exist. One source is type
|
|
|
|
|
// symbols for types with long string forms. See #15104.
|
|
|
|
|
origName = make([]byte, n)
|
|
|
|
|
r.readFull(origName)
|
|
|
|
|
} else if err != nil {
|
|
|
|
|
log.Fatalf("%s: error reading symbol: %v", err)
|
|
|
|
|
}
|
2016-04-03 18:27:17 +00:00
|
|
|
adjName := r.rdBuf[:0]
|
2016-02-28 15:59:33 -09:00
|
|
|
for {
|
|
|
|
|
i := bytes.Index(origName, emptyPkg)
|
|
|
|
|
if i == -1 {
|
2016-04-03 18:27:17 +00:00
|
|
|
s := string(append(adjName, origName...))
|
|
|
|
|
// Read past the peeked origName, now that we're done with it,
|
|
|
|
|
// using the rfBuf (also no longer used) as the scratch space.
|
|
|
|
|
// TODO: use bufio.Reader.Discard if available instead?
|
2016-04-06 07:11:24 -04:00
|
|
|
if err == nil {
|
|
|
|
|
r.readFull(r.rdBuf[:n])
|
|
|
|
|
}
|
2016-04-04 22:36:43 +03:00
|
|
|
r.rdBuf = adjName[:0] // in case 2*n wasn't enough
|
2016-04-06 13:09:06 -04:00
|
|
|
|
|
|
|
|
if DynlinkingGo() {
|
|
|
|
|
// These types are included in the symbol
|
|
|
|
|
// table when dynamically linking. To keep
|
|
|
|
|
// binary size down, we replace the names
|
|
|
|
|
// with SHA-1 prefixes.
|
|
|
|
|
//
|
|
|
|
|
// Keep the type.. prefix, which parts of the
|
|
|
|
|
// linker (like the DWARF generator) know means
|
|
|
|
|
// the symbol is not decodable.
|
|
|
|
|
//
|
|
|
|
|
// Leave type.runtime. symbols alone, because
|
|
|
|
|
// other parts of the linker manipulates them.
|
|
|
|
|
if strings.HasPrefix(s, "type.") && !strings.HasPrefix(s, "type.runtime.") {
|
|
|
|
|
hash := sha1.Sum([]byte(s))
|
|
|
|
|
prefix := "type."
|
|
|
|
|
if s[5] == '.' {
|
|
|
|
|
prefix = "type.."
|
|
|
|
|
}
|
|
|
|
|
s = prefix + base64.StdEncoding.EncodeToString(hash[:6])
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-03 18:27:17 +00:00
|
|
|
return s
|
2016-02-28 15:59:33 -09:00
|
|
|
}
|
|
|
|
|
adjName = append(adjName, origName[:i]...)
|
|
|
|
|
adjName = append(adjName, pkg...)
|
|
|
|
|
adjName = append(adjName, '.')
|
|
|
|
|
origName = origName[i+len(emptyPkg):]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 18:34:02 +03:00
|
|
|
// Reads the index of a symbol reference and resolves it to a symbol
|
|
|
|
|
func (r *objReader) readSymIndex() *LSym {
|
|
|
|
|
i := r.readInt()
|
|
|
|
|
return r.refs[i]
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|