[dev.link] all: merge branch 'master' into dev.link
Clean merge.
Change-Id: If9bfb0f27f41563fd5d386de9c1081542c3ce498
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index 5fe3fd9..fad87b2 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -23,6 +23,7 @@
Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
+ Newobj = flag.Bool("newobj", false, "use new object file format")
)
var (
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index fc6acc7..6b0a609 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -40,18 +40,18 @@
}
ctxt.Flag_dynlink = *flags.Dynlink
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
+ ctxt.Flag_newobj = *flags.Newobj
ctxt.Bso = bufio.NewWriter(os.Stdout)
defer ctxt.Bso.Flush()
architecture.Init(ctxt)
// Create object file, write header.
- out, err := os.Create(*flags.OutputFile)
+ buf, err := bio.Create(*flags.OutputFile)
if err != nil {
log.Fatal(err)
}
- defer bio.MustClose(out)
- buf := bufio.NewWriter(bio.MustWriter(out))
+ defer buf.Close()
if !*flags.SymABIs {
fmt.Fprintf(buf, "go object %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version)
@@ -83,6 +83,7 @@
}
}
if ok && !*flags.SymABIs {
+ ctxt.NumberSyms(true)
obj.WriteObjFile(ctxt, buf, "")
}
if !ok || diag {
@@ -91,9 +92,8 @@
} else {
log.Print("assembly failed")
}
- out.Close()
+ buf.Close()
os.Remove(*flags.OutputFile)
os.Exit(1)
}
- buf.Flush()
}
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index 54b87ab..9125f67 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -203,6 +203,7 @@
"bufio"
"bytes"
"cmd/compile/internal/types"
+ "cmd/internal/goobj2"
"cmd/internal/src"
"encoding/binary"
"fmt"
@@ -945,10 +946,12 @@
func (w *exportWriter) varExt(n *Node) {
w.linkname(n.Sym)
+ w.symIdx(n.Sym)
}
func (w *exportWriter) funcExt(n *Node) {
w.linkname(n.Sym)
+ w.symIdx(n.Sym)
// Escape analysis.
for _, fs := range types.RecvsParams {
@@ -987,6 +990,17 @@
w.string(s.Linkname)
}
+func (w *exportWriter) symIdx(s *types.Sym) {
+ if Ctxt.Flag_newobj {
+ lsym := s.Linksym()
+ if lsym.PkgIdx > goobj2.PkgIdxSelf || lsym.PkgIdx == goobj2.PkgIdxInvalid || s.Linkname != "" {
+ w.int64(-1)
+ } else {
+ w.int64(int64(lsym.SymIdx))
+ }
+ }
+}
+
// Inline bodies.
func (w *exportWriter) stmtList(list Nodes) {
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index 64c554d..824648a 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -10,6 +10,7 @@
import (
"cmd/compile/internal/types"
"cmd/internal/bio"
+ "cmd/internal/obj"
"cmd/internal/src"
"encoding/binary"
"fmt"
@@ -651,10 +652,12 @@
func (r *importReader) varExt(n *Node) {
r.linkname(n.Sym)
+ r.symIdx(n.Sym)
}
func (r *importReader) funcExt(n *Node) {
r.linkname(n.Sym)
+ r.symIdx(n.Sym)
// Escape analysis.
for _, fs := range types.RecvsParams {
@@ -683,6 +686,20 @@
s.Linkname = r.string()
}
+func (r *importReader) symIdx(s *types.Sym) {
+ if Ctxt.Flag_newobj {
+ lsym := s.Linksym()
+ idx := int32(r.int64())
+ if idx != -1 {
+ if s.Linkname != "" {
+ Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
+ }
+ lsym.SymIdx = idx
+ lsym.Set(obj.AttrIndexed, true)
+ }
+ }
+}
+
func (r *importReader) doInline(n *Node) {
if len(n.Func.Inl.Body) != 0 {
Fatalf("%v already has inline body", n)
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 05aac9e..9e8abbc 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -263,12 +263,14 @@
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
+ flag.BoolVar(&Ctxt.Flag_newobj, "newobj", false, "use new object file format")
+
objabi.Flagparse(usage)
// Record flags that affect the build result. (And don't
// record flags that don't, since that would cause spurious
// changes in the binary.)
- recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes")
+ recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "newobj")
if smallFrames {
maxStackVarSize = 128 * 1024
@@ -722,6 +724,8 @@
// Write object data to disk.
timings.Start("be", "dumpobj")
+ dumpdata()
+ Ctxt.NumberSyms(false)
dumpobj()
if asmhdr != "" {
dumpasmhdr()
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index be13b27..ae0fc1d 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -111,21 +111,7 @@
dumpexport(bout)
}
-func dumpLinkerObj(bout *bio.Writer) {
- printObjHeader(bout)
-
- if len(pragcgobuf) != 0 {
- // write empty export section; must be before cgo section
- fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
- fmt.Fprintf(bout, "\n$$ // cgo\n")
- if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
- Fatalf("serializing pragcgobuf: %v", err)
- }
- fmt.Fprintf(bout, "\n$$\n\n")
- }
-
- fmt.Fprintf(bout, "\n!\n")
-
+func dumpdata() {
externs := len(externdcl)
dumpglobls()
@@ -163,8 +149,24 @@
}
addGCLocals()
+}
- obj.WriteObjFile(Ctxt, bout.Writer, myimportpath)
+func dumpLinkerObj(bout *bio.Writer) {
+ printObjHeader(bout)
+
+ if len(pragcgobuf) != 0 {
+ // write empty export section; must be before cgo section
+ fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
+ fmt.Fprintf(bout, "\n$$ // cgo\n")
+ if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
+ Fatalf("serializing pragcgobuf: %v", err)
+ }
+ fmt.Fprintf(bout, "\n$$\n\n")
+ }
+
+ fmt.Fprintf(bout, "\n!\n")
+
+ obj.WriteObjFile(Ctxt, bout, myimportpath)
}
func addptabs() {
diff --git a/src/cmd/compile/internal/types/sym.go b/src/cmd/compile/internal/types/sym.go
index c9dd9f3..07bce4d 100644
--- a/src/cmd/compile/internal/types/sym.go
+++ b/src/cmd/compile/internal/types/sym.go
@@ -80,11 +80,18 @@
if sym == nil {
return nil
}
+ initPkg := func(r *obj.LSym) {
+ if sym.Linkname != "" {
+ r.Pkg = "_"
+ } else {
+ r.Pkg = sym.Pkg.Prefix
+ }
+ }
if sym.Func() {
// This is a function symbol. Mark it as "internal ABI".
- return Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
+ return Ctxt.LookupABIInit(sym.LinksymName(), obj.ABIInternal, initPkg)
}
- return Ctxt.Lookup(sym.LinksymName())
+ return Ctxt.LookupInit(sym.LinksymName(), initPkg)
}
// Less reports whether symbol a is ordered before symbol b.
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index f27ea17..e85dd9a 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -54,6 +54,7 @@
"cmd/internal/gcprog",
"cmd/internal/dwarf",
"cmd/internal/edit",
+ "cmd/internal/goobj2",
"cmd/internal/objabi",
"cmd/internal/obj",
"cmd/internal/obj/arm",
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
index 0c70b8c..2a3afff 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -503,6 +503,11 @@
// TODO: extract OS + build ID if/when we need it
r.readFull(r.tmp[:8])
+ if bytes.Equal(r.tmp[:8], []byte("\x00go114LD")) {
+ r.offset -= 8
+ r.readNew()
+ return nil
+ }
if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) {
return r.error(errCorruptObject)
}
diff --git a/src/cmd/internal/goobj/readnew.go b/src/cmd/internal/goobj/readnew.go
new file mode 100644
index 0000000..b4b8469
--- /dev/null
+++ b/src/cmd/internal/goobj/readnew.go
@@ -0,0 +1,168 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package goobj
+
+import (
+ "cmd/internal/goobj2"
+ "cmd/internal/objabi"
+ "fmt"
+ "strings"
+)
+
+// Read object file in new format. For now we still fill
+// the data to the current goobj API.
+func (r *objReader) readNew() {
+ start := uint32(r.offset)
+ rr := goobj2.NewReader(r.f, start)
+ if rr == nil {
+ panic("cannot read object file")
+ }
+
+ // Imports
+ pkglist := rr.Pkglist()
+ r.p.Imports = pkglist[1:] // index 0 is a dummy invalid package
+
+ abiToVer := func(abi uint16) int64 {
+ var vers int64
+ if abi == goobj2.SymABIstatic {
+ // Static symbol
+ vers = r.p.MaxVersion
+ }
+ return vers
+ }
+
+ resolveSymRef := func(s goobj2.SymRef) SymID {
+ var i int
+ switch p := s.PkgIdx; p {
+ case goobj2.PkgIdxInvalid:
+ if s.SymIdx != 0 {
+ panic("bad sym ref")
+ }
+ return SymID{}
+ case goobj2.PkgIdxNone:
+ i = int(s.SymIdx) + rr.NSym()
+ case goobj2.PkgIdxBuiltin:
+ panic("PkgIdxBuiltin is unused")
+ case goobj2.PkgIdxSelf:
+ i = int(s.SymIdx)
+ default:
+ pkg := pkglist[p]
+ return SymID{fmt.Sprintf("%s.<#%d>", pkg, s.SymIdx), 0}
+ }
+ sym := goobj2.Sym{}
+ sym.Read(rr, rr.SymOff(i))
+ return SymID{sym.Name, abiToVer(sym.ABI)}
+ }
+
+ // Read things for the current goobj API for now.
+
+ // Symbols
+ pcdataBase := start + rr.PcdataBase()
+ n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref()
+ ndef := rr.NSym() + rr.NNonpkgdef()
+ for i := 0; i < n; i++ {
+ osym := goobj2.Sym{}
+ osym.Read(rr, rr.SymOff(i))
+ if osym.Name == "" {
+ continue // not a real symbol
+ }
+ // In a symbol name in an object file, "". denotes the
+ // prefix for the package in which the object file has been found.
+ // Expand it.
+ name := strings.ReplaceAll(osym.Name, `"".`, r.pkgprefix)
+ symID := SymID{Name: name, Version: abiToVer(osym.ABI)}
+ r.p.SymRefs = append(r.p.SymRefs, symID)
+
+ if i >= ndef {
+ continue // not a defined symbol from here
+ }
+
+ // Symbol data
+ dataOff := rr.DataOff(i)
+ siz := int64(rr.DataSize(i))
+
+ sym := Sym{
+ SymID: symID,
+ Kind: objabi.SymKind(osym.Type),
+ DupOK: osym.Flag&goobj2.SymFlagDupok != 0,
+ Size: int64(osym.Siz),
+ Data: Data{int64(start + dataOff), siz},
+ }
+ r.p.Syms = append(r.p.Syms, &sym)
+
+ // Reloc
+ nreloc := rr.NReloc(i)
+ sym.Reloc = make([]Reloc, nreloc)
+ for j := 0; j < nreloc; j++ {
+ rel := goobj2.Reloc{}
+ rel.Read(rr, rr.RelocOff(i, j))
+ sym.Reloc[j] = Reloc{
+ Offset: int64(rel.Off),
+ Size: int64(rel.Siz),
+ Type: objabi.RelocType(rel.Type),
+ Add: rel.Add,
+ Sym: resolveSymRef(rel.Sym),
+ }
+ }
+
+ // Aux symbol info
+ isym := -1
+ funcdata := make([]goobj2.SymRef, 0, 4)
+ naux := rr.NAux(i)
+ for j := 0; j < naux; j++ {
+ a := goobj2.Aux{}
+ a.Read(rr, rr.AuxOff(i, j))
+ switch a.Type {
+ case goobj2.AuxGotype:
+ sym.Type = resolveSymRef(a.Sym)
+ case goobj2.AuxFuncInfo:
+ if a.Sym.PkgIdx != goobj2.PkgIdxSelf {
+ panic("funcinfo symbol not defined in current package")
+ }
+ isym = int(a.Sym.SymIdx)
+ case goobj2.AuxFuncdata:
+ funcdata = append(funcdata, a.Sym)
+ default:
+ panic("unknown aux type")
+ }
+ }
+
+ // Symbol Info
+ if isym == -1 {
+ continue
+ }
+ b := rr.BytesAt(rr.DataOff(isym), rr.DataSize(isym))
+ info := goobj2.FuncInfo{}
+ info.Read(b)
+
+ info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends
+ f := &Func{
+ Args: int64(info.Args),
+ Frame: int64(info.Locals),
+ NoSplit: info.NoSplit != 0,
+ Leaf: info.Flags&goobj2.FuncFlagLeaf != 0,
+ TopFrame: info.Flags&goobj2.FuncFlagTopFrame != 0,
+ PCSP: Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)},
+ PCFile: Data{int64(pcdataBase + info.Pcfile), int64(info.Pcline - info.Pcfile)},
+ PCLine: Data{int64(pcdataBase + info.Pcline), int64(info.Pcinline - info.Pcline)},
+ PCInline: Data{int64(pcdataBase + info.Pcinline), int64(info.Pcdata[0] - info.Pcinline)},
+ PCData: make([]Data, len(info.Pcdata)-1), // -1 as we appended one above
+ FuncData: make([]FuncData, len(info.Funcdataoff)),
+ File: make([]string, len(info.File)),
+ }
+ sym.Func = f
+ for k := range f.PCData {
+ f.PCData[k] = Data{int64(pcdataBase + info.Pcdata[k]), int64(info.Pcdata[k+1] - info.Pcdata[k])}
+ }
+ for k := range f.FuncData {
+ symID := resolveSymRef(funcdata[k])
+ f.FuncData[k] = FuncData{symID, int64(info.Funcdataoff[k])}
+ }
+ for k := range f.File {
+ symID := resolveSymRef(info.File[k])
+ f.File[k] = symID.Name
+ }
+ }
+}
diff --git a/src/cmd/internal/goobj2/funcinfo.go b/src/cmd/internal/goobj2/funcinfo.go
new file mode 100644
index 0000000..5938b5f
--- /dev/null
+++ b/src/cmd/internal/goobj2/funcinfo.go
@@ -0,0 +1,114 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package goobj2
+
+import (
+ "bytes"
+ "encoding/binary"
+)
+
+// FuncInfo is serialized as a symbol (aux symbol). The symbol data is
+// the binary encoding of the struct below.
+//
+// TODO: make each pcdata a separate symbol?
+type FuncInfo struct {
+ NoSplit uint8
+ Flags uint8
+
+ Args uint32
+ Locals uint32
+
+ Pcsp uint32
+ Pcfile uint32
+ Pcline uint32
+ Pcinline uint32
+ Pcdata []uint32
+ PcdataEnd uint32
+ Funcdataoff []uint32
+ File []SymRef // TODO: just use string?
+
+ // TODO: InlTree
+}
+
+const (
+ FuncFlagLeaf = 1 << iota
+ FuncFlagCFunc
+ FuncFlagReflectMethod
+ FuncFlagShared // This is really silly
+ FuncFlagTopFrame
+)
+
+func (a *FuncInfo) Write(w *bytes.Buffer) {
+ w.WriteByte(a.NoSplit)
+ w.WriteByte(a.Flags)
+
+ var b [4]byte
+ writeUint32 := func(x uint32) {
+ binary.LittleEndian.PutUint32(b[:], x)
+ w.Write(b[:])
+ }
+
+ writeUint32(a.Args)
+ writeUint32(a.Locals)
+
+ writeUint32(a.Pcsp)
+ writeUint32(a.Pcfile)
+ writeUint32(a.Pcline)
+ writeUint32(a.Pcinline)
+ writeUint32(uint32(len(a.Pcdata)))
+ for _, x := range a.Pcdata {
+ writeUint32(x)
+ }
+ writeUint32(a.PcdataEnd)
+ writeUint32(uint32(len(a.Funcdataoff)))
+ for _, x := range a.Funcdataoff {
+ writeUint32(x)
+ }
+ writeUint32(uint32(len(a.File)))
+ for _, f := range a.File {
+ writeUint32(f.PkgIdx)
+ writeUint32(f.SymIdx)
+ }
+
+ // TODO: InlTree
+}
+
+func (a *FuncInfo) Read(b []byte) {
+ a.NoSplit = b[0]
+ a.Flags = b[1]
+ b = b[2:]
+
+ readUint32 := func() uint32 {
+ x := binary.LittleEndian.Uint32(b)
+ b = b[4:]
+ return x
+ }
+
+ a.Args = readUint32()
+ a.Locals = readUint32()
+
+ a.Pcsp = readUint32()
+ a.Pcfile = readUint32()
+ a.Pcline = readUint32()
+ a.Pcinline = readUint32()
+ pcdatalen := readUint32()
+ a.Pcdata = make([]uint32, pcdatalen)
+ for i := range a.Pcdata {
+ a.Pcdata[i] = readUint32()
+ }
+ a.PcdataEnd = readUint32()
+ funcdataofflen := readUint32()
+ a.Funcdataoff = make([]uint32, funcdataofflen)
+ for i := range a.Funcdataoff {
+ a.Funcdataoff[i] = readUint32()
+ }
+ filelen := readUint32()
+ a.File = make([]SymRef, filelen)
+ for i := range a.File {
+ a.File[i] = SymRef{readUint32(), readUint32()}
+ }
+
+ // TODO: InlTree
+}
diff --git a/src/cmd/internal/goobj2/objfile.go b/src/cmd/internal/goobj2/objfile.go
new file mode 100644
index 0000000..b5cc0d7
--- /dev/null
+++ b/src/cmd/internal/goobj2/objfile.go
@@ -0,0 +1,568 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go new object file format, reading and writing.
+
+package goobj2 // TODO: replace the goobj package?
+
+import (
+ "bytes"
+ "cmd/internal/bio"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "unsafe"
+)
+
+// New object file format.
+//
+// Header struct {
+// Magic [...]byte // "\x00go114LD"
+// // TODO: Fingerprint
+// Offsets [...]uint32 // byte offset of each block below
+// }
+//
+// Strings [...]struct {
+// Len uint32
+// Data [...]byte
+// }
+//
+// PkgIndex [...]stringOff // TODO: add fingerprints
+//
+// DwarfFiles [...]stringOff // XXX as a separate block for now
+//
+// SymbolDefs [...]struct {
+// Name stringOff
+// ABI uint16
+// Type uint8
+// Flag uint8
+// Size uint32
+// }
+// NonPkgDefs [...]struct { // non-pkg symbol definitions
+// ... // same as SymbolDefs
+// }
+// NonPkgRefs [...]struct { // non-pkg symbol references
+// ... // same as SymbolDefs
+// }
+//
+// RelocIndex [...]uint32 // index to Relocs
+// AuxIndex [...]uint32 // index to Aux
+// DataIndex [...]uint32 // offset to Data
+//
+// Relocs [...]struct {
+// Off int32
+// Size uint8
+// Type uint8
+// Add int64
+// Sym symRef
+// }
+//
+// Aux [...]struct {
+// Type uint8
+// Sym symRef
+// }
+//
+// Data [...]byte
+// Pcdata [...]byte
+//
+// stringOff is a uint32 (?) offset that points to the corresponding
+// string, which is a uint32 length followed by that number of bytes.
+//
+// symRef is struct { PkgIdx, SymIdx uint32 }.
+//
+// Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
+// followed by that number of elements.
+//
+// The types below correspond to the encoded data structure in the
+// object file.
+
+// Symbol indexing.
+//
+// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
+// as the symRef struct above.
+//
+// PkgIdx is either a predeclared index (see PkgIdxNone below) or
+// an index of an imported package. For the latter case, PkgIdx is the
+// index of the package in the PkgIndex array. 0 is an invalid index.
+//
+// SymIdx is the index of the symbol in the given package.
+// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
+// SymbolDefs array.
+// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
+// NonPkgDefs array (could natually overflow to NonPkgRefs array).
+// - Otherwise, SymIdx is the index of the symbol in some other package's
+// SymbolDefs array.
+//
+// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
+//
+// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
+// Relocs/Aux/Data blocks, one element per symbol, first for all the
+// defined symbols, then all the defined non-package symbols, in the
+// same order of SymbolDefs/NonPkgDefs arrays. For N total defined
+// symbols, the array is of length N+1. The last element is the total
+// number of relocations (aux symbols, data blocks, etc.).
+//
+// They can be accessed by index. For the i-th symbol, its relocations
+// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
+// elements in the Relocs array. Aux/Data are likewise. (The index is
+// 0-based.)
+
+// Auxiliary symbols.
+//
+// Each symbol may (or may not) be associated with a number of auxiliary
+// symbols. They are described in the Aux block. See Aux struct below.
+// Currently a symbol's Gotype and FuncInfo are auxiliary symbols. We
+// may make use of aux symbols in more cases, e.g. DWARF symbols.
+
+// Package Index.
+const (
+ PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
+ PkgIdxBuiltin // Predefined symbols // TODO: not used for now, we could use it for compiler-generated symbols like runtime.newobject
+ PkgIdxSelf // Symbols defined in the current package
+ PkgIdxInvalid = 0
+ // The index of other referenced packages starts from 1.
+)
+
+// Blocks
+const (
+ BlkPkgIdx = iota
+ BlkDwarfFile
+ BlkSymdef
+ BlkNonpkgdef
+ BlkNonpkgref
+ BlkRelocIdx
+ BlkAuxIdx
+ BlkDataIdx
+ BlkReloc
+ BlkAux
+ BlkData
+ BlkPcdata
+ NBlk
+)
+
+// File header.
+// TODO: probably no need to export this.
+type Header struct {
+ Magic string
+ Offsets [NBlk]uint32
+}
+
+const Magic = "\x00go114LD"
+
+func (h *Header) Write(w *Writer) {
+ w.RawString(h.Magic)
+ for _, x := range h.Offsets {
+ w.Uint32(x)
+ }
+}
+
+func (h *Header) Read(r *Reader) error {
+ b := r.BytesAt(0, len(Magic))
+ h.Magic = string(b)
+ if h.Magic != Magic {
+ return errors.New("wrong magic, not a Go object file")
+ }
+ off := uint32(len(h.Magic))
+ for i := range h.Offsets {
+ h.Offsets[i] = r.uint32At(off)
+ off += 4
+ }
+ return nil
+}
+
+func (h *Header) Size() int {
+ return len(h.Magic) + 4*len(h.Offsets)
+}
+
+// Symbol definition.
+type Sym struct {
+ Name string
+ ABI uint16
+ Type uint8
+ Flag uint8
+ Siz uint32
+}
+
+const SymABIstatic = ^uint16(0)
+
+const (
+ SymFlagDupok = 1 << iota
+ SymFlagLocal
+ SymFlagTypelink
+)
+
+func (s *Sym) Write(w *Writer) {
+ w.StringRef(s.Name)
+ w.Uint16(s.ABI)
+ w.Uint8(s.Type)
+ w.Uint8(s.Flag)
+ w.Uint32(s.Siz)
+}
+
+func (s *Sym) Read(r *Reader, off uint32) {
+ s.Name = r.StringRef(off)
+ s.ABI = r.uint16At(off + 4)
+ s.Type = r.uint8At(off + 6)
+ s.Flag = r.uint8At(off + 7)
+ s.Siz = r.uint32At(off + 8)
+}
+
+func (s *Sym) Size() int {
+ return 4 + 2 + 1 + 1 + 4
+}
+
+// Symbol reference.
+type SymRef struct {
+ PkgIdx uint32
+ SymIdx uint32
+}
+
+func (s *SymRef) Write(w *Writer) {
+ w.Uint32(s.PkgIdx)
+ w.Uint32(s.SymIdx)
+}
+
+func (s *SymRef) Read(r *Reader, off uint32) {
+ s.PkgIdx = r.uint32At(off)
+ s.SymIdx = r.uint32At(off + 4)
+}
+
+func (s *SymRef) Size() int {
+ return 4 + 4
+}
+
+// Relocation.
+type Reloc struct {
+ Off int32
+ Siz uint8
+ Type uint8
+ Add int64
+ Sym SymRef
+}
+
+func (r *Reloc) Write(w *Writer) {
+ w.Uint32(uint32(r.Off))
+ w.Uint8(r.Siz)
+ w.Uint8(r.Type)
+ w.Uint64(uint64(r.Add))
+ r.Sym.Write(w)
+}
+
+func (o *Reloc) Read(r *Reader, off uint32) {
+ o.Off = r.int32At(off)
+ o.Siz = r.uint8At(off + 4)
+ o.Type = r.uint8At(off + 5)
+ o.Add = r.int64At(off + 6)
+ o.Sym.Read(r, off+14)
+}
+
+func (r *Reloc) Size() int {
+ return 4 + 1 + 1 + 8 + r.Sym.Size()
+}
+
+// Aux symbol info.
+type Aux struct {
+ Type uint8
+ Sym SymRef
+}
+
+// Aux Type
+const (
+ AuxGotype = iota
+ AuxFuncInfo
+ AuxFuncdata
+
+ // TODO: more. DWARF? Pcdata?
+)
+
+func (a *Aux) Write(w *Writer) {
+ w.Uint8(a.Type)
+ a.Sym.Write(w)
+}
+
+func (a *Aux) Read(r *Reader, off uint32) {
+ a.Type = r.uint8At(off)
+ a.Sym.Read(r, off+1)
+}
+
+func (a *Aux) Size() int {
+ return 1 + a.Sym.Size()
+}
+
+type Writer struct {
+ wr *bio.Writer
+ stringMap map[string]uint32
+ off uint32 // running offset
+}
+
+func NewWriter(wr *bio.Writer) *Writer {
+ return &Writer{wr: wr, stringMap: make(map[string]uint32)}
+}
+
+func (w *Writer) AddString(s string) {
+ if _, ok := w.stringMap[s]; ok {
+ return
+ }
+ w.stringMap[s] = w.off
+ w.Uint32(uint32(len(s)))
+ w.RawString(s)
+}
+
+func (w *Writer) StringRef(s string) {
+ off, ok := w.stringMap[s]
+ if !ok {
+ panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
+ }
+ w.Uint32(off)
+}
+
+func (w *Writer) RawString(s string) {
+ w.wr.WriteString(s)
+ w.off += uint32(len(s))
+}
+
+func (w *Writer) Bytes(s []byte) {
+ w.wr.Write(s)
+ w.off += uint32(len(s))
+}
+
+func (w *Writer) Uint64(x uint64) {
+ var b [8]byte
+ binary.LittleEndian.PutUint64(b[:], x)
+ w.wr.Write(b[:])
+ w.off += 8
+}
+
+func (w *Writer) Uint32(x uint32) {
+ var b [4]byte
+ binary.LittleEndian.PutUint32(b[:], x)
+ w.wr.Write(b[:])
+ w.off += 4
+}
+
+func (w *Writer) Uint16(x uint16) {
+ var b [2]byte
+ binary.LittleEndian.PutUint16(b[:], x)
+ w.wr.Write(b[:])
+ w.off += 2
+}
+
+func (w *Writer) Uint8(x uint8) {
+ w.wr.WriteByte(x)
+ w.off++
+}
+
+func (w *Writer) Offset() uint32 {
+ return w.off
+}
+
+type Reader struct {
+ b []byte // mmapped bytes, if not nil
+ readonly bool // whether b is backed with read-only memory
+
+ rd io.ReaderAt
+ start uint32
+ h Header // keep block offsets
+}
+
+func NewReader(rd io.ReaderAt, off uint32) *Reader {
+ r := &Reader{rd: rd, start: off}
+ err := r.h.Read(r)
+ if err != nil {
+ return nil
+ }
+ return r
+}
+
+func NewReaderFromBytes(b []byte, readonly bool) *Reader {
+ r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
+ err := r.h.Read(r)
+ if err != nil {
+ return nil
+ }
+ return r
+}
+
+func (r *Reader) BytesAt(off uint32, len int) []byte {
+ if len == 0 {
+ return nil
+ }
+ if r.b != nil {
+ end := int(off) + len
+ return r.b[int(off):end:end]
+ }
+ b := make([]byte, len)
+ _, err := r.rd.ReadAt(b, int64(r.start+off))
+ if err != nil {
+ panic("corrupted input")
+ }
+ return b
+}
+
+func (r *Reader) uint64At(off uint32) uint64 {
+ b := r.BytesAt(off, 8)
+ return binary.LittleEndian.Uint64(b)
+}
+
+func (r *Reader) int64At(off uint32) int64 {
+ return int64(r.uint64At(off))
+}
+
+func (r *Reader) uint32At(off uint32) uint32 {
+ b := r.BytesAt(off, 4)
+ return binary.LittleEndian.Uint32(b)
+}
+
+func (r *Reader) int32At(off uint32) int32 {
+ return int32(r.uint32At(off))
+}
+
+func (r *Reader) uint16At(off uint32) uint16 {
+ b := r.BytesAt(off, 2)
+ return binary.LittleEndian.Uint16(b)
+}
+
+func (r *Reader) uint8At(off uint32) uint8 {
+ b := r.BytesAt(off, 1)
+ return b[0]
+}
+
+func (r *Reader) StringAt(off uint32) string {
+ l := r.uint32At(off)
+ if r.b != nil {
+ b := r.b[off+4 : off+4+l]
+ if r.readonly {
+ return toString(b) // backed by RO memory, ok to make unsafe string
+ }
+ return string(b)
+ }
+ b := make([]byte, l)
+ n, err := r.rd.ReadAt(b, int64(r.start+off+4))
+ if n != int(l) || err != nil {
+ panic("corrupted input")
+ }
+ return string(b)
+}
+
+func toString(b []byte) string {
+ type stringHeader struct {
+ str unsafe.Pointer
+ len int
+ }
+
+ if len(b) == 0 {
+ return ""
+ }
+ ss := stringHeader{str: unsafe.Pointer(&b[0]), len: len(b)}
+ s := *(*string)(unsafe.Pointer(&ss))
+ return s
+}
+
+func (r *Reader) StringRef(off uint32) string {
+ return r.StringAt(r.uint32At(off))
+}
+
+func (r *Reader) Pkglist() []string {
+ n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / 4
+ s := make([]string, n)
+ for i := range s {
+ off := r.h.Offsets[BlkPkgIdx] + uint32(i)*4
+ s[i] = r.StringRef(off)
+ }
+ return s
+}
+
+func (r *Reader) NPkg() int {
+ return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / 4
+}
+
+func (r *Reader) Pkg(i int) string {
+ off := r.h.Offsets[BlkPkgIdx] + uint32(i)*4
+ return r.StringRef(off)
+}
+
+func (r *Reader) NDwarfFile() int {
+ return int(r.h.Offsets[BlkDwarfFile+1]-r.h.Offsets[BlkDwarfFile]) / 4
+}
+
+func (r *Reader) DwarfFile(i int) string {
+ off := r.h.Offsets[BlkDwarfFile] + uint32(i)*4
+ return r.StringRef(off)
+}
+
+func (r *Reader) NSym() int {
+ symsiz := (&Sym{}).Size()
+ return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / symsiz
+}
+
+func (r *Reader) NNonpkgdef() int {
+ symsiz := (&Sym{}).Size()
+ return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / symsiz
+}
+
+func (r *Reader) NNonpkgref() int {
+ symsiz := (&Sym{}).Size()
+ return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / symsiz
+}
+
+// SymOff returns the offset of the i-th symbol.
+func (r *Reader) SymOff(i int) uint32 {
+ symsiz := (&Sym{}).Size()
+ return r.h.Offsets[BlkSymdef] + uint32(i*symsiz)
+}
+
+// NReloc returns the number of relocations of the i-th symbol.
+func (r *Reader) NReloc(i int) int {
+ relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
+ return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
+}
+
+// RelocOff returns the offset of the j-th relocation of the i-th symbol.
+func (r *Reader) RelocOff(i int, j int) uint32 {
+ relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
+ relocIdx := r.uint32At(relocIdxOff)
+ relocsiz := (&Reloc{}).Size()
+ return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(relocsiz)
+}
+
+// NAux returns the number of aux symbols of the i-th symbol.
+func (r *Reader) NAux(i int) int {
+ auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
+ return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
+}
+
+// AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
+func (r *Reader) AuxOff(i int, j int) uint32 {
+ auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
+ auxIdx := r.uint32At(auxIdxOff)
+ auxsiz := (&Aux{}).Size()
+ return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(auxsiz)
+}
+
+// DataOff returns the offset of the i-th symbol's data.
+func (r *Reader) DataOff(i int) uint32 {
+ dataIdxOff := r.h.Offsets[BlkDataIdx] + uint32(i*4)
+ return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
+}
+
+// DataSize returns the size of the i-th symbol's data.
+func (r *Reader) DataSize(i int) int {
+ return int(r.DataOff(i+1) - r.DataOff(i))
+}
+
+// Data returns the i-th symbol's data.
+func (r *Reader) Data(i int) []byte {
+ return r.BytesAt(r.DataOff(i), r.DataSize(i))
+}
+
+// AuxDataBase returns the base offset of the aux data block.
+func (r *Reader) PcdataBase() uint32 {
+ return r.h.Offsets[BlkPcdata]
+}
+
+// ReadOnly returns whether r.BytesAt returns read-only bytes.
+func (r *Reader) ReadOnly() bool {
+ return r.readonly
+}
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 1c101bf..2c106ba 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -388,6 +388,10 @@
R []Reloc
Func *FuncInfo
+
+ Pkg string
+ PkgIdx int32
+ SymIdx int32 // TODO: replace RefIdx
}
// A FuncInfo contains extra fields for STEXT symbols.
@@ -409,6 +413,8 @@
GCLocals *LSym
GCRegs *LSym
StackObjects *LSym
+
+ FuncInfoSym *LSym
}
type InlMark struct {
@@ -460,7 +466,7 @@
)
// Attribute is a set of symbol attributes.
-type Attribute uint16
+type Attribute uint32
const (
AttrDuplicateOK Attribute = 1 << iota
@@ -501,6 +507,10 @@
// keep unwinding beyond this frame.
AttrTopFrame
+ // Indexed indicates this symbol has been assigned with an index (when using the
+ // new object file format).
+ AttrIndexed
+
// attrABIBase is the value at which the ABI is encoded in
// Attribute. This must be last; all bits after this are
// assumed to be an ABI value.
@@ -524,6 +534,7 @@
func (a Attribute) Static() bool { return a&AttrStatic != 0 }
func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 }
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 }
+func (a Attribute) Indexed() bool { return a&AttrIndexed != 0 }
func (a *Attribute) Set(flag Attribute, value bool) {
if value {
@@ -558,6 +569,7 @@
{bit: AttrStatic, s: "STATIC"},
{bit: AttrWasInlined, s: ""},
{bit: AttrTopFrame, s: "TOPFRAME"},
+ {bit: AttrIndexed, s: ""},
}
// TextAttrString formats a for printing in as part of a TEXT prog.
@@ -638,6 +650,7 @@
Flag_dynlink bool
Flag_optimize bool
Flag_locationlists bool
+ Flag_newobj bool // use new object file format
Bso *bufio.Writer
Pathname string
hashmu sync.Mutex // protects hash, funchash
@@ -671,6 +684,14 @@
// TODO(austin): Replace this with ABI wrappers once the ABIs
// actually diverge.
ABIAliases []*LSym
+
+ // pkgIdx maps package path to index. The index is used for
+ // symbol reference in the object file.
+ pkgIdx map[string]int32
+
+ defs []*LSym // list of defined symbols in the current package
+ nonpkgdefs []*LSym // list of defined non-package symbols
+ nonpkgrefs []*LSym // list of referenced non-package symbols
}
func (ctxt *Link) Diag(format string, args ...interface{}) {
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index ab5627c..76fbc58 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -8,6 +8,7 @@
import (
"bufio"
+ "cmd/internal/bio"
"cmd/internal/dwarf"
"cmd/internal/objabi"
"cmd/internal/sys"
@@ -80,7 +81,13 @@
}
}
-func WriteObjFile(ctxt *Link, b *bufio.Writer, pkgpath string) {
+func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
+ if ctxt.Flag_newobj {
+ WriteObjFile2(ctxt, bout, pkgpath)
+ return
+ }
+
+ b := bout.Writer
w := newObjWriter(ctxt, b, pkgpath)
// Magic header
@@ -221,8 +228,7 @@
}
}
-func (w *objWriter) writeSymDebug(s *LSym) {
- ctxt := w.ctxt
+func (ctxt *Link) writeSymDebug(s *LSym) {
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
@@ -302,7 +308,7 @@
func (w *objWriter) writeSym(s *LSym) {
ctxt := w.ctxt
if ctxt.Debugasm > 0 {
- w.writeSymDebug(s)
+ w.ctxt.writeSymDebug(s)
}
w.wr.WriteByte(symPrefix)
diff --git a/src/cmd/internal/obj/objfile2.go b/src/cmd/internal/obj/objfile2.go
new file mode 100644
index 0000000..c51be02
--- /dev/null
+++ b/src/cmd/internal/obj/objfile2.go
@@ -0,0 +1,363 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Writing Go object files.
+
+package obj
+
+import (
+ "bytes"
+ "cmd/internal/bio"
+ "cmd/internal/goobj2"
+ "cmd/internal/objabi"
+ "fmt"
+ "strings"
+)
+
+// Entry point of writing new object file.
+func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
+ if ctxt.Debugasm > 0 {
+ ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
+ }
+
+ genFuncInfoSyms(ctxt)
+
+ w := writer{
+ Writer: goobj2.NewWriter(b),
+ ctxt: ctxt,
+ pkgpath: objabi.PathToPrefix(pkgpath),
+ }
+
+ start := b.Offset()
+ w.init()
+
+ // Header
+ // We just reserve the space. We'll fill in the offsets later.
+ h := goobj2.Header{Magic: goobj2.Magic}
+ h.Write(w.Writer)
+
+ // String table
+ w.StringTable()
+
+ // Package references
+ h.Offsets[goobj2.BlkPkgIdx] = w.Offset()
+ for _, pkg := range w.pkglist {
+ w.StringRef(pkg)
+ }
+
+ // DWARF file table
+ h.Offsets[goobj2.BlkDwarfFile] = w.Offset()
+ for _, f := range ctxt.PosTable.DebugLinesFileTable() {
+ w.StringRef(f)
+ }
+
+ // Symbol definitions
+ h.Offsets[goobj2.BlkSymdef] = w.Offset()
+ for _, s := range ctxt.defs {
+ w.Sym(s)
+ }
+
+ // Non-pkg symbol definitions
+ h.Offsets[goobj2.BlkNonpkgdef] = w.Offset()
+ for _, s := range ctxt.nonpkgdefs {
+ w.Sym(s)
+ }
+
+ // Non-pkg symbol references
+ h.Offsets[goobj2.BlkNonpkgref] = w.Offset()
+ for _, s := range ctxt.nonpkgrefs {
+ w.Sym(s)
+ }
+
+ // Reloc indexes
+ h.Offsets[goobj2.BlkRelocIdx] = w.Offset()
+ nreloc := uint32(0)
+ lists := [][]*LSym{ctxt.defs, ctxt.nonpkgdefs}
+ for _, list := range lists {
+ for _, s := range list {
+ w.Uint32(nreloc)
+ nreloc += uint32(len(s.R))
+ }
+ }
+ w.Uint32(nreloc)
+
+ // Symbol Info indexes
+ h.Offsets[goobj2.BlkAuxIdx] = w.Offset()
+ naux := uint32(0)
+ for _, list := range lists {
+ for _, s := range list {
+ w.Uint32(naux)
+ if s.Gotype != nil {
+ naux++
+ }
+ if s.Func != nil {
+ // FuncInfo is an aux symbol, each Funcdata is an aux symbol
+ naux += 1 + uint32(len(s.Func.Pcln.Funcdata))
+ }
+ }
+ }
+ w.Uint32(naux)
+
+ // Data indexes
+ h.Offsets[goobj2.BlkDataIdx] = w.Offset()
+ dataOff := uint32(0)
+ for _, list := range lists {
+ for _, s := range list {
+ w.Uint32(dataOff)
+ dataOff += uint32(len(s.P))
+ }
+ }
+ w.Uint32(dataOff)
+
+ // Relocs
+ h.Offsets[goobj2.BlkReloc] = w.Offset()
+ for _, list := range lists {
+ for _, s := range list {
+ for i := range s.R {
+ w.Reloc(&s.R[i])
+ }
+ }
+ }
+
+ // Aux symbol info
+ h.Offsets[goobj2.BlkAux] = w.Offset()
+ for _, list := range lists {
+ for _, s := range list {
+ w.Aux(s)
+ }
+ }
+
+ // Data
+ h.Offsets[goobj2.BlkData] = w.Offset()
+ for _, list := range lists {
+ for _, s := range list {
+ w.Bytes(s.P)
+ }
+ }
+
+ // Pcdata
+ h.Offsets[goobj2.BlkPcdata] = w.Offset()
+ for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
+ if s.Func != nil {
+ pc := &s.Func.Pcln
+ w.Bytes(pc.Pcsp.P)
+ w.Bytes(pc.Pcfile.P)
+ w.Bytes(pc.Pcline.P)
+ w.Bytes(pc.Pcinline.P)
+ for i := range pc.Pcdata {
+ w.Bytes(pc.Pcdata[i].P)
+ }
+ }
+ }
+
+ // Fix up block offsets in the header
+ end := start + int64(w.Offset())
+ b.MustSeek(start, 0)
+ h.Write(w.Writer)
+ b.MustSeek(end, 0)
+}
+
+type writer struct {
+ *goobj2.Writer
+ ctxt *Link
+ pkgpath string // the package import path (escaped), "" if unknown
+ pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
+}
+
+// prepare package index list
+func (w *writer) init() {
+ w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
+ w.pkglist[0] = "" // dummy invalid package for index 0
+ for pkg, i := range w.ctxt.pkgIdx {
+ w.pkglist[i] = pkg
+ }
+
+ // Also make sure imported packages appear in the list (even if no symbol is referenced).
+ for _, pkg := range w.ctxt.Imports {
+ if _, ok := w.ctxt.pkgIdx[pkg]; !ok {
+ w.pkglist = append(w.pkglist, pkg)
+ }
+ }
+}
+
+func (w *writer) StringTable() {
+ w.AddString("")
+ for _, pkg := range w.ctxt.Imports {
+ w.AddString(pkg)
+ }
+ for _, pkg := range w.pkglist {
+ w.AddString(pkg)
+ }
+ w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
+ if w.pkgpath != "" {
+ s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
+ }
+ w.AddString(s.Name)
+ })
+ w.ctxt.traverseSyms(traverseDefs, func(s *LSym) {
+ if s.Type != objabi.STEXT {
+ return
+ }
+ pc := &s.Func.Pcln
+ for _, f := range pc.File {
+ w.AddString(f)
+ }
+ for _, call := range pc.InlTree.nodes {
+ f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
+ w.AddString(f)
+ }
+ })
+ for _, f := range w.ctxt.PosTable.DebugLinesFileTable() {
+ w.AddString(f)
+ }
+}
+
+func (w *writer) Sym(s *LSym) {
+ abi := uint16(s.ABI())
+ if s.Static() {
+ abi = goobj2.SymABIstatic
+ }
+ flag := uint8(0)
+ if s.DuplicateOK() {
+ flag |= goobj2.SymFlagDupok
+ }
+ if s.Local() {
+ flag |= goobj2.SymFlagLocal
+ }
+ if s.MakeTypelink() {
+ flag |= goobj2.SymFlagTypelink
+ }
+ o := goobj2.Sym{
+ Name: s.Name,
+ ABI: abi,
+ Type: uint8(s.Type),
+ Flag: flag,
+ Siz: uint32(s.Size),
+ }
+ o.Write(w.Writer)
+}
+
+func makeSymRef(s *LSym) goobj2.SymRef {
+ if s == nil {
+ return goobj2.SymRef{}
+ }
+ if s.PkgIdx == 0 || !s.Indexed() {
+ fmt.Printf("unindexed symbol reference: %v\n", s)
+ panic("unindexed symbol reference")
+ }
+ return goobj2.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
+}
+
+func (w *writer) Reloc(r *Reloc) {
+ o := goobj2.Reloc{
+ Off: r.Off,
+ Siz: r.Siz,
+ Type: uint8(r.Type),
+ Add: r.Add,
+ Sym: makeSymRef(r.Sym),
+ }
+ o.Write(w.Writer)
+}
+
+func (w *writer) Aux(s *LSym) {
+ if s.Gotype != nil {
+ o := goobj2.Aux{
+ Type: goobj2.AuxGotype,
+ Sym: makeSymRef(s.Gotype),
+ }
+ o.Write(w.Writer)
+ }
+ if s.Func != nil {
+ o := goobj2.Aux{
+ Type: goobj2.AuxFuncInfo,
+ Sym: makeSymRef(s.Func.FuncInfoSym),
+ }
+ o.Write(w.Writer)
+
+ for _, d := range s.Func.Pcln.Funcdata {
+ o := goobj2.Aux{
+ Type: goobj2.AuxFuncdata,
+ Sym: makeSymRef(d),
+ }
+ o.Write(w.Writer)
+ }
+ }
+}
+
+// generate symbols for FuncInfo.
+func genFuncInfoSyms(ctxt *Link) {
+ infosyms := make([]*LSym, 0, len(ctxt.Text))
+ var pcdataoff uint32
+ var b bytes.Buffer
+ symidx := int32(len(ctxt.defs))
+ for _, s := range ctxt.Text {
+ if s.Func == nil {
+ continue
+ }
+ nosplit := uint8(0)
+ if s.NoSplit() {
+ nosplit = 1
+ }
+ flags := uint8(0)
+ if s.Leaf() {
+ flags |= goobj2.FuncFlagLeaf
+ }
+ if s.CFunc() {
+ flags |= goobj2.FuncFlagCFunc
+ }
+ if s.ReflectMethod() {
+ flags |= goobj2.FuncFlagReflectMethod
+ }
+ if ctxt.Flag_shared { // This is really silly
+ flags |= goobj2.FuncFlagShared
+ }
+ if s.TopFrame() {
+ flags |= goobj2.FuncFlagTopFrame
+ }
+ o := goobj2.FuncInfo{
+ NoSplit: nosplit,
+ Flags: flags,
+ Args: uint32(s.Func.Args),
+ Locals: uint32(s.Func.Locals),
+ }
+ pc := &s.Func.Pcln
+ o.Pcsp = pcdataoff
+ pcdataoff += uint32(len(pc.Pcsp.P))
+ o.Pcfile = pcdataoff
+ pcdataoff += uint32(len(pc.Pcfile.P))
+ o.Pcline = pcdataoff
+ pcdataoff += uint32(len(pc.Pcline.P))
+ o.Pcinline = pcdataoff
+ pcdataoff += uint32(len(pc.Pcinline.P))
+ o.Pcdata = make([]uint32, len(pc.Pcdata))
+ for i, pcd := range pc.Pcdata {
+ o.Pcdata[i] = pcdataoff
+ pcdataoff += uint32(len(pcd.P))
+ }
+ o.PcdataEnd = pcdataoff
+ o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
+ for i, x := range pc.Funcdataoff {
+ o.Funcdataoff[i] = uint32(x)
+ }
+ o.File = make([]goobj2.SymRef, len(pc.File))
+ for i, f := range pc.File {
+ fsym := ctxt.Lookup(f)
+ o.File[i] = makeSymRef(fsym)
+ }
+
+ o.Write(&b)
+ isym := &LSym{
+ Type: objabi.SDATA, // for now, I don't think it matters
+ PkgIdx: goobj2.PkgIdxSelf,
+ SymIdx: symidx,
+ P: append([]byte(nil), b.Bytes()...),
+ }
+ isym.Set(AttrIndexed, true)
+ symidx++
+ infosyms = append(infosyms, isym)
+ s.Func.FuncInfoSym = isym
+ b.Reset()
+ }
+ ctxt.defs = append(ctxt.defs, infosyms...)
+}
diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go
index 05da9cc..ac65143b 100644
--- a/src/cmd/internal/obj/sizeof_test.go
+++ b/src/cmd/internal/obj/sizeof_test.go
@@ -21,7 +21,7 @@
_64bit uintptr // size on 64bit platforms
}{
{Addr{}, 32, 48},
- {LSym{}, 56, 104},
+ //{LSym{}, 56, 104}, // TODO: re-enable
{Prog{}, 132, 200},
}
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 15a501c..e72ec3e 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -32,6 +32,7 @@
package obj
import (
+ "cmd/internal/goobj2"
"cmd/internal/objabi"
"fmt"
"log"
@@ -78,6 +79,13 @@
// LookupABI looks up a symbol with the given ABI.
// If it does not exist, it creates it.
func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
+ return ctxt.LookupABIInit(name, abi, nil)
+}
+
+// LookupABI looks up a symbol with the given ABI.
+// If it does not exist, it creates it and
+// passes it to init for one-time initialization.
+func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
var hash map[string]*LSym
switch abi {
case ABI0:
@@ -94,6 +102,9 @@
s = &LSym{Name: name}
s.SetABI(abi)
hash[name] = s
+ if init != nil {
+ init(s)
+ }
}
ctxt.hashmu.Unlock()
return s
@@ -147,3 +158,117 @@
s.Set(AttrLocal, true)
})
}
+
+// Assign index to symbols.
+// asm is set to true if this is called by the assembler (i.e. not the compiler),
+// in which case all the symbols are non-package (for now).
+func (ctxt *Link) NumberSyms(asm bool) {
+ if !ctxt.Flag_newobj {
+ return
+ }
+
+ ctxt.pkgIdx = make(map[string]int32)
+ ctxt.defs = []*LSym{}
+ ctxt.nonpkgdefs = []*LSym{}
+
+ var idx, nonpkgidx int32 = 0, 0
+ ctxt.traverseSyms(traverseDefs, func(s *LSym) {
+ if asm || s.Pkg == "_" || s.DuplicateOK() {
+ s.PkgIdx = goobj2.PkgIdxNone
+ s.SymIdx = nonpkgidx
+ if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
+ panic("bad index")
+ }
+ ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
+ nonpkgidx++
+ } else {
+ s.PkgIdx = goobj2.PkgIdxSelf
+ s.SymIdx = idx
+ if idx != int32(len(ctxt.defs)) {
+ panic("bad index")
+ }
+ ctxt.defs = append(ctxt.defs, s)
+ idx++
+ }
+ s.Set(AttrIndexed, true)
+ })
+
+ ipkg := int32(1) // 0 is invalid index
+ nonpkgdef := nonpkgidx
+ ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
+ if rs.PkgIdx != goobj2.PkgIdxInvalid {
+ return
+ }
+ pkg := rs.Pkg
+ if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
+ rs.PkgIdx = goobj2.PkgIdxNone
+ rs.SymIdx = nonpkgidx
+ rs.Set(AttrIndexed, true)
+ if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
+ panic("bad index")
+ }
+ ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
+ nonpkgidx++
+ return
+ }
+ if k, ok := ctxt.pkgIdx[pkg]; ok {
+ rs.PkgIdx = k
+ return
+ }
+ rs.PkgIdx = ipkg
+ ctxt.pkgIdx[pkg] = ipkg
+ ipkg++
+ })
+}
+
+type traverseFlag uint32
+
+const (
+ traverseDefs traverseFlag = 1 << iota
+ traverseRefs
+ traverseAux
+
+ traverseAll = traverseDefs | traverseRefs | traverseAux
+)
+
+// Traverse symbols based on flag, call fn for each symbol.
+func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
+ lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
+ for _, list := range lists {
+ for _, s := range list {
+ if flag&traverseDefs != 0 {
+ fn(s)
+ }
+ if flag&traverseRefs != 0 {
+ for _, r := range s.R {
+ if r.Sym != nil {
+ fn(r.Sym)
+ }
+ }
+ }
+ if flag&traverseAux != 0 {
+ if s.Gotype != nil {
+ fn(s.Gotype)
+ }
+ if s.Type == objabi.STEXT {
+ pc := &s.Func.Pcln
+ for _, d := range pc.Funcdata {
+ if d != nil {
+ fn(d)
+ }
+ }
+ for _, f := range pc.File {
+ if fsym := ctxt.Lookup(f); fsym != nil {
+ fn(fsym)
+ }
+ }
+ for _, call := range pc.InlTree.nodes {
+ if call.Func != nil {
+ fn(call.Func)
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index fe16788..dbc7a59 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1085,13 +1085,13 @@
}
ptrsize := int64(p.ctxt.Arch.PtrSize)
- nptr := decodetypePtrdata(p.ctxt.Arch, typ) / ptrsize
+ nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / ptrsize
if debugGCProg {
fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
}
- if decodetypeUsegcprog(p.ctxt.Arch, typ) == 0 {
+ if decodetypeUsegcprog(p.ctxt.Arch, typ.P) == 0 {
// Copy pointers from mask into program.
mask := decodetypeGcmask(p.ctxt, typ)
for i := int64(0); i < nptr; i++ {
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index c880c0d..d0896fc 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -50,6 +50,11 @@
ctxt.Logf("%5.2f deadcode\n", Cputime())
}
+ if *flagNewobj {
+ deadcode2(ctxt)
+ return
+ }
+
d := &deadcodepass{
ctxt: ctxt,
ifaceMethod: make(map[methodsig]bool),
@@ -60,8 +65,8 @@
d.init()
d.flood()
- callSym := ctxt.Syms.ROLookup("reflect.Value.Call", sym.SymVerABIInternal)
- methSym := ctxt.Syms.ROLookup("reflect.Value.Method", sym.SymVerABIInternal)
+ callSym := ctxt.Lookup("reflect.Value.Call", sym.SymVerABIInternal)
+ methSym := ctxt.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
reflectSeen := false
if ctxt.DynlinkingGo() {
@@ -118,22 +123,70 @@
}
}
- for _, lib := range ctxt.Library {
- lib.Textp = lib.Textp[:0]
- }
+ addToTextp(ctxt)
+}
+func addToTextp(ctxt *Link) {
// Remove dead text but keep file information (z symbols).
- textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
+ textp := []*sym.Symbol{}
for _, s := range ctxt.Textp {
if s.Attr.Reachable() {
- if s.Unit != nil {
- s.Unit.Lib.Textp = append(s.Unit.Lib.Textp, s)
- s.Unit.Textp = append(s.Unit.Textp, s)
- }
textp = append(textp, s)
}
}
+
+ // Put reachable text symbols into Textp.
+ // do it in postorder so that packages are laid down in dependency order
+ // internal first, then everything else
+ ctxt.Library = postorder(ctxt.Library)
+ for _, doInternal := range [2]bool{true, false} {
+ for _, lib := range ctxt.Library {
+ if isRuntimeDepPkg(lib.Pkg) != doInternal {
+ continue
+ }
+ libtextp := lib.Textp[:0]
+ for _, s := range lib.Textp {
+ if s.Attr.Reachable() {
+ textp = append(textp, s)
+ libtextp = append(libtextp, s)
+ if s.Unit != nil {
+ s.Unit.Textp = append(s.Unit.Textp, s)
+ }
+ }
+ }
+ for _, s := range lib.DupTextSyms {
+ if s.Attr.Reachable() && !s.Attr.OnList() {
+ textp = append(textp, s)
+ libtextp = append(libtextp, s)
+ if s.Unit != nil {
+ s.Unit.Textp = append(s.Unit.Textp, s)
+ }
+ s.Attr |= sym.AttrOnList
+ // dupok symbols may be defined in multiple packages. its
+ // associated package is chosen sort of arbitrarily (the
+ // first containing package that the linker loads). canonicalize
+ // it here to the package with which it will be laid down
+ // in text.
+ s.File = objabi.PathToPrefix(lib.Pkg)
+ }
+ }
+ lib.Textp = libtextp
+ }
+ }
ctxt.Textp = textp
+
+ if len(ctxt.Shlibs) > 0 {
+ // We might have overwritten some functions above (this tends to happen for the
+ // autogenerated type equality/hashing functions) and we don't want to generated
+ // pcln table entries for these any more so remove them from Textp.
+ textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
+ for _, s := range ctxt.Textp {
+ if s.Type != sym.SDYNIMPORT {
+ textp = append(textp, s)
+ }
+ }
+ ctxt.Textp = textp
+ }
}
// methodref holds the relocations from a receiver type symbol to its
@@ -239,7 +292,7 @@
// We don't keep the go.plugin.exports symbol,
// but we do keep the symbols it refers to.
- exports := d.ctxt.Syms.ROLookup("go.plugin.exports", 0)
+ exports := d.ctxt.Lookup("go.plugin.exports", 0)
if exports != nil {
for i := range exports.R {
d.mark(exports.R[i].Sym, nil)
@@ -254,9 +307,9 @@
for _, name := range names {
// Mark symbol as an data/ABI0 symbol.
- d.mark(d.ctxt.Syms.ROLookup(name, 0), nil)
+ d.mark(d.ctxt.Lookup(name, 0), nil)
// Also mark any Go functions (internal ABI).
- d.mark(d.ctxt.Syms.ROLookup(name, sym.SymVerABIInternal), nil)
+ d.mark(d.ctxt.Lookup(name, sym.SymVerABIInternal), nil)
}
}
@@ -278,7 +331,7 @@
// later will give a better error than deadcode.
continue
}
- if decodetypeKind(d.ctxt.Arch, s)&kindMask == kindInterface {
+ if decodetypeKind(d.ctxt.Arch, s.P)&kindMask == kindInterface {
for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) {
if d.ctxt.Debugvlog > 1 {
d.ctxt.Logf("reached iface method: %s\n", sig)
diff --git a/src/cmd/link/internal/ld/deadcode2.go b/src/cmd/link/internal/ld/deadcode2.go
new file mode 100644
index 0000000..354d158
--- /dev/null
+++ b/src/cmd/link/internal/ld/deadcode2.go
@@ -0,0 +1,145 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "cmd/internal/objabi"
+ "cmd/internal/sys"
+ "cmd/link/internal/objfile"
+ "cmd/link/internal/sym"
+ "fmt"
+ "strings"
+)
+
+var _ = fmt.Print
+
+// TODO:
+// - Live method tracking:
+// Prune methods that are not directly called and cannot
+// be potentially called by interface or reflect call.
+// For now, all the methods from reachable type are alive.
+// - Shared object support:
+// It basically marks everything. We could consider using
+// a different mechanism to represent it.
+// - Field tracking support:
+// It needs to record from where the symbol is referenced.
+
+type workQueue []objfile.Sym
+
+func (q *workQueue) push(i objfile.Sym) { *q = append(*q, i) }
+func (q *workQueue) pop() objfile.Sym { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
+func (q *workQueue) empty() bool { return len(*q) == 0 }
+
+type deadcodePass2 struct {
+ ctxt *Link
+ loader *objfile.Loader
+ wq workQueue
+}
+
+func (d *deadcodePass2) init() {
+ d.loader.InitReachable()
+
+ var names []string
+
+ // In a normal binary, start at main.main and the init
+ // functions and mark what is reachable from there.
+ if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
+ names = append(names, "main.main", "main..inittask")
+ } else {
+ // The external linker refers main symbol directly.
+ if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
+ if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
+ *flagEntrySymbol = "_main"
+ } else {
+ *flagEntrySymbol = "main"
+ }
+ }
+ names = append(names, *flagEntrySymbol)
+ if d.ctxt.BuildMode == BuildModePlugin {
+ names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
+
+ // We don't keep the go.plugin.exports symbol,
+ // but we do keep the symbols it refers to.
+ exportsIdx := d.loader.Lookup("go.plugin.exports", 0)
+ if exportsIdx != 0 {
+ relocs := d.loader.Relocs(exportsIdx)
+ for i := 0; i < relocs.Count; i++ {
+ d.mark(relocs.At(i).Sym)
+ }
+ }
+ }
+ }
+ for _, s := range dynexp {
+ d.mark(d.loader.Lookup(s.Name, int(s.Version)))
+ }
+
+ for _, name := range names {
+ // Mark symbol as an data/ABI0 symbol.
+ d.mark(d.loader.Lookup(name, 0))
+ // Also mark any Go functions (internal ABI).
+ d.mark(d.loader.Lookup(name, sym.SymVerABIInternal))
+ }
+}
+
+func (d *deadcodePass2) flood() {
+ for !d.wq.empty() {
+ symIdx := d.wq.pop()
+ relocs := d.loader.Relocs(symIdx)
+ for i := 0; i < relocs.Count; i++ {
+ r := relocs.At(i)
+ if r.Type == objabi.R_WEAKADDROFF {
+ continue
+ }
+ if r.Type == objabi.R_METHODOFF {
+ // TODO: we should do something about it
+ // For now, all the methods are considered live
+ }
+ d.mark(r.Sym)
+ }
+ naux := d.loader.NAux(symIdx)
+ for i := 0; i < naux; i++ {
+ d.mark(d.loader.AuxSym(symIdx, i))
+ }
+ }
+}
+
+func (d *deadcodePass2) mark(symIdx objfile.Sym) {
+ if symIdx != 0 && !d.loader.Reachable.Has(symIdx) {
+ d.wq.push(symIdx)
+ d.loader.Reachable.Set(symIdx)
+ }
+}
+
+func deadcode2(ctxt *Link) {
+ loader := ctxt.loader
+ d := deadcodePass2{ctxt: ctxt, loader: loader}
+ d.init()
+ d.flood()
+
+ n := loader.NSym()
+ if ctxt.BuildMode != BuildModeShared {
+ // Keep a itablink if the symbol it points at is being kept.
+ // (When BuildModeShared, always keep itablinks.)
+ for i := 1; i < n; i++ {
+ s := objfile.Sym(i)
+ if strings.HasPrefix(loader.RawSymName(s), "go.itablink.") {
+ relocs := loader.Relocs(s)
+ if relocs.Count > 0 && loader.Reachable.Has(relocs.At(0).Sym) {
+ loader.Reachable.Set(s)
+ }
+ }
+ }
+ }
+
+ // Set reachable attr for now.
+ for i := 1; i < n; i++ {
+ if loader.Reachable.Has(objfile.Sym(i)) {
+ s := loader.Syms[i]
+ if s != nil && s.Name != "" {
+ s.Attr.Set(sym.AttrReachable, true)
+ }
+ }
+ }
+}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index 3afb389..3271c85 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -65,28 +65,28 @@
func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
// Type.commonType.kind
-func decodetypeKind(arch *sys.Arch, s *sym.Symbol) uint8 {
- return s.P[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
+func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
+ return p[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
}
// Type.commonType.kind
-func decodetypeUsegcprog(arch *sys.Arch, s *sym.Symbol) uint8 {
- return s.P[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
+func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
+ return p[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
}
// Type.commonType.size
-func decodetypeSize(arch *sys.Arch, s *sym.Symbol) int64 {
- return int64(decodeInuxi(arch, s.P, arch.PtrSize)) // 0x8 / 0x10
+func decodetypeSize(arch *sys.Arch, p []byte) int64 {
+ return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.ptrdata
-func decodetypePtrdata(arch *sys.Arch, s *sym.Symbol) int64 {
- return int64(decodeInuxi(arch, s.P[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
+func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
+ return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.tflag
-func decodetypeHasUncommon(arch *sys.Arch, s *sym.Symbol) bool {
- return s.P[2*arch.PtrSize+4]&tflagUncommon != 0
+func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
+ return p[2*arch.PtrSize+4]&tflagUncommon != 0
}
// Find the elf.Section of a given shared library that contains a given address.
@@ -138,7 +138,7 @@
func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
if s.Type == sym.SDYNIMPORT {
addr := decodetypeGcprogShlib(ctxt, s)
- ptrdata := decodetypePtrdata(ctxt.Arch, s)
+ ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
sect := findShlibSection(ctxt, s.File, addr)
if sect != nil {
r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
@@ -181,17 +181,17 @@
}
// Type.FuncType.dotdotdot
-func decodetypeFuncDotdotdot(arch *sys.Arch, s *sym.Symbol) bool {
- return uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2))&(1<<15) != 0
+func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
+ return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
}
// Type.FuncType.inCount
-func decodetypeFuncInCount(arch *sys.Arch, s *sym.Symbol) int {
- return int(decodeInuxi(arch, s.P[commonsize(arch):], 2))
+func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
+ return int(decodeInuxi(arch, p[commonsize(arch):], 2))
}
-func decodetypeFuncOutCount(arch *sys.Arch, s *sym.Symbol) int {
- return int(uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2)) & (1<<15 - 1))
+func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
+ return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
}
func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
@@ -199,14 +199,14 @@
if arch.PtrSize == 8 {
uadd += 4
}
- if decodetypeHasUncommon(arch, s) {
+ if decodetypeHasUncommon(arch, s.P) {
uadd += uncommonSize()
}
return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
}
func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
- return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s))
+ return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
}
// Type.StructType.fields.Slice::length
@@ -216,7 +216,7 @@
func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
off := commonsize(arch) + 4*arch.PtrSize
- if decodetypeHasUncommon(arch, s) {
+ if decodetypeHasUncommon(arch, s.P) {
off += uncommonSize()
}
off += i * structfieldSize(arch)
@@ -264,8 +264,8 @@
}
// InterfaceType.methods.length
-func decodetypeIfaceMethodCount(arch *sys.Arch, s *sym.Symbol) int64 {
- return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
+func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
+ return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}
// methodsig is a fully qualified typed method signature, like
@@ -299,7 +299,7 @@
mtypSym := decodeRelocSym(s, int32(off+4))
buf.WriteRune('(')
- inCount := decodetypeFuncInCount(arch, mtypSym)
+ inCount := decodetypeFuncInCount(arch, mtypSym.P)
for i := 0; i < inCount; i++ {
if i > 0 {
buf.WriteString(", ")
@@ -307,7 +307,7 @@
buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
}
buf.WriteString(") (")
- outCount := decodetypeFuncOutCount(arch, mtypSym)
+ outCount := decodetypeFuncOutCount(arch, mtypSym.P)
for i := 0; i < outCount; i++ {
if i > 0 {
buf.WriteString(", ")
@@ -324,7 +324,7 @@
}
func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
- if decodetypeKind(arch, s)&kindMask != kindInterface {
+ if decodetypeKind(arch, s.P)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
}
r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
@@ -335,17 +335,17 @@
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
}
off := int(r.Add) // array of reflect.imethod values
- numMethods := int(decodetypeIfaceMethodCount(arch, s))
+ numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
sizeofIMethod := 4 + 4
return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
}
func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
- if !decodetypeHasUncommon(arch, s) {
+ if !decodetypeHasUncommon(arch, s.P) {
panic(fmt.Sprintf("no methods on %q", s.Name))
}
off := commonsize(arch) // reflect.rtype
- switch decodetypeKind(arch, s) & kindMask {
+ switch decodetypeKind(arch, s.P) & kindMask {
case kindStruct: // reflect.structType
off += 4 * arch.PtrSize
case kindPtr: // reflect.ptrType
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index e426a6b..ebbfbb8 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -422,8 +422,8 @@
func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
name := gotype.Name[5:] // could also decode from Type.string
- kind := decodetypeKind(ctxt.Arch, gotype)
- bytesize := decodetypeSize(ctxt.Arch, gotype)
+ kind := decodetypeKind(ctxt.Arch, gotype.P)
+ bytesize := decodetypeSize(ctxt.Arch, gotype.P)
var die, typedefdie *dwarf.DWDie
switch kind {
@@ -488,17 +488,17 @@
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- nfields := decodetypeFuncInCount(ctxt.Arch, gotype)
+ nfields := decodetypeFuncInCount(ctxt.Arch, gotype.P)
for i := 0; i < nfields; i++ {
s := decodetypeFuncInType(ctxt.Arch, gotype, i)
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
}
- if decodetypeFuncDotdotdot(ctxt.Arch, gotype) {
+ if decodetypeFuncDotdotdot(ctxt.Arch, gotype.P) {
newdie(ctxt, die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
}
- nfields = decodetypeFuncOutCount(ctxt.Arch, gotype)
+ nfields = decodetypeFuncOutCount(ctxt.Arch, gotype.P)
for i := 0; i < nfields; i++ {
s := decodetypeFuncOutType(ctxt.Arch, gotype, i)
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
@@ -508,7 +508,7 @@
case objabi.KindInterface:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype))
+ nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype.P))
var s *sym.Symbol
if nfields == 0 {
s = lookupOrDiag(ctxt, "type.runtime.eface")
@@ -733,7 +733,7 @@
gotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol)
keytype := decodetypeMapKey(ctxt.Arch, gotype)
valtype := decodetypeMapValue(ctxt.Arch, gotype)
- keysize, valsize := decodetypeSize(ctxt.Arch, keytype), decodetypeSize(ctxt.Arch, valtype)
+ keysize, valsize := decodetypeSize(ctxt.Arch, keytype.P), decodetypeSize(ctxt.Arch, valtype.P)
keytype, valtype = walksymtypedef(ctxt, defgotype(ctxt, keytype)), walksymtypedef(ctxt, defgotype(ctxt, valtype))
// compute size info like hashmap.c does.
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 80d7ac3..13fbbed 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -111,7 +111,12 @@
}
p1 += p0
- loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
+ if *flagNewobj {
+ // loadcgo creates sym.Symbol. Delay this until all the symbols are added.
+ ctxt.cgodata = append(ctxt.cgodata, [3]string{filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1]})
+ } else {
+ loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
+ }
}
}
@@ -164,7 +169,7 @@
if i := strings.Index(remote, "#"); i >= 0 {
remote, q = remote[:i], remote[i+1:]
}
- s := ctxt.Syms.Lookup(local, 0)
+ s := ctxt.LookupOrCreate(local, 0)
if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ {
s.SetDynimplib(lib)
s.SetExtname(remote)
@@ -183,7 +188,7 @@
}
local := f[1]
- s := ctxt.Syms.Lookup(local, 0)
+ s := ctxt.LookupOrCreate(local, 0)
s.Type = sym.SHOSTOBJ
s.Size = 0
continue
@@ -204,7 +209,7 @@
// functions. Link.loadlib will resolve any
// ABI aliases we find here (since we may not
// yet know it's an alias).
- s := ctxt.Syms.Lookup(local, 0)
+ s := ctxt.LookupOrCreate(local, 0)
switch ctxt.BuildMode {
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 182e5b0..d030340 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -375,15 +375,8 @@
}
func (ctxt *Link) loadlib() {
- switch ctxt.BuildMode {
- case BuildModeCShared, BuildModePlugin:
- s := ctxt.Syms.Lookup("runtime.islibrary", 0)
- s.Attr |= sym.AttrDuplicateOK
- s.AddUint8(1)
- case BuildModeCArchive:
- s := ctxt.Syms.Lookup("runtime.isarchive", 0)
- s.Attr |= sym.AttrDuplicateOK
- s.AddUint8(1)
+ if *flagNewobj {
+ ctxt.loader = objfile.NewLoader()
}
loadinternal(ctxt, "runtime")
@@ -408,6 +401,52 @@
}
}
+ if *flagNewobj {
+ // Add references of externally defined symbols.
+ objfile.LoadRefs(ctxt.loader, ctxt.Arch, ctxt.Syms)
+
+ // Load cgo directives.
+ for _, p := range ctxt.cgodata {
+ loadcgo(ctxt, p[0], p[1], p[2])
+ }
+ }
+
+ iscgo = ctxt.Lookup("x_cgo_init", 0) != nil
+
+ // Record whether we can use plugins.
+ ctxt.canUsePlugins = (ctxt.Lookup("plugin.Open", sym.SymVerABIInternal) != nil)
+
+ // We now have enough information to determine the link mode.
+ determineLinkMode(ctxt)
+
+ // Now that we know the link mode, trim the dynexp list.
+ x := sym.AttrCgoExportDynamic
+
+ if ctxt.LinkMode == LinkExternal {
+ x = sym.AttrCgoExportStatic
+ }
+ w := 0
+ for i := range dynexp {
+ if dynexp[i].Attr&x != 0 {
+ dynexp[w] = dynexp[i]
+ w++
+ }
+ }
+ dynexp = dynexp[:w]
+
+ // Resolve ABI aliases in the list of cgo-exported functions.
+ // This is necessary because we load the ABI0 symbol for all
+ // cgo exports.
+ for i, s := range dynexp {
+ if s.Type != sym.SABIALIAS {
+ continue
+ }
+ t := resolveABIAlias(s)
+ t.Attr |= s.Attr
+ t.SetExtname(s.Extname())
+ dynexp[i] = t
+ }
+
for _, lib := range ctxt.Library {
if lib.Shlib != "" {
if ctxt.Debugvlog > 1 {
@@ -417,25 +456,6 @@
}
}
- iscgo = ctxt.Syms.ROLookup("x_cgo_init", 0) != nil
-
- // We now have enough information to determine the link mode.
- determineLinkMode(ctxt)
-
- // Recalculate pe parameters now that we have ctxt.LinkMode set.
- if ctxt.HeadType == objabi.Hwindows {
- Peinit(ctxt)
- }
-
- if ctxt.HeadType == objabi.Hdarwin && ctxt.LinkMode == LinkExternal {
- *FlagTextAddr = 0
- }
-
- if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
- toc := ctxt.Syms.Lookup(".TOC.", 0)
- toc.Type = sym.SDYNIMPORT
- }
-
if ctxt.LinkMode == LinkExternal && !iscgo && ctxt.LibraryByPkg["runtime/cgo"] == nil && !(objabi.GOOS == "darwin" && (ctxt.Arch.Family == sys.AMD64 || ctxt.Arch.Family == sys.I386)) {
// This indicates a user requested -linkmode=external.
// The startup code uses an import of runtime/cgo to decide
@@ -453,7 +473,8 @@
}
}
- if ctxt.LinkMode == LinkInternal {
+ // In internal link mode, read the host object files.
+ if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
// Drop all the cgo_import_static declarations.
// Turns out we won't be needing them.
for _, s := range ctxt.Syms.Allsym {
@@ -469,6 +490,104 @@
}
}
}
+
+ hostobjs(ctxt)
+
+ // If we have any undefined symbols in external
+ // objects, try to read them from the libgcc file.
+ any := false
+ for _, s := range ctxt.Syms.Allsym {
+ for i := range s.R {
+ r := &s.R[i] // Copying sym.Reloc has measurable impact on performance
+ if r.Sym != nil && r.Sym.Type == sym.SXREF && r.Sym.Name != ".got" {
+ any = true
+ break
+ }
+ }
+ }
+ if any {
+ if *flagLibGCC == "" {
+ *flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
+ }
+ if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
+ // On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
+ // In this case we fail to load libgcc.a and can encounter link
+ // errors - see if we can find libcompiler_rt.a instead.
+ *flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
+ }
+ if *flagLibGCC != "none" {
+ hostArchive(ctxt, *flagLibGCC)
+ }
+ if ctxt.HeadType == objabi.Hwindows {
+ if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
+ hostArchive(ctxt, p)
+ }
+ if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
+ hostArchive(ctxt, p)
+ }
+ // TODO: maybe do something similar to peimporteddlls to collect all lib names
+ // and try link them all to final exe just like libmingwex.a and libmingw32.a:
+ /*
+ for:
+ #cgo windows LDFLAGS: -lmsvcrt -lm
+ import:
+ libmsvcrt.a libm.a
+ */
+ }
+ }
+ } else if ctxt.LinkMode == LinkExternal {
+ hostlinksetup(ctxt)
+ }
+
+ // We've loaded all the code now.
+ ctxt.Loaded = true
+
+ importcycles()
+}
+
+// Set up flags and special symbols depending on the platform build mode.
+func (ctxt *Link) linksetup() {
+ switch ctxt.BuildMode {
+ case BuildModeCShared, BuildModePlugin:
+ s := ctxt.Syms.Lookup("runtime.islibrary", 0)
+ s.Type = sym.SNOPTRDATA
+ s.Attr |= sym.AttrDuplicateOK
+ s.AddUint8(1)
+ case BuildModeCArchive:
+ s := ctxt.Syms.Lookup("runtime.isarchive", 0)
+ s.Type = sym.SNOPTRDATA
+ s.Attr |= sym.AttrDuplicateOK
+ s.AddUint8(1)
+ }
+
+ // Recalculate pe parameters now that we have ctxt.LinkMode set.
+ if ctxt.HeadType == objabi.Hwindows {
+ Peinit(ctxt)
+ }
+
+ if ctxt.HeadType == objabi.Hdarwin && ctxt.LinkMode == LinkExternal {
+ *FlagTextAddr = 0
+ }
+
+ // If there are no dynamic libraries needed, gcc disables dynamic linking.
+ // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
+ // assumes that a dynamic binary always refers to at least one dynamic library.
+ // Rather than be a source of test cases for glibc, disable dynamic linking
+ // the same way that gcc would.
+ //
+ // Exception: on OS X, programs such as Shark only work with dynamic
+ // binaries, so leave it enabled on OS X (Mach-O) binaries.
+ // Also leave it enabled on Solaris which doesn't support
+ // statically linked binaries.
+ if ctxt.BuildMode == BuildModeExe {
+ if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
+ *FlagD = true
+ }
+ }
+
+ if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
+ toc := ctxt.Syms.Lookup(".TOC.", 0)
+ toc.Type = sym.SDYNIMPORT
}
// The Android Q linker started to complain about underalignment of the our TLS
@@ -531,93 +650,6 @@
moduledata.Attr |= sym.AttrReachable
ctxt.Moduledata = moduledata
- // Now that we know the link mode, trim the dynexp list.
- x := sym.AttrCgoExportDynamic
-
- if ctxt.LinkMode == LinkExternal {
- x = sym.AttrCgoExportStatic
- }
- w := 0
- for i := range dynexp {
- if dynexp[i].Attr&x != 0 {
- dynexp[w] = dynexp[i]
- w++
- }
- }
- dynexp = dynexp[:w]
-
- // In internal link mode, read the host object files.
- if ctxt.LinkMode == LinkInternal {
- hostobjs(ctxt)
-
- // If we have any undefined symbols in external
- // objects, try to read them from the libgcc file.
- any := false
- for _, s := range ctxt.Syms.Allsym {
- for i := range s.R {
- r := &s.R[i] // Copying sym.Reloc has measurable impact on performance
- if r.Sym != nil && r.Sym.Type == sym.SXREF && r.Sym.Name != ".got" {
- any = true
- break
- }
- }
- }
- if any {
- if *flagLibGCC == "" {
- *flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
- }
- if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
- // On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
- // In this case we fail to load libgcc.a and can encounter link
- // errors - see if we can find libcompiler_rt.a instead.
- *flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
- }
- if *flagLibGCC != "none" {
- hostArchive(ctxt, *flagLibGCC)
- }
- if ctxt.HeadType == objabi.Hwindows {
- if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
- hostArchive(ctxt, p)
- }
- if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
- hostArchive(ctxt, p)
- }
- // TODO: maybe do something similar to peimporteddlls to collect all lib names
- // and try link them all to final exe just like libmingwex.a and libmingw32.a:
- /*
- for:
- #cgo windows LDFLAGS: -lmsvcrt -lm
- import:
- libmsvcrt.a libm.a
- */
- }
- }
- } else {
- hostlinksetup(ctxt)
- }
-
- // We've loaded all the code now.
- ctxt.Loaded = true
-
- // Record whether we can use plugins.
- ctxt.canUsePlugins = (ctxt.Syms.ROLookup("plugin.Open", sym.SymVerABIInternal) != nil)
-
- // If there are no dynamic libraries needed, gcc disables dynamic linking.
- // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
- // assumes that a dynamic binary always refers to at least one dynamic library.
- // Rather than be a source of test cases for glibc, disable dynamic linking
- // the same way that gcc would.
- //
- // Exception: on OS X, programs such as Shark only work with dynamic
- // binaries, so leave it enabled on OS X (Mach-O) binaries.
- // Also leave it enabled on Solaris which doesn't support
- // statically linked binaries.
- if ctxt.BuildMode == BuildModeExe {
- if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
- *FlagD = true
- }
- }
-
// If package versioning is required, generate a hash of the
// packages used in the link.
if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() {
@@ -635,59 +667,6 @@
got.Attr |= sym.AttrReachable
}
}
-
- importcycles()
-
- // put symbols into Textp
- // do it in postorder so that packages are laid down in dependency order
- // internal first, then everything else
- ctxt.Library = postorder(ctxt.Library)
- for _, doInternal := range [2]bool{true, false} {
- for _, lib := range ctxt.Library {
- if isRuntimeDepPkg(lib.Pkg) != doInternal {
- continue
- }
- ctxt.Textp = append(ctxt.Textp, lib.Textp...)
- for _, s := range lib.DupTextSyms {
- if !s.Attr.OnList() {
- ctxt.Textp = append(ctxt.Textp, s)
- s.Attr |= sym.AttrOnList
- // dupok symbols may be defined in multiple packages. its
- // associated package is chosen sort of arbitrarily (the
- // first containing package that the linker loads). canonicalize
- // it here to the package with which it will be laid down
- // in text.
- s.File = objabi.PathToPrefix(lib.Pkg)
- }
- }
- }
- }
-
- if len(ctxt.Shlibs) > 0 {
- // We might have overwritten some functions above (this tends to happen for the
- // autogenerated type equality/hashing functions) and we don't want to generated
- // pcln table entries for these any more so remove them from Textp.
- textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
- for _, s := range ctxt.Textp {
- if s.Type != sym.SDYNIMPORT {
- textp = append(textp, s)
- }
- }
- ctxt.Textp = textp
- }
-
- // Resolve ABI aliases in the list of cgo-exported functions.
- // This is necessary because we load the ABI0 symbol for all
- // cgo exports.
- for i, s := range dynexp {
- if s.Type != sym.SABIALIAS {
- continue
- }
- t := resolveABIAlias(s)
- t.Attr |= s.Attr
- t.SetExtname(s.Extname())
- dynexp[i] = t
- }
}
// mangleTypeSym shortens the names of symbols that represent Go types
@@ -1773,7 +1752,12 @@
default:
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
}
- c := objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, unit, eof-f.Offset(), pn, flags)
+ var c int
+ if *flagNewobj {
+ objfile.LoadNew(ctxt.loader, ctxt.Arch, ctxt.Syms, f, lib, unit, eof-f.Offset(), pn, flags)
+ } else {
+ c = objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, unit, eof-f.Offset(), pn, flags)
+ }
strictDupMsgCount += c
addImports(ctxt, lib, pn)
return nil
@@ -1928,7 +1912,7 @@
ver = sym.SymVerABIInternal
}
- lsym := ctxt.Syms.Lookup(elfsym.Name, ver)
+ lsym := ctxt.LookupOrCreate(elfsym.Name, ver)
// Because loadlib above loads all .a files before loading any shared
// libraries, any non-dynimport symbols we find that duplicate symbols
// already loaded should be ignored (the symbols from the .a files
@@ -2545,3 +2529,30 @@
mark[lib] = visited
*order = append(*order, lib)
}
+
+func (ctxt *Link) loadlibfull() {
+ // Load full symbol contents, resolve indexed references.
+ objfile.LoadReloc(ctxt.loader)
+ objfile.LoadFull(ctxt.loader)
+
+ // For now, add all symbols to ctxt.Syms.
+ for _, s := range ctxt.loader.Syms {
+ if s != nil && s.Name != "" {
+ ctxt.Syms.Add(s)
+ }
+ }
+
+ // Drop the reference.
+ ctxt.loader = nil
+
+ addToTextp(ctxt)
+}
+
+func (ctxt *Link) dumpsyms() {
+ for _, s := range ctxt.Syms.Allsym {
+ fmt.Printf("%s %s %p\n", s, s.Type, s)
+ for i := range s.R {
+ fmt.Println("\t", s.R[i].Type, s.R[i].Sym)
+ }
+ }
+}
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index 53092d2..dfb686f 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -35,6 +35,7 @@
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/objfile"
"cmd/link/internal/sym"
"debug/elf"
"fmt"
@@ -96,6 +97,9 @@
runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen.
relocbuf []byte // temporary buffer for applying relocations
+
+ loader *objfile.Loader
+ cgodata [][3]string // cgo directives to load, three strings are args for loadcgo
}
type unresolvedSymKey struct {
@@ -172,3 +176,32 @@
}
l.ImportStrings = nil
}
+
+// convenient helper during the transition period.
+func (ctxt *Link) Lookup(name string, ver int) *sym.Symbol {
+ if *flagNewobj {
+ i := ctxt.loader.Lookup(name, ver)
+ if i == 0 {
+ return nil
+ }
+ return ctxt.loader.Syms[i]
+ } else {
+ return ctxt.Syms.ROLookup(name, ver)
+ }
+}
+
+// convenient helper during the transition period.
+func (ctxt *Link) LookupOrCreate(name string, ver int) *sym.Symbol {
+ if *flagNewobj {
+ i := ctxt.loader.Lookup(name, ver)
+ if i != 0 {
+ return ctxt.loader.Syms[i]
+ }
+ ctxt.loader.AddExtSym(name, ver)
+ s := ctxt.Syms.Newsym(name, ver)
+ ctxt.loader.Syms = append(ctxt.loader.Syms, s)
+ return s
+ } else {
+ return ctxt.Syms.Lookup(name, ver)
+ }
+}
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 67e5ef9..e667afe 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -86,6 +86,7 @@
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
+ flagNewobj = flag.Bool("newobj", false, "use new object file format")
FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
@@ -207,8 +208,13 @@
}
ctxt.loadlib()
- ctxt.dostrdata()
deadcode(ctxt)
+ if *flagNewobj {
+ ctxt.loadlibfull() // XXX do it here for now
+ }
+ ctxt.linksetup()
+ ctxt.dostrdata()
+
dwarfGenerateDebugInfo(ctxt)
if objabi.Fieldtrack_enabled != 0 {
fieldtrack(ctxt)
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index d686a8a..98305c8 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -693,7 +693,7 @@
// creating the moduledata from scratch and it does not have a
// compiler-provided size, so read it from the type data.
moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0)
- moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype)
+ moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype.P)
moduledata.Grow(moduledata.Size)
lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
diff --git a/src/cmd/link/internal/objfile/objfile2.go b/src/cmd/link/internal/objfile/objfile2.go
new file mode 100644
index 0000000..ad3ea85
--- /dev/null
+++ b/src/cmd/link/internal/objfile/objfile2.go
@@ -0,0 +1,740 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package objfile
+
+import (
+ "bytes"
+ "cmd/internal/bio"
+ "cmd/internal/dwarf"
+ "cmd/internal/goobj2"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/sys"
+ "cmd/link/internal/sym"
+ "fmt"
+ "log"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+var _ = fmt.Print
+
+// Sym encapsulates a global symbol index, used to identify a specific
+// Go symbol. The 0-valued Sym is corresponds to an invalid symbol.
+type Sym int
+
+// Relocs encapsulates the set of relocations on a given symbol; an
+// instance of this type is returned by the Loader Relocs() method.
+type Relocs struct {
+ Count int // number of relocs
+
+ li int // local index of symbol whose relocs we're examining
+ r *oReader // object reader for containing package
+ l *Loader // loader
+}
+
+// Reloc contains the payload for a specific relocation.
+// TODO: replace this with sym.Reloc, once we change the
+// relocation target from "*sym.Symbol" to "loader.Sym" in sym.Reloc.
+type Reloc struct {
+ Off int32 // offset to rewrite
+ Size uint8 // number of bytes to rewrite: 0, 1, 2, or 4
+ Type objabi.RelocType // the relocation type
+ Add int64 // addend
+ Sym Sym // global index of symbol the reloc addresses
+}
+
+// oReader is a wrapper type of obj.Reader, along with some
+// extra information.
+// TODO: rename to objReader once the old one is gone?
+type oReader struct {
+ *goobj2.Reader
+ unit *sym.CompilationUnit
+ version int // version of static symbol
+ pkgprefix string
+}
+
+type objIdx struct {
+ r *oReader
+ i Sym // start index
+}
+
+type nameVer struct {
+ name string
+ v int
+}
+
+type bitmap []uint32
+
+// set the i-th bit.
+func (bm bitmap) Set(i Sym) {
+ n, r := uint(i)/32, uint(i)%32
+ bm[n] |= 1 << r
+}
+
+// whether the i-th bit is set.
+func (bm bitmap) Has(i Sym) bool {
+ n, r := uint(i)/32, uint(i)%32
+ return bm[n]&(1<<r) != 0
+}
+
+func makeBitmap(n int) bitmap {
+ return make(bitmap, (n+31)/32)
+}
+
+// A Loader loads new object files and resolves indexed symbol references.
+//
+// TODO: describe local-global index mapping.
+type Loader struct {
+ start map[*oReader]Sym // map from object file to its start index
+ objs []objIdx // sorted by start index (i.e. objIdx.i)
+ max Sym // current max index
+ extStart Sym // from this index on, the symbols are externally defined
+
+ symsByName map[nameVer]Sym // map symbol name to index
+
+ objByPkg map[string]*oReader // map package path to its Go object reader
+
+ Syms []*sym.Symbol // indexed symbols. XXX we still make sym.Symbol for now.
+
+ Reachable bitmap // bitmap of reachable symbols, indexed by global index
+}
+
+func NewLoader() *Loader {
+ return &Loader{
+ start: make(map[*oReader]Sym),
+ objs: []objIdx{{nil, 0}},
+ symsByName: make(map[nameVer]Sym),
+ objByPkg: make(map[string]*oReader),
+ Syms: []*sym.Symbol{nil},
+ }
+}
+
+// Return the start index in the global index space for a given object file.
+func (l *Loader) StartIndex(r *oReader) Sym {
+ return l.start[r]
+}
+
+// Add object file r, return the start index.
+func (l *Loader) AddObj(pkg string, r *oReader) Sym {
+ if _, ok := l.start[r]; ok {
+ panic("already added")
+ }
+ pkg = objabi.PathToPrefix(pkg) // the object file contains escaped package path
+ if _, ok := l.objByPkg[pkg]; !ok {
+ l.objByPkg[pkg] = r
+ }
+ n := r.NSym() + r.NNonpkgdef()
+ i := l.max + 1
+ l.start[r] = i
+ l.objs = append(l.objs, objIdx{r, i})
+ l.max += Sym(n)
+ return i
+}
+
+// Add a symbol with a given index, return if it is added.
+func (l *Loader) AddSym(name string, ver int, i Sym, dupok bool) bool {
+ if l.extStart != 0 {
+ panic("AddSym called after AddExtSym is called")
+ }
+ nv := nameVer{name, ver}
+ if _, ok := l.symsByName[nv]; ok {
+ if dupok || true { // TODO: "true" isn't quite right. need to implement "overwrite" logic.
+ return false
+ }
+ panic("duplicated definition of symbol " + name)
+ }
+ l.symsByName[nv] = i
+ return true
+}
+
+// Add an external symbol (without index). Return the index of newly added
+// symbol, or 0 if not added.
+func (l *Loader) AddExtSym(name string, ver int) Sym {
+ nv := nameVer{name, ver}
+ if _, ok := l.symsByName[nv]; ok {
+ return 0
+ }
+ i := l.max + 1
+ l.symsByName[nv] = i
+ l.max++
+ if l.extStart == 0 {
+ l.extStart = i
+ }
+ return i
+}
+
+// Convert a local index to a global index.
+func (l *Loader) ToGlobal(r *oReader, i int) Sym {
+ return l.StartIndex(r) + Sym(i)
+}
+
+// Convert a global index to a local index.
+func (l *Loader) ToLocal(i Sym) (*oReader, int) {
+ if l.extStart != 0 && i >= l.extStart {
+ return nil, int(i - l.extStart)
+ }
+ // Search for the local object holding index i.
+ // Below k is the first one that has its start index > i,
+ // so k-1 is the one we want.
+ k := sort.Search(len(l.objs), func(k int) bool {
+ return l.objs[k].i > i
+ })
+ return l.objs[k-1].r, int(i - l.objs[k-1].i)
+}
+
+// Resolve a local symbol reference. Return global index.
+func (l *Loader) Resolve(r *oReader, s goobj2.SymRef) Sym {
+ var rr *oReader
+ switch p := s.PkgIdx; p {
+ case goobj2.PkgIdxInvalid:
+ if s.SymIdx != 0 {
+ panic("bad sym ref")
+ }
+ return 0
+ case goobj2.PkgIdxNone:
+ // Resolve by name
+ i := int(s.SymIdx) + r.NSym()
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(i))
+ name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
+ v := abiToVer(osym.ABI, r.version)
+ nv := nameVer{name, v}
+ return l.symsByName[nv]
+ case goobj2.PkgIdxBuiltin:
+ panic("PkgIdxBuiltin not used")
+ case goobj2.PkgIdxSelf:
+ rr = r
+ default:
+ pkg := r.Pkg(int(p))
+ var ok bool
+ rr, ok = l.objByPkg[pkg]
+ if !ok {
+ log.Fatalf("reference of nonexisted package %s, from %v", pkg, r.unit.Lib)
+ }
+ }
+ return l.ToGlobal(rr, int(s.SymIdx))
+}
+
+// Look up a symbol by name, return global index, or 0 if not found.
+// This is more like Syms.ROLookup than Lookup -- it doesn't create
+// new symbol.
+func (l *Loader) Lookup(name string, ver int) Sym {
+ nv := nameVer{name, ver}
+ return l.symsByName[nv]
+}
+
+// Number of total symbols.
+func (l *Loader) NSym() int {
+ return int(l.max + 1)
+}
+
+// Returns the raw (unpatched) name of the i-th symbol.
+func (l *Loader) RawSymName(i Sym) string {
+ r, li := l.ToLocal(i)
+ if r == nil {
+ return ""
+ }
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(li))
+ return osym.Name
+}
+
+// Returns the (patched) name of the i-th symbol.
+func (l *Loader) SymName(i Sym) string {
+ r, li := l.ToLocal(i)
+ if r == nil {
+ return ""
+ }
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(li))
+ return strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
+}
+
+// Returns the type of the i-th symbol.
+func (l *Loader) SymType(i Sym) sym.SymKind {
+ r, li := l.ToLocal(i)
+ if r == nil {
+ return 0
+ }
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(li))
+ return sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
+}
+
+// Returns the number of aux symbols given a global index.
+func (l *Loader) NAux(i Sym) int {
+ r, li := l.ToLocal(i)
+ if r == nil {
+ return 0
+ }
+ return r.NAux(li)
+}
+
+// Returns the referred symbol of the j-th aux symbol of the i-th
+// symbol.
+func (l *Loader) AuxSym(i Sym, j int) Sym {
+ r, li := l.ToLocal(i)
+ a := goobj2.Aux{}
+ a.Read(r.Reader, r.AuxOff(li, j))
+ return l.Resolve(r, a.Sym)
+}
+
+// Initialize Reachable bitmap for running deadcode pass.
+func (l *Loader) InitReachable() {
+ l.Reachable = makeBitmap(l.NSym())
+}
+
+// At method returns the j-th reloc for a global symbol.
+func (relocs *Relocs) At(j int) Reloc {
+ rel := goobj2.Reloc{}
+ rel.Read(relocs.r.Reader, relocs.r.RelocOff(relocs.li, j))
+ target := relocs.l.Resolve(relocs.r, rel.Sym)
+ return Reloc{
+ Off: rel.Off,
+ Size: rel.Siz,
+ Type: objabi.RelocType(rel.Type),
+ Add: rel.Add,
+ Sym: target,
+ }
+}
+
+// Relocs returns a Relocs object for the given global sym.
+func (l *Loader) Relocs(i Sym) Relocs {
+ r, li := l.ToLocal(i)
+ if r == nil {
+ return Relocs{}
+ }
+ return l.relocs(r, li)
+}
+
+// Relocs returns a Relocs object given a local sym index and reader.
+func (l *Loader) relocs(r *oReader, li int) Relocs {
+ return Relocs{
+ Count: r.NReloc(li),
+ li: li,
+ r: r,
+ l: l,
+ }
+}
+
+// Preload a package: add autolibs, add symbols to the symbol table.
+// Does not read symbol data yet.
+func LoadNew(l *Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) {
+ roObject, readonly, err := f.Slice(uint64(length))
+ if err != nil {
+ log.Fatal("cannot read object file:", err)
+ }
+ r := goobj2.NewReaderFromBytes(roObject, readonly)
+ if r == nil {
+ panic("cannot read object file")
+ }
+ localSymVersion := syms.IncVersion()
+ pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
+ or := &oReader{r, unit, localSymVersion, pkgprefix}
+
+ // Autolib
+ npkg := r.NPkg()
+ lib.ImportStrings = append(lib.ImportStrings, make([]string, npkg-1)...)[:len(lib.ImportStrings)]
+ for i := 1; i < npkg; i++ {
+ lib.ImportStrings = append(lib.ImportStrings, r.Pkg(i))
+ }
+
+ // DWARF file table
+ nfile := r.NDwarfFile()
+ unit.DWARFFileTable = make([]string, nfile)
+ for i := range unit.DWARFFileTable {
+ unit.DWARFFileTable[i] = r.DwarfFile(i)
+ }
+
+ istart := l.AddObj(lib.Pkg, or)
+
+ ndef := r.NSym()
+ nnonpkgdef := r.NNonpkgdef()
+
+ // XXX add all symbols for now
+ l.Syms = append(l.Syms, make([]*sym.Symbol, ndef+nnonpkgdef)...)
+ for i, n := 0, ndef+nnonpkgdef; i < n; i++ {
+ osym := goobj2.Sym{}
+ osym.Read(r, r.SymOff(i))
+ name := strings.Replace(osym.Name, "\"\".", pkgprefix, -1)
+ if name == "" {
+ continue // don't add unnamed aux symbol
+ }
+ v := abiToVer(osym.ABI, localSymVersion)
+ dupok := osym.Flag&goobj2.SymFlagDupok != 0
+ if l.AddSym(name, v, istart+Sym(i), dupok) {
+ s := syms.Newsym(name, v)
+ preprocess(arch, s) // TODO: put this at a better place
+ l.Syms[istart+Sym(i)] = s
+ }
+ }
+
+ // The caller expects us consuming all the data
+ f.MustSeek(length, os.SEEK_CUR)
+}
+
+// Make sure referenced symbols are added. Most of them should already be added.
+// This should only be needed for referenced external symbols.
+func LoadRefs(l *Loader, arch *sys.Arch, syms *sym.Symbols) {
+ for _, o := range l.objs[1:] {
+ loadObjRefs(l, o.r, arch, syms)
+ }
+}
+
+func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch, syms *sym.Symbols) {
+ lib := r.unit.Lib
+ pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
+ ndef := r.NSym() + r.NNonpkgdef()
+ for i, n := 0, r.NNonpkgref(); i < n; i++ {
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(ndef+i))
+ name := strings.Replace(osym.Name, "\"\".", pkgprefix, -1)
+ v := abiToVer(osym.ABI, r.version)
+ if ii := l.AddExtSym(name, v); ii != 0 {
+ s := syms.Newsym(name, v)
+ preprocess(arch, s) // TODO: put this at a better place
+ if ii != Sym(len(l.Syms)) {
+ panic("AddExtSym returned bad index")
+ }
+ l.Syms = append(l.Syms, s)
+ }
+ }
+}
+
+func abiToVer(abi uint16, localSymVersion int) int {
+ var v int
+ if abi == goobj2.SymABIstatic {
+ // Static
+ v = localSymVersion
+ } else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
+ // Note that data symbols are "ABI0", which maps to version 0.
+ v = abiver
+ } else {
+ log.Fatalf("invalid symbol ABI: %d", abi)
+ }
+ return v
+}
+
+func preprocess(arch *sys.Arch, s *sym.Symbol) {
+ if s.Name != "" && 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 = sym.SRODATA
+ s.Attr |= sym.AttrLocal
+ switch s.Name[:5] {
+ case "$f32.":
+ if uint64(uint32(x)) != x {
+ log.Panicf("$-symbol %s too large: %d", s.Name, x)
+ }
+ s.AddUint32(arch, uint32(x))
+ case "$f64.", "$i64.":
+ s.AddUint64(arch, x)
+ default:
+ log.Panicf("unrecognized $-symbol: %s", s.Name)
+ }
+ s.Attr.Set(sym.AttrReachable, false)
+ }
+}
+
+// Load relocations for building the dependency graph in deadcode pass.
+// For now, we load symbol types, relocations, gotype, and the contents
+// of type symbols, which are needed in deadcode.
+func LoadReloc(l *Loader) {
+ for _, o := range l.objs[1:] {
+ loadObjReloc(l, o.r)
+ }
+}
+
+func loadObjReloc(l *Loader, r *oReader) {
+ lib := r.unit.Lib
+ pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
+ istart := l.StartIndex(r)
+
+ resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
+ i := l.Resolve(r, s)
+ return l.Syms[i]
+ }
+
+ for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
+ s := l.Syms[istart+Sym(i)]
+ if s == nil || s.Name == "" {
+ continue
+ }
+
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(i))
+ name := strings.Replace(osym.Name, "\"\".", pkgprefix, -1)
+ if s.Name != name { // Sanity check. We can remove it in the final version.
+ fmt.Println("name mismatch:", lib, i, s.Name, name)
+ panic("name mismatch")
+ }
+
+ if s.Type != 0 && s.Type != sym.SXREF {
+ fmt.Println("symbol already processed:", lib, i, s)
+ panic("symbol already processed")
+ }
+
+ t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
+ if t == sym.SXREF {
+ log.Fatalf("bad sxref")
+ }
+ if t == 0 {
+ log.Fatalf("missing type for %s in %s", s.Name, lib)
+ }
+ if !s.Attr.Reachable() && (t < sym.SDWARFSECT || t > sym.SDWARFLINES) && !(t == sym.SRODATA && strings.HasPrefix(name, "type.")) {
+ // No need to load unreachable symbols.
+ // XXX DWARF symbols may be used but are not marked reachable.
+ // XXX type symbol's content may be needed in DWARF code, but they are not marked.
+ continue
+ }
+ if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
+ t = s.Type
+ }
+ s.Type = t
+ s.Unit = r.unit
+
+ // Relocs
+ relocs := l.relocs(r, i)
+ s.R = make([]sym.Reloc, relocs.Count)
+ for j := range s.R {
+ r := relocs.At(j)
+ rs := r.Sym
+ sz := r.Size
+ rt := r.Type
+ if rt == objabi.R_METHODOFF {
+ if l.Reachable.Has(rs) {
+ rt = objabi.R_ADDROFF
+ } else {
+ sz = 0
+ rs = 0
+ }
+ }
+ if rt == objabi.R_WEAKADDROFF && !l.Reachable.Has(rs) {
+ rs = 0
+ sz = 0
+ }
+ if rs != 0 && l.SymType(rs) == sym.SABIALIAS {
+ rsrelocs := l.Relocs(rs)
+ rs = rsrelocs.At(0).Sym
+ }
+ s.R[j] = sym.Reloc{
+ Off: r.Off,
+ Siz: sz,
+ Type: rt,
+ Add: r.Add,
+ Sym: l.Syms[rs],
+ }
+ }
+
+ // Aux symbol
+ naux := r.NAux(i)
+ for j := 0; j < naux; j++ {
+ a := goobj2.Aux{}
+ a.Read(r.Reader, r.AuxOff(i, j))
+ switch a.Type {
+ case goobj2.AuxGotype:
+ typ := resolveSymRef(a.Sym)
+ if typ != nil {
+ s.Gotype = typ
+ }
+ case goobj2.AuxFuncdata:
+ pc := s.FuncInfo
+ if pc == nil {
+ pc = &sym.FuncInfo{Funcdata: make([]*sym.Symbol, 0, 4)}
+ s.FuncInfo = pc
+ }
+ pc.Funcdata = append(pc.Funcdata, resolveSymRef(a.Sym))
+ }
+ }
+
+ if s.Type == sym.STEXT {
+ dupok := osym.Flag&goobj2.SymFlagDupok != 0
+ if !dupok {
+ if s.Attr.OnList() {
+ log.Fatalf("symbol %s listed multiple times", s.Name)
+ }
+ s.Attr |= sym.AttrOnList
+ lib.Textp = append(lib.Textp, s)
+ } else {
+ // there may ba a dup in another package
+ // put into a temp list and add to text later
+ lib.DupTextSyms = append(lib.DupTextSyms, s)
+ }
+ }
+ }
+}
+
+// Load full contents.
+// TODO: For now, some contents are already load in LoadReloc. Maybe
+// we should combine LoadReloc back into this, once we rewrite deadcode
+// pass to use index directly.
+func LoadFull(l *Loader) {
+ for _, o := range l.objs[1:] {
+ loadObjFull(l, o.r)
+ }
+}
+
+func loadObjFull(l *Loader, r *oReader) {
+ lib := r.unit.Lib
+ pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
+ istart := l.StartIndex(r)
+
+ resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
+ i := l.Resolve(r, s)
+ return l.Syms[i]
+ }
+
+ pcdataBase := r.PcdataBase()
+ for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
+ s := l.Syms[istart+Sym(i)]
+ if s == nil || s.Name == "" {
+ continue
+ }
+ if !s.Attr.Reachable() && (s.Type < sym.SDWARFSECT || s.Type > sym.SDWARFLINES) && !(s.Type == sym.SRODATA && strings.HasPrefix(s.Name, "type.")) {
+ // No need to load unreachable symbols.
+ // XXX DWARF symbols may be used but are not marked reachable.
+ // XXX type symbol's content may be needed in DWARF code, but they are not marked.
+ continue
+ }
+
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(i))
+ name := strings.Replace(osym.Name, "\"\".", pkgprefix, -1)
+ if s.Name != name { // Sanity check. We can remove it in the final version.
+ fmt.Println("name mismatch:", lib, i, s.Name, name)
+ panic("name mismatch")
+ }
+
+ dupok := osym.Flag&goobj2.SymFlagDupok != 0
+ local := osym.Flag&goobj2.SymFlagLocal != 0
+ makeTypelink := osym.Flag&goobj2.SymFlagTypelink != 0
+ size := osym.Siz
+
+ // Symbol data
+ s.P = r.Data(i)
+ s.Attr.Set(sym.AttrReadOnly, r.ReadOnly())
+
+ // Aux symbol info
+ isym := -1
+ naux := r.NAux(i)
+ for j := 0; j < naux; j++ {
+ a := goobj2.Aux{}
+ a.Read(r.Reader, r.AuxOff(i, j))
+ switch a.Type {
+ case goobj2.AuxGotype, goobj2.AuxFuncdata:
+ // already loaded
+ case goobj2.AuxFuncInfo:
+ if a.Sym.PkgIdx != goobj2.PkgIdxSelf {
+ panic("funcinfo symbol not defined in current package")
+ }
+ isym = int(a.Sym.SymIdx)
+ default:
+ panic("unknown aux type")
+ }
+ }
+
+ s.File = pkgprefix[:len(pkgprefix)-1]
+ if dupok {
+ s.Attr |= sym.AttrDuplicateOK
+ }
+ if s.Size < int64(size) {
+ s.Size = int64(size)
+ }
+ s.Attr.Set(sym.AttrLocal, local)
+ s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
+
+ if s.Type == sym.SDWARFINFO {
+ // For DWARF symbols, replace `"".` to actual package prefix
+ // in the symbol content.
+ // TODO: maybe we should do this in the compiler and get rid
+ // of this.
+ patchDWARFName(s, r)
+ }
+
+ if s.Type != sym.STEXT {
+ continue
+ }
+
+ // FuncInfo
+ if isym == -1 {
+ continue
+ }
+ b := r.Data(isym)
+ info := goobj2.FuncInfo{}
+ info.Read(b)
+
+ if info.NoSplit != 0 {
+ s.Attr |= sym.AttrNoSplit
+ }
+ if info.Flags&goobj2.FuncFlagReflectMethod != 0 {
+ s.Attr |= sym.AttrReflectMethod
+ }
+ if info.Flags&goobj2.FuncFlagShared != 0 {
+ s.Attr |= sym.AttrShared
+ }
+ if info.Flags&goobj2.FuncFlagTopFrame != 0 {
+ s.Attr |= sym.AttrTopFrame
+ }
+
+ info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends
+ pc := s.FuncInfo
+ if pc == nil {
+ pc = &sym.FuncInfo{}
+ s.FuncInfo = pc
+ }
+ pc.Args = int32(info.Args)
+ pc.Locals = int32(info.Locals)
+ pc.Pcdata = make([]sym.Pcdata, len(info.Pcdata)-1) // -1 as we appended one above
+ pc.Funcdataoff = make([]int64, len(info.Funcdataoff))
+ pc.File = make([]*sym.Symbol, len(info.File))
+ pc.Pcsp.P = r.BytesAt(pcdataBase+info.Pcsp, int(info.Pcfile-info.Pcsp))
+ pc.Pcfile.P = r.BytesAt(pcdataBase+info.Pcfile, int(info.Pcline-info.Pcfile))
+ pc.Pcline.P = r.BytesAt(pcdataBase+info.Pcline, int(info.Pcinline-info.Pcline))
+ pc.Pcinline.P = r.BytesAt(pcdataBase+info.Pcinline, int(info.Pcdata[0]-info.Pcinline))
+ for k := range pc.Pcdata {
+ pc.Pcdata[k].P = r.BytesAt(pcdataBase+info.Pcdata[k], int(info.Pcdata[k+1]-info.Pcdata[k]))
+ }
+ for k := range pc.Funcdataoff {
+ pc.Funcdataoff[k] = int64(info.Funcdataoff[k])
+ }
+ for k := range pc.File {
+ pc.File[k] = resolveSymRef(info.File[k])
+ }
+ }
+}
+
+func patchDWARFName(s *sym.Symbol, r *oReader) {
+ // This is kind of ugly. Really the package name should not
+ // even be included here.
+ if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
+ return
+ }
+ e := bytes.IndexByte(s.P, 0)
+ if e == -1 {
+ return
+ }
+ p := bytes.Index(s.P[:e], emptyPkg)
+ if p == -1 {
+ return
+ }
+ pkgprefix := []byte(r.pkgprefix)
+ patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
+
+ s.P = append(patched, s.P[e:]...)
+ s.Attr.Set(sym.AttrReadOnly, false)
+ delta := int64(len(s.P)) - s.Size
+ s.Size = int64(len(s.P))
+ for i := range s.R {
+ r := &s.R[i]
+ if r.Off > int32(e) {
+ r.Off += int32(delta)
+ }
+ }
+}
diff --git a/src/cmd/link/internal/sym/symbols.go b/src/cmd/link/internal/sym/symbols.go
index f0fcf23..e772496 100644
--- a/src/cmd/link/internal/sym/symbols.go
+++ b/src/cmd/link/internal/sym/symbols.go
@@ -86,6 +86,17 @@
return syms.hash[v][name]
}
+// Add an existing symbol to the symbol table.
+func (syms *Symbols) Add(s *Symbol) {
+ name := s.Name
+ v := int(s.Version)
+ m := syms.hash[v]
+ if _, ok := m[name]; ok {
+ panic(name + " already added")
+ }
+ m[name] = s
+}
+
// Allocate a new version (i.e. symbol namespace).
func (syms *Symbols) IncVersion() int {
syms.hash = append(syms.hash, make(map[string]*Symbol))