[dev.link] all: merge branch 'master' into dev.link
Clean merge.
Change-Id: I2ae070c60c011779a0f0a1344f5b6d45ef10d8a1
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index fad87b2..6aefc96 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -23,7 +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")
+ Importpath = flag.String("p", "", "set expected package import to path")
)
var (
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index 6b0a609..d42093a 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -40,7 +40,6 @@
}
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()
@@ -74,7 +73,7 @@
pList.Firstpc, ok = parser.Parse()
// reports errors to parser.Errorf
if ok {
- obj.Flushplist(ctxt, pList, nil, "")
+ obj.Flushplist(ctxt, pList, nil, *flags.Importpath)
}
}
if !ok {
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index 7ee0876..a3baa24 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -991,18 +991,16 @@
}
func (w *exportWriter) symIdx(s *types.Sym) {
- if Ctxt.Flag_newobj {
- lsym := s.Linksym()
- if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
- // Don't export index for non-package symbols, linkname'd symbols,
- // and symbols without an index. They can only be referenced by
- // name.
- w.int64(-1)
- } else {
- // For a defined symbol, export its index.
- // For re-exporting an imported symbol, pass its index through.
- w.int64(int64(lsym.SymIdx))
- }
+ lsym := s.Linksym()
+ if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
+ // Don't export index for non-package symbols, linkname'd symbols,
+ // and symbols without an index. They can only be referenced by
+ // name.
+ w.int64(-1)
+ } else {
+ // For a defined symbol, export its index.
+ // For re-exporting an imported symbol, pass its index through.
+ w.int64(int64(lsym.SymIdx))
}
}
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index f99b70a..dfcaa56 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -687,16 +687,14 @@
}
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)
+ 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)
}
}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 18a210b..745973e 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -277,7 +277,6 @@
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")
flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging")
objabi.Flagparse(usage)
@@ -285,7 +284,7 @@
// 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", "newobj")
+ recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes")
if smallFrames {
maxStackVarSize = 128 * 1024
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index a07e64b..5ec2381 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -73,6 +73,7 @@
"cmd/link/internal/amd64",
"cmd/link/internal/arm",
"cmd/link/internal/arm64",
+ "cmd/link/internal/benchmark",
"cmd/link/internal/ld",
"cmd/link/internal/loadelf",
"cmd/link/internal/loader",
@@ -81,7 +82,6 @@
"cmd/link/internal/loadxcoff",
"cmd/link/internal/mips",
"cmd/link/internal/mips64",
- "cmd/link/internal/objfile",
"cmd/link/internal/ppc64",
"cmd/link/internal/riscv64",
"cmd/link/internal/s390x",
diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go
index 7d17c0c..78db845 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -37,6 +37,17 @@
return base.Tool("link")
}
+func pkgPath(a *Action) string {
+ p := a.Package
+ ppath := p.ImportPath
+ if cfg.BuildBuildmode == "plugin" {
+ ppath = pluginPath(a)
+ } else if p.Name == "main" && !p.Internal.ForceLibrary {
+ ppath = "main"
+ }
+ return ppath
+}
+
func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) {
p := a.Package
objdir := a.Objdir
@@ -47,12 +58,7 @@
ofile = objdir + out
}
- pkgpath := p.ImportPath
- if cfg.BuildBuildmode == "plugin" {
- pkgpath = pluginPath(a)
- } else if p.Name == "main" && !p.Internal.ForceLibrary {
- pkgpath = "main"
- }
+ pkgpath := pkgPath(a)
gcargs := []string{"-p", pkgpath}
if p.Module != nil && p.Module.GoVersion != "" && allowedVersion(p.Module.GoVersion) {
gcargs = append(gcargs, "-lang=go"+p.Module.GoVersion)
@@ -240,7 +246,8 @@
func asmArgs(a *Action, p *load.Package) []interface{} {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(cfg.GOROOT, "pkg", "include")
- args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", a.trimpath(), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags}
+ pkgpath := pkgPath(a)
+ args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-p", pkgpath, "-trimpath", a.trimpath(), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags}
if p.ImportPath == "runtime" && cfg.Goarch == "386" {
for _, arg := range forcedAsmflags {
if arg == "-dynlink" {
diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go
index 56b44a1..62036ae 100644
--- a/src/cmd/internal/dwarf/dwarf.go
+++ b/src/cmd/internal/dwarf/dwarf.go
@@ -21,15 +21,6 @@
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
const InfoPrefix = "go.info."
-// RangePrefix is the prefix for all the symbols containing DWARF location lists.
-const LocPrefix = "go.loc."
-
-// RangePrefix is the prefix for all the symbols containing DWARF range lists.
-const RangePrefix = "go.range."
-
-// DebugLinesPrefix is the prefix for all the symbols containing DWARF debug_line information from the compiler.
-const DebugLinesPrefix = "go.debuglines."
-
// ConstInfoPrefix is the prefix for all symbols containing DWARF info
// entries that contain constants.
const ConstInfoPrefix = "go.constinfo."
@@ -48,7 +39,7 @@
// Sym represents a symbol.
type Sym interface {
- Len() int64
+ Length(dwarfContext interface{}) int64
}
// A Var represents a local variable or a function parameter.
@@ -1279,7 +1270,7 @@
putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, callee)
if abbrev == DW_ABRV_INLINED_SUBROUTINE_RANGES {
- putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Len(), s.Ranges)
+ putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Length(ctxt), s.Ranges)
s.PutRanges(ctxt, ic.Ranges)
} else {
st := ic.Ranges[0].Start
@@ -1440,7 +1431,7 @@
putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, s.StartPC)
} else {
Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES)
- putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Len(), s.Ranges)
+ putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Length(ctxt), s.Ranges)
s.PutRanges(ctxt, scope.Ranges)
}
@@ -1585,7 +1576,7 @@
}
if abbrevUsesLoclist(abbrev) {
- putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Loc.Len(), s.Loc)
+ putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Loc.Length(ctxt), s.Loc)
v.PutLocationList(s.Loc, s.StartPC)
} else {
loc := encbuf[:0]
diff --git a/src/cmd/internal/goobj/readnew.go b/src/cmd/internal/goobj/readnew.go
index 3f9d0d1..e09260f 100644
--- a/src/cmd/internal/goobj/readnew.go
+++ b/src/cmd/internal/goobj/readnew.go
@@ -149,7 +149,7 @@
f := &Func{
Args: int64(info.Args),
Frame: int64(info.Locals),
- NoSplit: info.NoSplit != 0,
+ NoSplit: osym.NoSplit(),
Leaf: osym.Leaf(),
TopFrame: osym.TopFrame(),
PCSP: Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)},
diff --git a/src/cmd/internal/goobj2/funcinfo.go b/src/cmd/internal/goobj2/funcinfo.go
index 8620931..053d7ad 100644
--- a/src/cmd/internal/goobj2/funcinfo.go
+++ b/src/cmd/internal/goobj2/funcinfo.go
@@ -14,8 +14,6 @@
//
// TODO: make each pcdata a separate symbol?
type FuncInfo struct {
- NoSplit uint8
-
Args uint32
Locals uint32
@@ -32,8 +30,6 @@
}
func (a *FuncInfo) Write(w *bytes.Buffer) {
- w.WriteByte(a.NoSplit)
-
var b [4]byte
writeUint32 := func(x uint32) {
binary.LittleEndian.PutUint32(b[:], x)
@@ -68,9 +64,6 @@
}
func (a *FuncInfo) Read(b []byte) {
- a.NoSplit = b[0]
- b = b[1:]
-
readUint32 := func() uint32 {
x := binary.LittleEndian.Uint32(b)
b = b[4:]
@@ -107,6 +100,16 @@
}
}
+// Accessors reading only some fields.
+// TODO: more accessors.
+
+func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
+
+// return start and end offsets.
+func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
+ return binary.LittleEndian.Uint32(b[8:]), binary.LittleEndian.Uint32(b[12:])
+}
+
// InlTreeNode is the serialized form of FileInfo.InlTree.
type InlTreeNode struct {
Parent int32
diff --git a/src/cmd/internal/goobj2/objfile.go b/src/cmd/internal/goobj2/objfile.go
index 4c364b0..d5a9b4a 100644
--- a/src/cmd/internal/goobj2/objfile.go
+++ b/src/cmd/internal/goobj2/objfile.go
@@ -203,7 +203,7 @@
SymFlagLocal
SymFlagTypelink
SymFlagLeaf
- SymFlagCFunc
+ SymFlagNoSplit
SymFlagReflectMethod
SymFlagGoType
SymFlagTopFrame
@@ -225,6 +225,20 @@
s.Siz = r.uint32At(off + 8)
}
+// Read fields other than the symbol name. The name is not necessary
+// in some cases, and most of the time spent in Read is reading the
+// name.
+func (s *Sym) ReadWithoutName(r *Reader, off uint32) {
+ 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) ReadFlag(r *Reader, off uint32) {
+ s.Flag = r.uint8At(off + 7)
+}
+
func (s *Sym) Size() int {
return 4 + 2 + 1 + 1 + 4
}
@@ -233,7 +247,7 @@
func (s *Sym) Local() bool { return s.Flag&SymFlagLocal != 0 }
func (s *Sym) Typelink() bool { return s.Flag&SymFlagTypelink != 0 }
func (s *Sym) Leaf() bool { return s.Flag&SymFlagLeaf != 0 }
-func (s *Sym) CFunc() bool { return s.Flag&SymFlagCFunc != 0 }
+func (s *Sym) NoSplit() bool { return s.Flag&SymFlagNoSplit != 0 }
func (s *Sym) ReflectMethod() bool { return s.Flag&SymFlagReflectMethod != 0 }
func (s *Sym) IsGoType() bool { return s.Flag&SymFlagGoType != 0 }
func (s *Sym) TopFrame() bool { return s.Flag&SymFlagTopFrame != 0 }
@@ -283,10 +297,39 @@
o.Sym.Read(r, off+14)
}
+// Only reads the target symbol and reloc type, leaving other fields unset.
+func (o *Reloc) ReadSymType(r *Reader, off uint32) {
+ o.Type = r.uint8At(off + 5)
+ o.Sym.Read(r, off+14)
+}
+
func (r *Reloc) Size() int {
return 4 + 1 + 1 + 8 + r.Sym.Size()
}
+// XXX experiment with another way of accessing relocations.
+
+const RelocSize = 22 // TODO: is it possible to not hard-code this?
+
+type Reloc2 [RelocSize]byte
+
+func (r *Reloc2) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) }
+func (r *Reloc2) Siz() uint8 { return r[4] }
+func (r *Reloc2) Type() uint8 { return r[5] }
+func (r *Reloc2) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) }
+func (r *Reloc2) Sym() SymRef {
+ return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])}
+}
+
+func (r *Reloc2) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) {
+ binary.LittleEndian.PutUint32(r[:], uint32(off))
+ r[4] = size
+ r[5] = typ
+ binary.LittleEndian.PutUint64(r[6:], uint64(add))
+ binary.LittleEndian.PutUint32(r[14:], sym.PkgIdx)
+ binary.LittleEndian.PutUint32(r[18:], sym.SymIdx)
+}
+
// Aux symbol info.
type Aux struct {
Type uint8
@@ -316,6 +359,11 @@
a.Sym.Read(r, off+1)
}
+// Only reads the target symbol, leaving other fields unset.
+func (a *Aux) ReadSym(r *Reader, off uint32) {
+ a.Sym.Read(r, off+1)
+}
+
func (a *Aux) Size() int {
return 1 + a.Sym.Size()
}
@@ -541,6 +589,12 @@
return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(relocsiz)
}
+// Reloc2 returns a pointer to the j-th relocation of the i-th symbol.
+func (r *Reader) Reloc2(i int, j int) *Reloc2 {
+ off := r.RelocOff(i, j)
+ return (*Reloc2)(unsafe.Pointer(&r.b[off]))
+}
+
// 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)
diff --git a/src/cmd/internal/goobj2/objfile_test.go b/src/cmd/internal/goobj2/objfile_test.go
new file mode 100644
index 0000000..eea97d4
--- /dev/null
+++ b/src/cmd/internal/goobj2/objfile_test.go
@@ -0,0 +1,29 @@
+// Copyright 2020 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 (
+ "bufio"
+ "bytes"
+ "cmd/internal/bio"
+ "testing"
+)
+
+func dummyWriter() *Writer {
+ var buf bytes.Buffer
+ wr := &bio.Writer{Writer: bufio.NewWriter(&buf)} // hacky: no file, so cannot seek
+ return NewWriter(wr)
+}
+
+func TestSize(t *testing.T) {
+ // This test checks that hard-coded sizes match the actual sizes
+ // in the object file format.
+ w := dummyWriter()
+ (&Reloc{}).Write(w)
+ off := w.off
+ if sz := uint32(RelocSize); off != sz {
+ t.Errorf("size mismatch: %d bytes written, but size=%d", off, sz)
+ }
+}
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 76c6f26..9701580 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -381,7 +381,6 @@
Type objabi.SymKind
Attribute
- RefIdx int // Index of this symbol in the symbol reference list.
Size int64
Gotype *LSym
P []byte
@@ -391,7 +390,7 @@
Pkg string
PkgIdx int32
- SymIdx int32 // TODO: replace RefIdx
+ SymIdx int32
}
// A FuncInfo contains extra fields for STEXT symbols.
@@ -652,7 +651,6 @@
Flag_linkshared 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
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 7fd97f7..717d471 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -7,229 +7,25 @@
package obj
import (
- "bufio"
"cmd/internal/bio"
"cmd/internal/dwarf"
"cmd/internal/objabi"
"cmd/internal/sys"
"fmt"
- "log"
- "path/filepath"
"sort"
- "strings"
"sync"
)
-// objWriter writes Go object files.
-type objWriter struct {
- wr *bufio.Writer
- ctxt *Link
- // Temporary buffer for zigzag int writing.
- varintbuf [10]uint8
-
- // Number of objects written of each type.
- nRefs int
- nData int
- nReloc int
- nPcdata int
- nFuncdata int
- nFile int
-
- pkgpath string // the package import path (escaped), "" if unknown
-}
-
-func (w *objWriter) addLengths(s *LSym) {
- w.nData += len(s.P)
- w.nReloc += len(s.R)
-
- if s.Type != objabi.STEXT {
- return
- }
-
- pc := &s.Func.Pcln
-
- data := 0
- data += len(pc.Pcsp.P)
- data += len(pc.Pcfile.P)
- data += len(pc.Pcline.P)
- data += len(pc.Pcinline.P)
- for _, pcd := range pc.Pcdata {
- data += len(pcd.P)
- }
-
- w.nData += data
- w.nPcdata += len(pc.Pcdata)
-
- w.nFuncdata += len(pc.Funcdataoff)
- w.nFile += len(pc.File)
-}
-
-func (w *objWriter) writeLengths() {
- w.writeInt(int64(w.nData))
- w.writeInt(int64(w.nReloc))
- w.writeInt(int64(w.nPcdata))
- w.writeInt(int64(0)) // TODO: remove at next object file rev
- w.writeInt(int64(w.nFuncdata))
- w.writeInt(int64(w.nFile))
-}
-
-func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter {
- return &objWriter{
- ctxt: ctxt,
- wr: b,
- pkgpath: objabi.PathToPrefix(pkgpath),
- }
-}
-
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
- w.wr.WriteString("\x00go114ld")
-
- // Version
- w.wr.WriteByte(1)
-
- // Autolib
- for _, pkg := range ctxt.Imports {
- w.writeString(pkg)
- }
- w.writeString("")
-
- // DWARF File Table
- fileTable := ctxt.PosTable.DebugLinesFileTable()
- w.writeInt(int64(len(fileTable)))
- for _, str := range fileTable {
- w.writeString(filepath.ToSlash(str))
- }
-
- // Symbol references
- for _, s := range ctxt.Text {
- w.writeRefs(s)
- w.addLengths(s)
- }
-
- if ctxt.Headtype == objabi.Haix {
- // Data must be sorted to keep a constant order in TOC symbols.
- // As they are created during Progedit, two symbols can be switched between
- // two different compilations. Therefore, BuildID will be different.
- // TODO: find a better place and optimize to only sort TOC symbols
- sort.Slice(ctxt.Data, func(i, j int) bool {
- return ctxt.Data[i].Name < ctxt.Data[j].Name
- })
- }
-
- for _, s := range ctxt.Data {
- w.writeRefs(s)
- w.addLengths(s)
- }
- for _, s := range ctxt.ABIAliases {
- w.writeRefs(s)
- w.addLengths(s)
- }
- // End symbol references
- w.wr.WriteByte(0xff)
-
- // Lengths
- w.writeLengths()
-
- // Data block
- for _, s := range ctxt.Text {
- w.wr.Write(s.P)
- pc := &s.Func.Pcln
- w.wr.Write(pc.Pcsp.P)
- w.wr.Write(pc.Pcfile.P)
- w.wr.Write(pc.Pcline.P)
- w.wr.Write(pc.Pcinline.P)
- for _, pcd := range pc.Pcdata {
- w.wr.Write(pcd.P)
- }
- }
- for _, s := range ctxt.Data {
- if len(s.P) > 0 {
- switch s.Type {
- case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
- ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name)
- }
- }
- w.wr.Write(s.P)
- }
-
- // Symbols
- for _, s := range ctxt.Text {
- w.writeSym(s)
- }
- for _, s := range ctxt.Data {
- w.writeSym(s)
- }
- for _, s := range ctxt.ABIAliases {
- w.writeSym(s)
- }
-
- // Magic footer
- w.wr.WriteString("\xffgo114ld")
-}
-
-// Symbols are prefixed so their content doesn't get confused with the magic footer.
-const symPrefix = 0xfe
-
-func (w *objWriter) writeRef(s *LSym, isPath bool) {
- if s == nil || s.RefIdx != 0 {
- return
- }
- w.wr.WriteByte(symPrefix)
- if isPath {
- w.writeString(filepath.ToSlash(s.Name))
- } else if w.pkgpath != "" {
- // w.pkgpath is already escaped.
- n := strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
- w.writeString(n)
- } else {
- w.writeString(s.Name)
- }
- // Write ABI/static information.
- abi := int64(s.ABI())
- if s.Static() {
- abi = -1
- }
- w.writeInt(abi)
- w.nRefs++
- s.RefIdx = w.nRefs
-}
-
-func (w *objWriter) writeRefs(s *LSym) {
- w.writeRef(s, false)
- w.writeRef(s.Gotype, false)
- for _, r := range s.R {
- w.writeRef(r.Sym, false)
- }
-
- if s.Type == objabi.STEXT {
- pc := &s.Func.Pcln
- for _, d := range pc.Funcdata {
- w.writeRef(d, false)
- }
- for _, f := range pc.File {
- fsym := w.ctxt.Lookup(f)
- w.writeRef(fsym, true)
- }
- for _, call := range pc.InlTree.nodes {
- w.writeRef(call.Func, false)
- f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
- fsym := w.ctxt.Lookup(f)
- w.writeRef(fsym, true)
- }
- }
+ WriteObjFile2(ctxt, bout, pkgpath)
}
func (ctxt *Link) writeSymDebug(s *LSym) {
- fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
+ ctxt.writeSymDebugNamed(s, s.Name)
+}
+
+func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
+ fmt.Fprintf(ctxt.Bso, "%s ", name)
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
}
@@ -305,137 +101,6 @@
}
}
-func (w *objWriter) writeSym(s *LSym) {
- ctxt := w.ctxt
- if ctxt.Debugasm > 0 {
- w.ctxt.writeSymDebug(s)
- }
-
- w.wr.WriteByte(symPrefix)
- w.wr.WriteByte(byte(s.Type))
- w.writeRefIndex(s)
- flags := int64(0)
- if s.DuplicateOK() {
- flags |= 1
- }
- if s.Local() {
- flags |= 1 << 1
- }
- if s.MakeTypelink() {
- flags |= 1 << 2
- }
- w.writeInt(flags)
- w.writeInt(s.Size)
- w.writeRefIndex(s.Gotype)
- w.writeInt(int64(len(s.P)))
-
- w.writeInt(int64(len(s.R)))
- var r *Reloc
- for i := range s.R {
- r = &s.R[i]
- w.writeInt(int64(r.Off))
- w.writeInt(int64(r.Siz))
- w.writeInt(int64(r.Type))
- w.writeInt(r.Add)
- w.writeRefIndex(r.Sym)
- }
-
- if s.Type != objabi.STEXT {
- return
- }
-
- w.writeInt(int64(s.Func.Args))
- w.writeInt(int64(s.Func.Locals))
- w.writeBool(s.NoSplit())
- flags = int64(0)
- if s.Leaf() {
- flags |= 1
- }
- if s.CFunc() {
- flags |= 1 << 1
- }
- if s.ReflectMethod() {
- flags |= 1 << 2
- }
- if ctxt.Flag_shared {
- flags |= 1 << 3
- }
- if s.TopFrame() {
- flags |= 1 << 4
- }
- w.writeInt(flags)
- w.writeInt(int64(0)) // TODO: remove at next object file rev
-
- pc := &s.Func.Pcln
- w.writeInt(int64(len(pc.Pcsp.P)))
- w.writeInt(int64(len(pc.Pcfile.P)))
- w.writeInt(int64(len(pc.Pcline.P)))
- w.writeInt(int64(len(pc.Pcinline.P)))
- w.writeInt(int64(len(pc.Pcdata)))
- for _, pcd := range pc.Pcdata {
- w.writeInt(int64(len(pcd.P)))
- }
- w.writeInt(int64(len(pc.Funcdataoff)))
- for i := range pc.Funcdataoff {
- w.writeRefIndex(pc.Funcdata[i])
- }
- for i := range pc.Funcdataoff {
- w.writeInt(pc.Funcdataoff[i])
- }
- w.writeInt(int64(len(pc.File)))
- for _, f := range pc.File {
- fsym := ctxt.Lookup(f)
- w.writeRefIndex(fsym)
- }
- w.writeInt(int64(len(pc.InlTree.nodes)))
- for _, call := range pc.InlTree.nodes {
- w.writeInt(int64(call.Parent))
- f, l := linkgetlineFromPos(w.ctxt, call.Pos)
- fsym := ctxt.Lookup(f)
- w.writeRefIndex(fsym)
- w.writeInt(int64(l))
- w.writeRefIndex(call.Func)
- w.writeInt(int64(call.ParentPC))
- }
-}
-
-func (w *objWriter) writeBool(b bool) {
- if b {
- w.writeInt(1)
- } else {
- w.writeInt(0)
- }
-}
-
-func (w *objWriter) writeInt(sval int64) {
- var v uint64
- uv := (uint64(sval) << 1) ^ uint64(sval>>63)
- p := w.varintbuf[:]
- for v = uv; v >= 0x80; v >>= 7 {
- p[0] = uint8(v | 0x80)
- p = p[1:]
- }
- p[0] = uint8(v)
- p = p[1:]
- w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
-}
-
-func (w *objWriter) writeString(s string) {
- w.writeInt(int64(len(s)))
- w.wr.WriteString(s)
-}
-
-func (w *objWriter) writeRefIndex(s *LSym) {
- if s == nil {
- w.writeInt(0)
- return
- }
- if s.RefIdx == 0 {
- log.Fatalln("writing an unreferenced symbol", s.Name)
- }
- w.writeInt(int64(s.RefIdx))
-}
-
// relocByOff sorts relocations by their offsets.
type relocByOff []Reloc
@@ -544,18 +209,24 @@
if s.Func.dwarfInfoSym == nil {
s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
if ctxt.Flag_locationlists {
- s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
+ s.Func.dwarfLocSym = &LSym{
+ Type: objabi.SDWARFLOC,
+ }
}
- s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
+ s.Func.dwarfRangesSym = &LSym{
+ Type: objabi.SDWARFRANGE,
+ }
if s.WasInlined() {
s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
}
- s.Func.dwarfDebugLinesSym = ctxt.LookupDerived(s, dwarf.DebugLinesPrefix+s.Name)
+ s.Func.dwarfDebugLinesSym = &LSym{
+ Type: objabi.SDWARFLINES,
+ }
}
return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
}
-func (s *LSym) Len() int64 {
+func (s *LSym) Length(dwarfContext interface{}) int64 {
return s.Size
}
diff --git a/src/cmd/internal/obj/objfile2.go b/src/cmd/internal/obj/objfile2.go
index 69019e0..359e82e 100644
--- a/src/cmd/internal/obj/objfile2.go
+++ b/src/cmd/internal/obj/objfile2.go
@@ -18,9 +18,8 @@
// 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)
- }
+
+ debugAsmEmit(ctxt)
genFuncInfoSyms(ctxt)
@@ -60,7 +59,7 @@
// DWARF file table
h.Offsets[goobj2.BlkDwarfFile] = w.Offset()
for _, f := range ctxt.PosTable.DebugLinesFileTable() {
- w.StringRef(f)
+ w.StringRef(filepath.ToSlash(f))
}
// Symbol definitions
@@ -207,7 +206,7 @@
}
})
for _, f := range w.ctxt.PosTable.DebugLinesFileTable() {
- w.AddString(f)
+ w.AddString(filepath.ToSlash(f))
}
}
@@ -229,8 +228,8 @@
if s.Leaf() {
flag |= goobj2.SymFlagLeaf
}
- if s.CFunc() {
- flag |= goobj2.SymFlagCFunc
+ if s.NoSplit() {
+ flag |= goobj2.SymFlagNoSplit
}
if s.ReflectMethod() {
flag |= goobj2.SymFlagReflectMethod
@@ -307,21 +306,21 @@
}
o.Write(w.Writer)
}
- if s.Func.dwarfLocSym != nil {
+ if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
o := goobj2.Aux{
Type: goobj2.AuxDwarfLoc,
Sym: makeSymRef(s.Func.dwarfLocSym),
}
o.Write(w.Writer)
}
- if s.Func.dwarfRangesSym != nil {
+ if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
o := goobj2.Aux{
Type: goobj2.AuxDwarfRanges,
Sym: makeSymRef(s.Func.dwarfRangesSym),
}
o.Write(w.Writer)
}
- if s.Func.dwarfDebugLinesSym != nil {
+ if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
o := goobj2.Aux{
Type: goobj2.AuxDwarfLines,
Sym: makeSymRef(s.Func.dwarfDebugLinesSym),
@@ -343,13 +342,13 @@
if s.Func.dwarfInfoSym != nil {
n++
}
- if s.Func.dwarfLocSym != nil {
+ if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
n++
}
- if s.Func.dwarfRangesSym != nil {
+ if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
n++
}
- if s.Func.dwarfDebugLinesSym != nil {
+ if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
n++
}
}
@@ -366,14 +365,9 @@
if s.Func == nil {
continue
}
- nosplit := uint8(0)
- if s.NoSplit() {
- nosplit = 1
- }
o := goobj2.FuncInfo{
- NoSplit: nosplit,
- Args: uint32(s.Func.Args),
- Locals: uint32(s.Func.Locals),
+ Args: uint32(s.Func.Args),
+ Locals: uint32(s.Func.Locals),
}
pc := &s.Func.Pcln
o.Pcsp = pcdataoff
@@ -424,6 +418,43 @@
infosyms = append(infosyms, isym)
s.Func.FuncInfoSym = isym
b.Reset()
+
+ dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym}
+ for _, s := range dwsyms {
+ if s == nil || s.Size == 0 {
+ continue
+ }
+ s.PkgIdx = goobj2.PkgIdxSelf
+ s.SymIdx = symidx
+ s.Set(AttrIndexed, true)
+ symidx++
+ infosyms = append(infosyms, s)
+ }
}
ctxt.defs = append(ctxt.defs, infosyms...)
}
+
+// debugDumpAux is a dumper for selected aux symbols.
+func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
+ // Most aux symbols (ex: funcdata) are not interesting--
+ // pick out just the DWARF ones for now.
+ if aux.Type != objabi.SDWARFLOC &&
+ aux.Type != objabi.SDWARFINFO &&
+ aux.Type != objabi.SDWARFLINES &&
+ aux.Type != objabi.SDWARFRANGE {
+ return
+ }
+ ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
+}
+
+func debugAsmEmit(ctxt *Link) {
+ if ctxt.Debugasm > 0 {
+ ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
+ if ctxt.Debugasm > 1 {
+ fn := func(par *LSym, aux *LSym) {
+ writeAuxSymDebug(ctxt, par, aux)
+ }
+ ctxt.traverseAuxSyms(fn)
+ }
+ }
+}
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
index 7579dd0..917343e 100644
--- a/src/cmd/internal/obj/plist.go
+++ b/src/cmd/internal/obj/plist.go
@@ -109,7 +109,9 @@
continue
}
linkpcln(ctxt, s)
- ctxt.populateDWARF(plist.Curfn, s, myimportpath)
+ if myimportpath != "" {
+ ctxt.populateDWARF(plist.Curfn, s, myimportpath)
+ }
}
}
@@ -137,20 +139,10 @@
ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entries for s.
- info, loc, ranges, _, lines := ctxt.dwarfSym(s)
+ info, _, _, _, _ := ctxt.dwarfSym(s)
info.Type = objabi.SDWARFINFO
info.Set(AttrDuplicateOK, s.DuplicateOK())
- if loc != nil {
- loc.Type = objabi.SDWARFLOC
- loc.Set(AttrDuplicateOK, s.DuplicateOK())
- ctxt.Data = append(ctxt.Data, loc)
- }
- ranges.Type = objabi.SDWARFRANGE
- ranges.Set(AttrDuplicateOK, s.DuplicateOK())
- ctxt.Data = append(ctxt.Data, info, ranges)
- lines.Type = objabi.SDWARFLINES
- lines.Set(AttrDuplicateOK, s.DuplicateOK())
- ctxt.Data = append(ctxt.Data, lines)
+ ctxt.Data = append(ctxt.Data, info)
}
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go
index b5e170c..69e6047 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{}, 76, 128},
+ {LSym{}, 72, 120},
{Prog{}, 132, 200},
}
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 3ef8866..9cd1786 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -164,10 +164,6 @@
// 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
- }
-
if ctxt.Headtype == objabi.Haix {
// Data must be sorted to keep a constant order in TOC symbols.
// As they are created during Progedit, two symbols can be switched between
@@ -298,28 +294,58 @@
fn(s.Gotype)
}
if s.Type == objabi.STEXT {
- pc := &s.Func.Pcln
- for _, d := range pc.Funcdata {
- if d != nil {
- fn(d)
- }
+ f := func(parent *LSym, aux *LSym) {
+ fn(aux)
}
- 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)
- }
- f, _ := linkgetlineFromPos(ctxt, call.Pos)
- if fsym := ctxt.Lookup(f); fsym != nil {
- fn(fsym)
- }
- }
+ ctxt.traverseFuncAux(s, f)
}
}
}
}
}
+
+func (ctxt *Link) traverseFuncAux(fsym *LSym, fn func(parent *LSym, aux *LSym)) {
+ pc := &fsym.Func.Pcln
+ for _, d := range pc.Funcdata {
+ if d != nil {
+ fn(fsym, d)
+ }
+ }
+ for _, f := range pc.File {
+ if filesym := ctxt.Lookup(f); filesym != nil {
+ fn(fsym, filesym)
+ }
+ }
+ for _, call := range pc.InlTree.nodes {
+ if call.Func != nil {
+ fn(fsym, call.Func)
+ }
+ f, _ := linkgetlineFromPos(ctxt, call.Pos)
+ if filesym := ctxt.Lookup(f); filesym != nil {
+ fn(fsym, filesym)
+ }
+ }
+ dwsyms := []*LSym{fsym.Func.dwarfRangesSym, fsym.Func.dwarfLocSym, fsym.Func.dwarfDebugLinesSym}
+ for _, dws := range dwsyms {
+ if dws == nil || dws.Size == 0 {
+ continue
+ }
+ fn(fsym, dws)
+ }
+}
+
+// Traverse aux symbols, calling fn for each sym/aux pair.
+func (ctxt *Link) traverseAuxSyms(fn func(parent *LSym, aux *LSym)) {
+ lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
+ for _, list := range lists {
+ for _, s := range list {
+ if s.Gotype != nil {
+ fn(s, s.Gotype)
+ }
+ if s.Type != objabi.STEXT {
+ continue
+ }
+ ctxt.traverseFuncAux(s, fn)
+ }
+ }
+}
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index 26208cc..06c4a36 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -34,6 +34,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"log"
@@ -98,7 +99,15 @@
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+// makeWritable makes a readonly symbol writable if we do opcode rewriting.
+func makeWritable(s *sym.Symbol) {
+ if s.Attr.ReadOnly() {
+ s.Attr.Set(sym.AttrReadOnly, false)
+ s.P = append([]byte(nil), s.P...)
+ }
+}
+
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
targ := r.Sym
switch r.Type {
@@ -150,6 +159,7 @@
if targ.Type != sym.SDYNIMPORT {
// have symbol
if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
+ makeWritable(s)
// turn MOVQ of GOT entry into LEAQ of symbol itself
s.P[r.Off-2] = 0x8d
@@ -225,6 +235,7 @@
return false
}
+ makeWritable(s)
s.P[r.Off-2] = 0x8d
r.Type = objabi.R_PCREL
return true
@@ -371,7 +382,7 @@
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- ld.Adddynsym(ctxt, targ)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, targ)
got := ctxt.Syms.Lookup(".got", 0)
s.Type = got.Type
@@ -553,36 +564,34 @@
return true
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return t
}
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- got := ctxt.Syms.Lookup(".got.plt", 0)
- if plt.Size == 0 {
+func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() == 0 {
// pushq got+8(IP)
plt.AddUint8(0xff)
plt.AddUint8(0x35)
- plt.AddPCRelPlus(ctxt.Arch, got, 8)
+ plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 8)
// jmpq got+16(IP)
plt.AddUint8(0xff)
plt.AddUint8(0x25)
- plt.AddPCRelPlus(ctxt.Arch, got, 16)
+ plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 16)
// nopl 0(AX)
plt.AddUint32(ctxt.Arch, 0x00401f0f)
// assume got->size == 0 too
- got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
+ got.AddAddrPlus(ctxt.Arch, dynamic, 0)
got.AddUint64(ctxt.Arch, 0)
got.AddUint64(ctxt.Arch, 0)
@@ -594,14 +603,14 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ctxt.Syms.Lookup(".plt", 0)
got := ctxt.Syms.Lookup(".got.plt", 0)
rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
- elfsetupplt(ctxt)
+ panic("plt is not set up")
}
// jmpq *got+size(IP)
@@ -662,7 +671,7 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
got := ctxt.Syms.Lookup(".got", 0)
s.SetGot(int32(got.Size))
got.AddUint64(ctxt.Arch, 0)
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index f2fb654..e4a52e5 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -34,6 +34,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"fmt"
@@ -115,7 +116,7 @@
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
targ := r.Sym
switch r.Type {
@@ -243,7 +244,7 @@
break
}
if ctxt.IsELF {
- ld.Adddynsym(ctxt, targ)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, targ)
rel := ctxt.Syms.Lookup(".rel", 0)
rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
@@ -300,10 +301,8 @@
return true
}
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- got := ctxt.Syms.Lookup(".got.plt", 0)
- if plt.Size == 0 {
+func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() == 0 {
// str lr, [sp, #-4]!
plt.AddUint32(ctxt.Arch, 0xe52de004)
@@ -317,7 +316,7 @@
plt.AddUint32(ctxt.Arch, 0xe5bef008)
// .word &GLOBAL_OFFSET_TABLE[0] - .
- plt.AddPCRelPlus(ctxt.Arch, got, 4)
+ plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 4)
// the first .plt entry requires 3 .plt.got entries
got.AddUint32(ctxt.Arch, 0)
@@ -597,8 +596,8 @@
}
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
switch r.Type {
case objabi.R_CALLARM:
r.Done = false
@@ -623,7 +622,7 @@
// the section load address.
// we need to compensate that by removing the instruction's address
// from addend.
- if ctxt.HeadType == objabi.Hdarwin {
+ if target.IsDarwin() {
r.Xadd -= ld.Symaddr(s) + int64(r.Off)
}
@@ -641,19 +640,19 @@
case objabi.R_CONST:
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
// The following three arch specific relocations are only for generation of
// Linux/ARM ELF's PLT entry (3 assembler instruction)
case objabi.R_PLT0: // add ip, pc, #0xXX00000
- if ld.Symaddr(ctxt.Syms.Lookup(".got.plt", 0)) < ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) {
+ if ld.Symaddr(syms.GOTPLT) < ld.Symaddr(syms.PLT) {
ld.Errorf(s, ".got.plt should be placed after .plt section.")
}
- return 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add)) >> 20)), true
+ return 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(syms.PLT)+int64(r.Off))+r.Add)) >> 20)), true
case objabi.R_PLT1: // add ip, ip, #0xYY000
- return 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+4)) >> 12)), true
+ return 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(syms.PLT)+int64(r.Off))+r.Add+4)) >> 12)), true
case objabi.R_PLT2: // ldr pc, [ip, #0xZZZ]!
- return 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+8))), true
+ return 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(syms.PLT)+int64(r.Off))+r.Add+8))), true
case objabi.R_CALLARM: // bl XXXXXX or b YYYYYY
// r.Add is the instruction
// low 24-bit encodes the target address
@@ -667,7 +666,7 @@
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return t
}
@@ -690,14 +689,14 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ctxt.Syms.Lookup(".plt", 0)
got := ctxt.Syms.Lookup(".got.plt", 0)
rel := ctxt.Syms.Lookup(".rel.plt", 0)
if plt.Size == 0 {
- elfsetupplt(ctxt)
+ panic("plt is not set up")
}
// .got entry
@@ -745,7 +744,7 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
got := ctxt.Syms.Lookup(".got", 0)
s.SetGot(int32(got.Size))
got.AddUint32(ctxt.Arch, 0)
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 9c3f442..0b4ecd6 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -34,9 +34,9 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
- "encoding/binary"
"fmt"
"log"
)
@@ -92,7 +92,7 @@
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
targ := r.Sym
switch r.Type {
@@ -434,14 +434,14 @@
return true
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
switch r.Type {
default:
return val, false
case objabi.R_ARM64_GOTPCREL:
var o1, o2 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o1 = uint32(val >> 32)
o2 = uint32(val)
} else {
@@ -456,14 +456,14 @@
// (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
// add + R_ADDRARM64.
- if !(r.Sym.IsFileLocal() || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && ctxt.DynlinkingGo() {
+ if !(r.Sym.IsFileLocal() || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && target.IsDynlinkingGo() {
if o2&0xffc00000 != 0xf9400000 {
ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
}
o2 = 0x91000000 | (o2 & 0x000003ff)
r.Type = objabi.R_ADDRARM64
}
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
val = int64(o1)<<32 | int64(o2)
} else {
val = int64(o2)<<32 | int64(o1)
@@ -490,10 +490,10 @@
// the BR26 relocation should be fully resolved at link time.
// That is the reason why the next if block is disabled. When the bug in ld64
// is fixed, we can enable this block and also enable duff's device in cmd/7g.
- if false && ctxt.HeadType == objabi.Hdarwin {
+ if false && target.IsDarwin() {
var o0, o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o0 = uint32(val >> 32)
o1 = uint32(val)
} else {
@@ -510,7 +510,7 @@
r.Xadd = 0
// when laid out, the instruction order must always be o1, o2.
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
val = int64(o0)<<32 | int64(o1)
} else {
val = int64(o1)<<32 | int64(o0)
@@ -533,7 +533,7 @@
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
case objabi.R_ADDRARM64:
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
@@ -543,7 +543,7 @@
var o0, o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o0 = uint32(val >> 32)
o1 = uint32(val)
} else {
@@ -555,42 +555,42 @@
o1 |= uint32(t&0xfff) << 10
// when laid out, the instruction order must always be o1, o2.
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
return int64(o0)<<32 | int64(o1), true
}
return int64(o1)<<32 | int64(o0), true
case objabi.R_ARM64_TLS_LE:
r.Done = false
- if ctxt.HeadType == objabi.Hdarwin {
- ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
+ if target.IsDarwin() {
+ ld.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
}
// The TCB is two pointers. This is not documented anywhere, but is
// de facto part of the ABI.
- v := r.Sym.Value + int64(2*ctxt.Arch.PtrSize)
+ v := r.Sym.Value + int64(2*target.Arch.PtrSize)
if v < 0 || v >= 32678 {
ld.Errorf(s, "TLS offset out of range %d", v)
}
return val | (v << 5), true
case objabi.R_ARM64_TLS_IE:
- if ctxt.BuildMode == ld.BuildModePIE && ctxt.IsELF {
+ if target.IsPIE() && target.IsElf() {
// We are linking the final executable, so we
// can optimize any TLS IE relocation to LE.
r.Done = false
- if ctxt.HeadType != objabi.Hlinux {
- ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
+ if !target.IsLinux() {
+ ld.Errorf(s, "TLS reloc on unsupported OS %v", target.HeadType)
}
// The TCB is two pointers. This is not documented anywhere, but is
// de facto part of the ABI.
- v := ld.Symaddr(r.Sym) + int64(2*ctxt.Arch.PtrSize) + r.Add
+ v := ld.Symaddr(r.Sym) + int64(2*target.Arch.PtrSize) + r.Add
if v < 0 || v >= 32678 {
ld.Errorf(s, "TLS offset out of range %d", v)
}
var o0, o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o0 = uint32(val >> 32)
o1 = uint32(val)
} else {
@@ -609,7 +609,7 @@
o1 = 0xf2800000 | uint32(o1&0x1f) | (uint32(v&0xffff) << 5)
// when laid out, the instruction order must always be o0, o1.
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
return int64(o0)<<32 | int64(o1), true
}
return int64(o1)<<32 | int64(o0), true
@@ -620,7 +620,7 @@
case objabi.R_CALLARM64:
var t int64
if r.Sym.Type == sym.SDYNIMPORT {
- t = (ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) + r.Add) - (s.Value + int64(r.Off))
+ t = (ld.Symaddr(syms.PLT) + r.Add) - (s.Value + int64(r.Off))
} else {
t = (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off))
}
@@ -707,35 +707,30 @@
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return -1
}
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- gotplt := ctxt.Syms.Lookup(".got.plt", 0)
- if plt.Size == 0 {
+func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() == 0 {
// stp x16, x30, [sp, #-16]!
// identifying information
plt.AddUint32(ctxt.Arch, 0xa9bf7bf0)
// the following two instructions (adrp + ldr) load *got[2] into x17
// adrp x16, &got[0]
- plt.AddAddrPlus4(gotplt, 16)
- plt.SetUint32(ctxt.Arch, plt.Size-4, 0x90000010)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
+ plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x90000010)
// <imm> is the offset value of &got[2] to &got[0], the same below
// ldr x17, [x16, <imm>]
- plt.AddAddrPlus4(gotplt, 16)
- plt.SetUint32(ctxt.Arch, plt.Size-4, 0xf9400211)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_GOT
+ plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_GOT, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0xf9400211)
// add x16, x16, <imm>
- plt.AddAddrPlus4(gotplt, 16)
- plt.SetUint32(ctxt.Arch, plt.Size-4, 0x91000210)
- plt.R[len(plt.R)-1].Type = objabi.R_ARM64_PCREL
+ plt.AddSymRef(ctxt.Arch, gotplt.Sym(), 16, objabi.R_ARM64_PCREL, 4)
+ plt.SetUint32(ctxt.Arch, plt.Size()-4, 0x91000210)
// br x17
plt.AddUint32(ctxt.Arch, 0xd61f0220)
@@ -746,10 +741,10 @@
plt.AddUint32(ctxt.Arch, 0xd503201f)
// check gotplt.size == 0
- if gotplt.Size != 0 {
- ld.Errorf(gotplt, "got.plt is not empty at the very beginning")
+ if gotplt.Size() != 0 {
+ ctxt.Errorf(gotplt.Sym(), "got.plt is not empty at the very beginning")
}
- gotplt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
+ gotplt.AddAddrPlus(ctxt.Arch, dynamic, 0)
gotplt.AddUint64(ctxt.Arch, 0)
gotplt.AddUint64(ctxt.Arch, 0)
@@ -761,14 +756,14 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ctxt.Syms.Lookup(".plt", 0)
gotplt := ctxt.Syms.Lookup(".got.plt", 0)
rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
- elfsetupplt(ctxt)
+ panic("plt is not set up")
}
// adrp x16, &got.plt[0]
@@ -809,7 +804,7 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
got := ctxt.Syms.Lookup(".got", 0)
s.SetGot(int32(got.Size))
got.AddUint64(ctxt.Arch, 0)
diff --git a/src/cmd/link/internal/benchmark/bench.go b/src/cmd/link/internal/benchmark/bench.go
new file mode 100644
index 0000000..52f9826
--- /dev/null
+++ b/src/cmd/link/internal/benchmark/bench.go
@@ -0,0 +1,176 @@
+// Copyright 2020 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 benchmark provides a Metrics object that enables memory and CPU
+// profiling for the linker. The Metrics objects can be used to mark stages
+// of the code, and name the measurements during that stage. There is also
+// optional GCs that can be performed at the end of each stage, so you
+// can get an accurate measurement of how each stage changes live memory.
+package benchmark
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "time"
+ "unicode"
+)
+
+type Flags int
+
+const (
+ GC = 1 << iota
+ NoGC Flags = 0
+)
+
+type Metrics struct {
+ gc Flags
+ marks []*mark
+ curMark *mark
+ filebase string
+ pprofFile *os.File
+}
+
+type mark struct {
+ name string
+ startM, endM, gcM runtime.MemStats
+ startT, endT time.Time
+}
+
+// New creates a new Metrics object.
+//
+// Typical usage should look like:
+//
+// func main() {
+// filename := "" // Set to enable per-phase pprof file output.
+// bench := benchmark.New(benchmark.GC, filename)
+// defer bench.Report(os.Stdout)
+// // etc
+// bench.Start("foo")
+// foo()
+// bench.Start("bar")
+// bar()
+// }
+//
+// Note that a nil Metrics object won't cause any errors, so one could write
+// code like:
+//
+// func main() {
+// enableBenchmarking := flag.Bool("enable", true, "enables benchmarking")
+// flag.Parse()
+// var bench *benchmark.Metrics
+// if *enableBenchmarking {
+// bench = benchmark.New(benchmark.GC)
+// }
+// bench.Start("foo")
+// // etc.
+// }
+func New(gc Flags, filebase string) *Metrics {
+ if gc == GC {
+ runtime.GC()
+ }
+ return &Metrics{gc: gc, filebase: filebase}
+}
+
+// Report reports the metrics.
+// Closes the currently Start(ed) range, and writes the report to the given io.Writer.
+func (m *Metrics) Report(w io.Writer) {
+ if m == nil {
+ return
+ }
+
+ m.closeMark()
+
+ gcString := ""
+ if m.gc == GC {
+ gcString = "_GC"
+ }
+
+ var totTime time.Duration
+ for _, curMark := range m.marks {
+ dur := curMark.endT.Sub(curMark.startT)
+ totTime += dur
+ fmt.Fprintf(w, "%s 1 %d ns/op", makeBenchString(curMark.name+gcString), dur.Nanoseconds())
+ fmt.Fprintf(w, "\t%d B/op", curMark.endM.TotalAlloc-curMark.startM.TotalAlloc)
+ fmt.Fprintf(w, "\t%d allocs/op", curMark.endM.Mallocs-curMark.startM.Mallocs)
+ if m.gc == GC {
+ fmt.Fprintf(w, "\t%d live-B", curMark.gcM.HeapAlloc)
+ } else {
+ fmt.Fprintf(w, "\t%d heap-B", curMark.endM.HeapAlloc)
+ }
+ fmt.Fprintf(w, "\n")
+ }
+ fmt.Fprintf(w, "%s 1 %d ns/op\n", makeBenchString("total time"+gcString), totTime.Nanoseconds())
+}
+
+// Starts marks the beginning of a new measurement phase.
+// Once a metric is started, it continues until either a Report is issued, or another Start is called.
+func (m *Metrics) Start(name string) {
+ if m == nil {
+ return
+ }
+ m.closeMark()
+ m.curMark = &mark{name: name}
+ // Unlikely we need to a GC here, as one was likely just done in closeMark.
+ if m.shouldPProf() {
+ f, err := os.Create(makePProfFilename(m.filebase, name))
+ if err != nil {
+ panic(err)
+ }
+ m.pprofFile = f
+ if err = pprof.StartCPUProfile(m.pprofFile); err != nil {
+ panic(err)
+ }
+ }
+ runtime.ReadMemStats(&m.curMark.startM)
+ m.curMark.startT = time.Now()
+}
+
+func (m *Metrics) closeMark() {
+ if m == nil || m.curMark == nil {
+ return
+ }
+ m.curMark.endT = time.Now()
+ runtime.ReadMemStats(&m.curMark.endM)
+ if m.gc == GC {
+ runtime.GC()
+ runtime.ReadMemStats(&m.curMark.gcM)
+ }
+ if m.shouldPProf() {
+ pprof.StopCPUProfile()
+ m.pprofFile.Close()
+ m.pprofFile = nil
+ }
+ m.marks = append(m.marks, m.curMark)
+ m.curMark = nil
+}
+
+// shouldPProf returns true if we should be doing pprof runs.
+func (m *Metrics) shouldPProf() bool {
+ return m != nil && len(m.filebase) > 0
+}
+
+// makeBenchString makes a benchmark string consumable by Go's benchmarking tools.
+func makeBenchString(name string) string {
+ needCap := true
+ ret := []rune("Benchmark")
+ for _, r := range name {
+ if unicode.IsSpace(r) {
+ needCap = true
+ continue
+ }
+ if needCap {
+ r = unicode.ToUpper(r)
+ needCap = false
+ }
+ ret = append(ret, r)
+ }
+ return string(ret)
+}
+
+func makePProfFilename(filebase, name string) string {
+ return fmt.Sprintf("%s_%s.profile", filebase, makeBenchString(name))
+}
diff --git a/src/cmd/link/internal/benchmark/bench_test.go b/src/cmd/link/internal/benchmark/bench_test.go
new file mode 100644
index 0000000..48d4d74
--- /dev/null
+++ b/src/cmd/link/internal/benchmark/bench_test.go
@@ -0,0 +1,53 @@
+// Copyright 2020 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 benchmark
+
+import (
+ "testing"
+)
+
+func TestMakeBenchString(t *testing.T) {
+ tests := []struct {
+ have, want string
+ }{
+ {"foo", "BenchmarkFoo"},
+ {" foo ", "BenchmarkFoo"},
+ {"foo bar", "BenchmarkFooBar"},
+ }
+ for i, test := range tests {
+ if v := makeBenchString(test.have); test.want != v {
+ t.Errorf("test[%d] makeBenchString(%q) == %q, want %q", i, test.have, v, test.want)
+ }
+ }
+}
+
+func TestPProfFlag(t *testing.T) {
+ tests := []struct {
+ name string
+ want bool
+ }{
+ {"", false},
+ {"foo", true},
+ }
+ for i, test := range tests {
+ b := New(GC, test.name)
+ if v := b.shouldPProf(); test.want != v {
+ t.Errorf("test[%d] shouldPProf() == %v, want %v", i, v, test.want)
+ }
+ }
+}
+
+func TestPProfNames(t *testing.T) {
+ want := "foo_BenchmarkTest.profile"
+ if v := makePProfFilename("foo", "test"); v != want {
+ t.Errorf("makePProfFilename() == %q, want %q", v, want)
+ }
+}
+
+// Ensure that public APIs work with a nil Metrics object.
+func TestNilBenchmarkObject(t *testing.T) {
+ var b *Metrics
+ b.Start("TEST")
+ b.Report(nil)
+}
diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
index 4a20d96..268f40e 100644
--- a/src/cmd/link/internal/ld/ar.go
+++ b/src/cmd/link/internal/ld/ar.go
@@ -104,15 +104,13 @@
any := true
for any {
var load []uint64
- 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 {
- if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
- load = append(load, off)
- loaded[off] = true
- }
- }
+ returnAllUndefs := -1
+ undefs := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
+ for _, symIdx := range undefs {
+ name := ctxt.loader.SymName(symIdx)
+ if off := armap[name]; off != 0 && !loaded[off] {
+ load = append(load, off)
+ loaded[off] = true
}
}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 7ca01c8..39ec054 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -37,6 +37,7 @@
"cmd/internal/gcprog"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"compress/zlib"
"encoding/binary"
@@ -99,7 +100,7 @@
if Symaddr(r.Sym) == 0 && (r.Sym.Type != sym.SDYNIMPORT && r.Sym.Type != sym.SUNDEFEXT) {
if r.Sym.File != s.File {
if !isRuntimeDepPkg(s.File) || !isRuntimeDepPkg(r.Sym.File) {
- ctxt.ErrorUnresolved(s, r)
+ ctxt.errorUnresolved(s, r)
}
// runtime and its dependent packages may call to each other.
// they are fine, as they will be laid down together.
@@ -126,7 +127,9 @@
//
// This is a performance-critical function for the linker; be careful
// to avoid introducing unnecessary allocations in the main loop.
-func relocsym(ctxt *Link, s *sym.Symbol) {
+// TODO: This function is called in parallel. When the Loader wavefront
+// reaches here, calls into the loader need to be parallel as well.
+func relocsym(target *Target, err *ErrorReporter, lookup LookupFn, syms *ArchSyms, s *sym.Symbol) {
if len(s.R) == 0 {
return
}
@@ -157,8 +160,8 @@
if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) {
// When putting the runtime but not main into a shared library
// these symbols are undefined and that's OK.
- if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin {
- if r.Sym.Name == "main.main" || (ctxt.BuildMode != BuildModePlugin && r.Sym.Name == "main..inittask") {
+ if target.IsShared() || target.IsPlugin() {
+ if r.Sym.Name == "main.main" || (!target.IsPlugin() && r.Sym.Name == "main..inittask") {
r.Sym.Type = sym.SDYNIMPORT
} else if strings.HasPrefix(r.Sym.Name, "go.info.") {
// Skip go.info symbols. They are only needed to communicate
@@ -166,7 +169,7 @@
continue
}
} else {
- ctxt.ErrorUnresolved(s, r)
+ err.errorUnresolved(s, r)
continue
}
}
@@ -180,21 +183,21 @@
// We need to be able to reference dynimport symbols when linking against
// shared libraries, and Solaris, Darwin and AIX need it always
- if ctxt.HeadType != objabi.Hsolaris && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Haix && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !ctxt.DynlinkingGo() && !r.Sym.Attr.SubSymbol() {
- if !(ctxt.Arch.Family == sys.PPC64 && ctxt.LinkMode == LinkExternal && r.Sym.Name == ".TOC.") {
- Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(ctxt.Arch, r.Type))
+ if !target.IsSolaris() && !target.IsDarwin() && !target.IsAIX() && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !target.IsDynlinkingGo() && !r.Sym.Attr.SubSymbol() {
+ if !(target.IsPPC64() && target.IsExternal() && r.Sym.Name == ".TOC.") {
+ Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(target.Arch, r.Type))
}
}
if r.Sym != nil && r.Sym.Type != sym.STLSBSS && r.Type != objabi.R_WEAKADDROFF && !r.Sym.Attr.Reachable() {
Errorf(s, "unreachable sym in relocation: %s", r.Sym.Name)
}
- if ctxt.LinkMode == LinkExternal {
+ if target.IsExternal() {
r.InitExt()
}
// TODO(mundaym): remove this special case - see issue 14218.
- if ctxt.Arch.Family == sys.S390X {
+ if target.IsS390X() {
switch r.Type {
case objabi.R_PCRELDBL:
r.InitExt()
@@ -215,33 +218,33 @@
case 1:
o = int64(s.P[off])
case 2:
- o = int64(ctxt.Arch.ByteOrder.Uint16(s.P[off:]))
+ o = int64(target.Arch.ByteOrder.Uint16(s.P[off:]))
case 4:
- o = int64(ctxt.Arch.ByteOrder.Uint32(s.P[off:]))
+ o = int64(target.Arch.ByteOrder.Uint32(s.P[off:]))
case 8:
- o = int64(ctxt.Arch.ByteOrder.Uint64(s.P[off:]))
+ o = int64(target.Arch.ByteOrder.Uint64(s.P[off:]))
}
- if offset, ok := thearch.Archreloc(ctxt, r, s, o); ok {
+ if offset, ok := thearch.Archreloc(target, syms, r, s, o); ok {
o = offset
} else {
- Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type))
+ Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(target.Arch, r.Type))
}
case objabi.R_TLS_LE:
- if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
+ if target.IsExternal() && target.IsElf() {
r.Done = false
if r.Sym == nil {
- r.Sym = ctxt.Tlsg
+ r.Sym = syms.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
- if ctxt.Arch.Family != sys.AMD64 {
+ if !target.IsAMD64() {
o = r.Add
}
break
}
- if ctxt.IsELF && ctxt.Arch.Family == sys.ARM {
+ if target.IsElf() && target.IsARM() {
// On ELF ARM, the thread pointer is 8 bytes before
// the start of the thread-local data block, so add 8
// to the actual TLS offset (r->sym->value).
@@ -250,43 +253,43 @@
// related to the fact that our own TLS storage happens
// to take up 8 bytes.
o = 8 + r.Sym.Value
- } else if ctxt.IsELF || ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hdarwin {
- o = int64(ctxt.Tlsoffset) + r.Add
- } else if ctxt.HeadType == objabi.Hwindows {
+ } else if target.IsElf() || target.IsPlan9() || target.IsDarwin() {
+ o = int64(syms.Tlsoffset) + r.Add
+ } else if target.IsWindows() {
o = r.Add
} else {
- log.Fatalf("unexpected R_TLS_LE relocation for %v", ctxt.HeadType)
+ log.Fatalf("unexpected R_TLS_LE relocation for %v", target.HeadType)
}
case objabi.R_TLS_IE:
- if ctxt.LinkMode == LinkExternal && ctxt.IsELF {
+ if target.IsExternal() && target.IsElf() {
r.Done = false
if r.Sym == nil {
- r.Sym = ctxt.Tlsg
+ r.Sym = syms.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
o = 0
- if ctxt.Arch.Family != sys.AMD64 {
+ if !target.IsAMD64() {
o = r.Add
}
break
}
- if ctxt.BuildMode == BuildModePIE && ctxt.IsELF {
+ if target.IsPIE() && target.IsElf() {
// We are linking the final executable, so we
// can optimize any TLS IE relocation to LE.
if thearch.TLSIEtoLE == nil {
- log.Fatalf("internal linking of TLS IE not supported on %v", ctxt.Arch.Family)
+ log.Fatalf("internal linking of TLS IE not supported on %v", target.Arch.Family)
}
thearch.TLSIEtoLE(s, int(off), int(r.Siz))
- o = int64(ctxt.Tlsoffset)
- // TODO: o += r.Add when ctxt.Arch.Family != sys.AMD64?
+ o = int64(syms.Tlsoffset)
+ // TODO: o += r.Add when !target.IsAmd64()?
// Why do we treat r.Add differently on AMD64?
// Is the external linker using Xadd at all?
} else {
log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", s.Name)
}
case objabi.R_ADDR:
- if ctxt.LinkMode == LinkExternal && r.Sym.Type != sym.SCONST {
+ if target.IsExternal() && r.Sym.Type != sym.SCONST {
r.Done = false
// set up addend for eventual relocation via outer symbol.
@@ -304,20 +307,20 @@
r.Xsym = rs
o = r.Xadd
- if ctxt.IsELF {
- if ctxt.Arch.Family == sys.AMD64 {
+ if target.IsElf() {
+ if target.IsAMD64() {
o = 0
}
- } else if ctxt.HeadType == objabi.Hdarwin {
+ } else if target.IsDarwin() {
if rs.Type != sym.SHOSTOBJ {
o += Symaddr(rs)
}
- } else if ctxt.HeadType == objabi.Hwindows {
+ } else if target.IsWindows() {
// nothing to do
- } else if ctxt.HeadType == objabi.Haix {
+ } else if target.IsAIX() {
o = Symaddr(r.Sym) + r.Add
} else {
- Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType)
+ Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
}
break
@@ -327,14 +330,14 @@
// as section addresses can change once loaded.
// The "default" symbol address is still needed by the loader so
// the current relocation can't be skipped.
- if ctxt.HeadType == objabi.Haix && r.Sym.Type != sym.SDYNIMPORT {
+ if target.IsAIX() && r.Sym.Type != sym.SDYNIMPORT {
// It's not possible to make a loader relocation in a
// symbol which is not inside .data section.
// FIXME: It should be forbidden to have R_ADDR from a
// symbol which isn't in .data. However, as .text has the
// same address once loaded, this is possible.
if s.Sect.Seg == &Segdata {
- Xcoffadddynrel(ctxt, s, r)
+ Xcoffadddynrel(target, s, r)
}
}
@@ -345,7 +348,7 @@
// fail at runtime. See https://golang.org/issue/7980.
// Instead of special casing only amd64, we treat this as an error on all
// 64-bit architectures so as to be future-proof.
- if int32(o) < 0 && ctxt.Arch.PtrSize > 4 && siz == 4 {
+ if int32(o) < 0 && target.Arch.PtrSize > 4 && siz == 4 {
Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add)
errorexit()
}
@@ -354,7 +357,7 @@
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
}
- if ctxt.LinkMode == LinkExternal {
+ if target.IsExternal() {
r.Done = false
// On most platforms, the external linker needs to adjust DWARF references
@@ -362,7 +365,7 @@
// DWARF linking, and it understands how to follow section offsets.
// Leaving in the relocation records confuses it (see
// https://golang.org/issue/22068) so drop them for Darwin.
- if ctxt.HeadType == objabi.Hdarwin {
+ if target.IsDarwin() {
r.Done = true
}
@@ -371,15 +374,15 @@
// IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32.
// Do not replace R_DWARFSECREF with R_ADDR for windows -
// let PE code emit correct relocations.
- if ctxt.HeadType != objabi.Hwindows {
+ if !target.IsWindows() {
r.Type = objabi.R_ADDR
}
- r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
+ r.Xsym = lookup(r.Sym.Sect.Name, 0)
r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
o = r.Xadd
- if ctxt.IsELF && ctxt.Arch.Family == sys.AMD64 {
+ if target.IsElf() && target.IsAMD64() {
o = 0
}
break
@@ -406,7 +409,7 @@
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL:
- if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin && r.Sym != nil && r.Sym.Type != sym.SCONST {
+ if target.IsDynlinkingGo() && target.IsDarwin() && r.Sym != nil && r.Sym.Type != sym.SCONST {
r.Done = false
r.Xadd = r.Add
r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
@@ -418,18 +421,18 @@
}
fallthrough
case objabi.R_CALL, objabi.R_PCREL:
- if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
+ if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT {
// pass through to the external linker.
r.Done = false
r.Xadd = 0
- if ctxt.IsELF {
+ if target.IsElf() {
r.Xadd -= int64(r.Siz)
}
r.Xsym = r.Sym
o = 0
break
}
- if ctxt.LinkMode == LinkExternal && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
+ if target.IsExternal() && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) {
r.Done = false
// set up addend for eventual relocation via outer symbol.
@@ -448,14 +451,14 @@
r.Xsym = rs
o = r.Xadd
- if ctxt.IsELF {
- if ctxt.Arch.Family == sys.AMD64 {
+ if target.IsElf() {
+ if target.IsAMD64() {
o = 0
}
- } else if ctxt.HeadType == objabi.Hdarwin {
+ } else if target.IsDarwin() {
if r.Type == objabi.R_CALL {
- if ctxt.LinkMode == LinkExternal && rs.Type == sym.SDYNIMPORT {
- switch ctxt.Arch.Family {
+ if target.IsExternal() && rs.Type == sym.SDYNIMPORT {
+ switch target.Arch.Family {
case sys.AMD64:
// AMD64 dynamic relocations are relative to the end of the relocation.
o += int64(r.Siz)
@@ -470,18 +473,18 @@
}
o -= int64(r.Off) // relative to section offset, not symbol
}
- } else if ctxt.Arch.Family == sys.ARM {
+ } else if target.IsARM() {
// see ../arm/asm.go:/machoreloc1
o += Symaddr(rs) - s.Value - int64(r.Off)
} else {
o += int64(r.Siz)
}
- } else if ctxt.HeadType == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 { // only amd64 needs PCREL
+ } else if target.IsWindows() && target.IsAMD64() { // only amd64 needs PCREL
// PE/COFF's PC32 relocation uses the address after the relocated
// bytes as the base. Compensate by skewing the addend.
o += int64(r.Siz)
} else {
- Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, ctxt.HeadType)
+ Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType)
}
break
@@ -497,10 +500,10 @@
o = r.Sym.Size + r.Add
case objabi.R_XCOFFREF:
- if ctxt.HeadType != objabi.Haix {
+ if !target.IsAIX() {
Errorf(s, "find XCOFF R_REF on non-XCOFF files")
}
- if ctxt.LinkMode != LinkExternal {
+ if !target.IsExternal() {
Errorf(s, "find XCOFF R_REF with internal linking")
}
r.Xsym = r.Sym
@@ -516,10 +519,10 @@
o = r.Add
}
- if ctxt.Arch.Family == sys.PPC64 || ctxt.Arch.Family == sys.S390X {
+ if target.IsPPC64() || target.IsS390X() {
r.InitExt()
if r.Variant != sym.RV_NONE {
- o = thearch.Archrelocvariant(ctxt, r, s, o)
+ o = thearch.Archrelocvariant(target, syms, r, s, o)
}
}
@@ -534,7 +537,7 @@
if r.Xsym != nil {
xnam = r.Xsym.Name
}
- fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Variant, o)
+ fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(target.Arch, r.Type), r.Variant, o)
}
switch siz {
default:
@@ -549,7 +552,7 @@
Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o)
}
i16 := int16(o)
- ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
+ target.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
case 4:
if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL {
if o != int64(int32(o)) {
@@ -562,23 +565,39 @@
}
fl := int32(o)
- ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
+ target.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
case 8:
- ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+ target.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
}
}
}
func (ctxt *Link) reloc() {
- for _, s := range ctxt.Textp {
- relocsym(ctxt, s)
- }
- for _, s := range datap {
- relocsym(ctxt, s)
- }
- for _, s := range dwarfp {
- relocsym(ctxt, s)
- }
+ var wg sync.WaitGroup
+ target := &ctxt.Target
+ reporter := &ctxt.ErrorReporter
+ lookup := ctxt.Syms.ROLookup
+ syms := &ctxt.ArchSyms
+ wg.Add(3)
+ go func() {
+ for _, s := range ctxt.Textp {
+ relocsym(target, reporter, lookup, syms, s)
+ }
+ wg.Done()
+ }()
+ go func() {
+ for _, s := range datap {
+ relocsym(target, reporter, lookup, syms, s)
+ }
+ wg.Done()
+ }()
+ go func() {
+ for _, s := range dwarfp {
+ relocsym(target, reporter, lookup, syms, s)
+ }
+ wg.Done()
+ }()
+ wg.Wait()
}
func windynrelocsym(ctxt *Link, rel, s *sym.Symbol) {
@@ -646,13 +665,15 @@
}
func dynrelocsym(ctxt *Link, s *sym.Symbol) {
+ target := &ctxt.Target
+ syms := &ctxt.ArchSyms
for ri := range s.R {
r := &s.R[ri]
if ctxt.BuildMode == BuildModePIE && ctxt.LinkMode == LinkInternal {
// It's expected that some relocations will be done
// later by relocsym (R_TLS_LE, R_ADDROFF), so
// don't worry if Adddynrel returns false.
- thearch.Adddynrel(ctxt, s, r)
+ thearch.Adddynrel(ctxt, target, syms, s, r)
continue
}
@@ -660,7 +681,7 @@
if r.Sym != nil && !r.Sym.Attr.Reachable() {
Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
}
- if !thearch.Adddynrel(ctxt, s, r) {
+ if !thearch.Adddynrel(ctxt, target, syms, s, r) {
Errorf(s, "unsupported dynamic relocation for symbol %s (type=%d (%s) stype=%d (%s))", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Type, r.Sym.Type)
}
}
@@ -927,48 +948,40 @@
}
// addstrdata sets the initial value of the string variable name to value.
-func addstrdata(ctxt *Link, name, value string) {
- s := ctxt.Syms.ROLookup(name, 0)
- if s == nil || s.Gotype == nil {
- // Not defined in the loaded packages.
+func addstrdata(arch *sys.Arch, l *loader.Loader, name, value string) {
+ s := l.Lookup(name, 0)
+ if s == 0 {
return
}
- if s.Gotype.Name != "type.string" {
- Errorf(s, "cannot set with -X: not a var of type string (%s)", s.Gotype.Name)
+ if goType := l.SymGoType(s); goType == 0 {
+ return
+ } else if typeName := l.SymName(goType); typeName != "type.string" {
+ Errorf(nil, "%s: cannot set with -X: not a var of type string (%s)", name, typeName)
return
}
- if s.Type == sym.SBSS {
- s.Type = sym.SDATA
+ bld := l.MakeSymbolUpdater(s)
+ if bld.Type() == sym.SBSS {
+ bld.SetType(sym.SDATA)
}
- p := fmt.Sprintf("%s.str", s.Name)
- sp := ctxt.Syms.Lookup(p, 0)
+ p := fmt.Sprintf("%s.str", name)
+ sp := l.LookupOrCreateSym(p, 0)
+ sbld := l.MakeSymbolUpdater(sp)
- Addstring(sp, value)
- sp.Type = sym.SRODATA
+ sbld.Addstring(value)
+ sbld.SetType(sym.SRODATA)
- s.Size = 0
- s.P = s.P[:0]
- if s.Attr.ReadOnly() {
- s.P = make([]byte, 0, ctxt.Arch.PtrSize*2)
- s.Attr.Set(sym.AttrReadOnly, false)
- }
- s.R = s.R[:0]
- reachable := s.Attr.Reachable()
- s.AddAddr(ctxt.Arch, sp)
- s.AddUint(ctxt.Arch, uint64(len(value)))
-
- // addstring, addaddr, etc., mark the symbols as reachable.
- // In this case that is not necessarily true, so stick to what
- // we know before entering this function.
- s.Attr.Set(sym.AttrReachable, reachable)
-
- sp.Attr.Set(sym.AttrReachable, reachable)
+ bld.SetSize(0)
+ bld.SetData(make([]byte, 0, arch.PtrSize*2))
+ bld.SetReadOnly(false)
+ bld.SetRelocs(nil)
+ bld.AddAddrPlus(arch, sp, 0)
+ bld.AddUint(arch, uint64(len(value)))
}
func (ctxt *Link) dostrdata() {
for _, name := range strnames {
- addstrdata(ctxt, name, strdata[name])
+ addstrdata(ctxt.Arch, ctxt.loader, name, strdata[name])
}
}
@@ -2450,6 +2463,8 @@
binary.BigEndian.PutUint64(sizeBytes[:], uint64(total))
buf.Write(sizeBytes[:])
+ var relocbuf []byte // temporary buffer for applying relocations
+
// Using zlib.BestSpeed achieves very nearly the same
// compression levels of zlib.DefaultCompression, but takes
// substantially less time. This is important because DWARF
@@ -2458,17 +2473,22 @@
if err != nil {
log.Fatalf("NewWriterLevel failed: %s", err)
}
+ target := &ctxt.Target
+ reporter := &ctxt.ErrorReporter
+ lookup := ctxt.Syms.ROLookup
+ archSyms := &ctxt.ArchSyms
for _, s := range syms {
// s.P may be read-only. Apply relocations in a
// temporary buffer, and immediately write it out.
oldP := s.P
wasReadOnly := s.Attr.ReadOnly()
if len(s.R) != 0 && wasReadOnly {
- ctxt.relocbuf = append(ctxt.relocbuf[:0], s.P...)
- s.P = ctxt.relocbuf
+ relocbuf = append(relocbuf[:0], s.P...)
+ s.P = relocbuf
+ // TODO: This function call needs to be parallelized when the loader wavefront gets here.
s.Attr.Set(sym.AttrReadOnly, false)
}
- relocsym(ctxt, s)
+ relocsym(target, reporter, lookup, archSyms, s)
if _, err := z.Write(s.P); err != nil {
log.Fatalf("compression failed: %s", err)
}
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 6d96ae5..13ddcda 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -6,11 +6,7 @@
import (
"cmd/internal/objabi"
- "cmd/internal/sys"
"cmd/link/internal/sym"
- "fmt"
- "strings"
- "unicode"
)
// deadcode marks all reachable symbols.
@@ -46,363 +42,59 @@
//
// Any unreached text symbols are removed from ctxt.Textp.
func deadcode(ctxt *Link) {
- if ctxt.Debugvlog != 0 {
- ctxt.Logf("deadcode\n")
- }
-
- if *flagNewobj {
- deadcode2(ctxt)
- return
- }
-
- d := &deadcodepass{
- ctxt: ctxt,
- ifaceMethod: make(map[methodsig]bool),
- }
-
- // First, flood fill any symbols directly reachable in the call
- // graph from *flagEntrySymbol. Ignore all methods not directly called.
- d.init()
- d.flood()
-
- callSym := ctxt.Syms.ROLookup("reflect.Value.Call", sym.SymVerABIInternal)
- methSym := ctxt.Syms.ROLookup("reflect.Value.Method", sym.SymVerABIInternal)
- reflectSeen := false
-
- if ctxt.DynlinkingGo() {
- // Exported methods may satisfy interfaces we don't know
- // about yet when dynamically linking.
- reflectSeen = true
- }
-
- for {
- if !reflectSeen {
- if d.reflectMethod || (callSym != nil && callSym.Attr.Reachable()) || (methSym != nil && methSym.Attr.Reachable()) {
- // Methods might be called via reflection. Give up on
- // static analysis, mark all exported methods of
- // all reachable types as reachable.
- reflectSeen = true
- }
- }
-
- // Mark all methods that could satisfy a discovered
- // interface as reachable. We recheck old marked interfaces
- // as new types (with new methods) may have been discovered
- // in the last pass.
- var rem []methodref
- for _, m := range d.markableMethods {
- if (reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
- d.markMethod(m)
- } else {
- rem = append(rem, m)
- }
- }
- d.markableMethods = rem
-
- if len(d.markQueue) == 0 {
- // No new work was discovered. Done.
- break
- }
- d.flood()
- }
-
- // Remove all remaining unreached R_METHODOFF relocations.
- for _, m := range d.markableMethods {
- for _, r := range m.r {
- d.cleanupReloc(r)
- }
- }
-
- if ctxt.BuildMode != BuildModeShared {
- // Keep a itablink if the symbol it points at is being kept.
- // (When BuildModeShared, always keep itablinks.)
- for _, s := range ctxt.Syms.Allsym {
- if strings.HasPrefix(s.Name, "go.itablink.") {
- s.Attr.Set(sym.AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
- }
- }
- }
-
- addToTextp(ctxt)
+ deadcode2(ctxt)
}
+// addToTextp populates the context Textp slice (needed in various places
+// in the linker) and also the unit Textp slices (needed by the "old"
+// phase 2 DWARF generation).
func addToTextp(ctxt *Link) {
- // Remove dead text but keep file information (z symbols).
- textp := []*sym.Symbol{}
- for _, s := range ctxt.Textp {
- if s.Attr.Reachable() {
- 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)
+ // First set up ctxt.Textp, based on ctxt.Textp2.
+ textp := make([]*sym.Symbol, 0, len(ctxt.Textp2))
+ haveshlibs := len(ctxt.Shlibs) > 0
+ for _, tsym := range ctxt.Textp2 {
+ sp := ctxt.loader.Syms[tsym]
+ if sp == nil || !ctxt.loader.AttrReachable(tsym) {
+ panic("should never happen")
+ }
+ if haveshlibs && sp.Type == sym.SDYNIMPORT {
+ continue
+ }
+ textp = append(textp, sp)
+ }
+ ctxt.Textp = textp
+
+ // Dupok symbols may be defined in multiple packages; the
+ // associated package for a dupok sym is chosen sort of
+ // arbitrarily (the first containing package that the linker
+ // loads). The loop below canonicalizes the File to the package
+ // with which it will be laid down in text. Assumes that
+ // ctxt.Library is already in postorder.
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
-// method. There are three relocations, one for each of the fields in
-// the reflect.method struct: mtyp, ifn, and tfn.
-type methodref struct {
- m methodsig
- src *sym.Symbol // receiver type symbol
- r [3]*sym.Reloc // R_METHODOFF relocations to fields of runtime.method
-}
-
-func (m methodref) ifn() *sym.Symbol { return m.r[1].Sym }
-
-func (m methodref) isExported() bool {
- for _, r := range m.m {
- return unicode.IsUpper(r)
- }
- panic("methodref has no signature")
-}
-
-// deadcodepass holds state for the deadcode flood fill.
-type deadcodepass struct {
- ctxt *Link
- markQueue []*sym.Symbol // symbols to flood fill in next pass
- ifaceMethod map[methodsig]bool // methods declared in reached interfaces
- markableMethods []methodref // methods of reached types
- reflectMethod bool
-}
-
-func (d *deadcodepass) cleanupReloc(r *sym.Reloc) {
- if r.Sym.Attr.Reachable() {
- r.Type = objabi.R_ADDROFF
- } else {
- if d.ctxt.Debugvlog > 1 {
- d.ctxt.Logf("removing method %s\n", r.Sym.Name)
- }
- r.Sym = nil
- r.Siz = 0
- }
-}
-
-// mark appends a symbol to the mark queue for flood filling.
-func (d *deadcodepass) mark(s, parent *sym.Symbol) {
- if s == nil || s.Attr.Reachable() {
- return
- }
- if s.Attr.ReflectMethod() {
- d.reflectMethod = true
- }
- if *flagDumpDep {
- p := "_"
- if parent != nil {
- p = parent.Name
- }
- fmt.Printf("%s -> %s\n", p, s.Name)
- }
- s.Attr |= sym.AttrReachable
- if d.ctxt.Reachparent != nil {
- d.ctxt.Reachparent[s] = parent
- }
- d.markQueue = append(d.markQueue, s)
-}
-
-// markMethod marks a method as reachable.
-func (d *deadcodepass) markMethod(m methodref) {
- for _, r := range m.r {
- d.mark(r.Sym, m.src)
- r.Type = objabi.R_ADDROFF
- }
-}
-
-// init marks all initial symbols as reachable.
-// In a typical binary, this is *flagEntrySymbol.
-func (d *deadcodepass) init() {
- var names []string
-
- if d.ctxt.BuildMode == BuildModeShared {
- // Mark all symbols defined in this library as reachable when
- // building a shared library.
- for _, s := range d.ctxt.Syms.Allsym {
- if s.Type != 0 && s.Type != sym.SDYNIMPORT {
- d.mark(s, nil)
- }
- }
- } else {
- // 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.
- exports := d.ctxt.Syms.ROLookup("go.plugin.exports", 0)
- if exports != nil {
- for i := range exports.R {
- d.mark(exports.R[i].Sym, nil)
- }
+ for _, dsym := range lib.DupTextSyms2 {
+ tsp := ctxt.loader.Syms[dsym]
+ if !tsp.Attr.OnList() {
+ tsp.Attr |= sym.AttrOnList
+ tsp.File = objabi.PathToPrefix(lib.Pkg)
}
}
}
- for _, s := range dynexp {
- d.mark(s, nil)
- }
}
- for _, name := range names {
- // Mark symbol as a data/ABI0 symbol.
- d.mark(d.ctxt.Syms.ROLookup(name, 0), nil)
- // Also mark any Go functions (internal ABI).
- d.mark(d.ctxt.Syms.ROLookup(name, sym.SymVerABIInternal), nil)
- }
-}
-
-// flood fills symbols reachable from the markQueue symbols.
-// As it goes, it collects methodref and interface method declarations.
-func (d *deadcodepass) flood() {
- for len(d.markQueue) > 0 {
- s := d.markQueue[0]
- d.markQueue = d.markQueue[1:]
- if s.Type == sym.STEXT {
- if d.ctxt.Debugvlog > 1 {
- d.ctxt.Logf("marktext %s\n", s.Name)
+ // Finally, set up compilation unit Textp slices. Can be removed
+ // once loader-Sym DWARF-gen phase 2 is always enabled.
+ for _, lib := range ctxt.Library {
+ for _, unit := range lib.Units {
+ for _, usym := range unit.Textp2 {
+ usp := ctxt.loader.Syms[usym]
+ usp.Attr |= sym.AttrOnList
+ unit.Textp = append(unit.Textp, usp)
}
}
-
- if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' {
- if len(s.P) == 0 {
- // Probably a bug. The undefined symbol check
- // later will give a better error than deadcode.
- continue
- }
- 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)
- }
- d.ifaceMethod[sig] = true
- }
- }
- }
-
- mpos := 0 // 0-3, the R_METHODOFF relocs of runtime.uncommontype
- var methods []methodref
- for i := range s.R {
- r := &s.R[i]
- if r.Sym == nil {
- continue
- }
- if r.Type == objabi.R_WEAKADDROFF {
- // An R_WEAKADDROFF relocation is not reason
- // enough to mark the pointed-to symbol as
- // reachable.
- continue
- }
- if r.Sym.Type == sym.SABIALIAS {
- // Patch this relocation through the
- // ABI alias before marking.
- r.Sym = resolveABIAlias(r.Sym)
- }
- if r.Type != objabi.R_METHODOFF {
- d.mark(r.Sym, s)
- continue
- }
- // Collect rtype pointers to methods for
- // later processing in deadcode.
- if mpos == 0 {
- m := methodref{src: s}
- m.r[0] = r
- methods = append(methods, m)
- } else {
- methods[len(methods)-1].r[mpos] = r
- }
- mpos++
- if mpos == len(methodref{}.r) {
- mpos = 0
- }
- }
- if len(methods) > 0 {
- // Decode runtime type information for type methods
- // to help work out which methods can be called
- // dynamically via interfaces.
- methodsigs := decodetypeMethods(d.ctxt.Arch, s)
- if len(methods) != len(methodsigs) {
- panic(fmt.Sprintf("%q has %d method relocations for %d methods", s.Name, len(methods), len(methodsigs)))
- }
- for i, m := range methodsigs {
- name := string(m)
- name = name[:strings.Index(name, "(")]
- if !strings.HasSuffix(methods[i].ifn().Name, name) {
- panic(fmt.Sprintf("%q relocation for %q does not match method %q", s.Name, methods[i].ifn().Name, name))
- }
- methods[i].m = m
- }
- d.markableMethods = append(d.markableMethods, methods...)
- }
-
- if s.FuncInfo != nil {
- for i := range s.FuncInfo.Funcdata {
- d.mark(s.FuncInfo.Funcdata[i], s)
- }
- }
- d.mark(s.Gotype, s)
- d.mark(s.Sub, s)
- d.mark(s.Outer, s)
}
}
diff --git a/src/cmd/link/internal/ld/deadcode2.go b/src/cmd/link/internal/ld/deadcode2.go
index 9197c70..a7a41e3 100644
--- a/src/cmd/link/internal/ld/deadcode2.go
+++ b/src/cmd/link/internal/ld/deadcode2.go
@@ -37,7 +37,6 @@
ctxt *Link
ldr *loader.Loader
wq workQueue
- rtmp []loader.Reloc
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
markableMethods []methodref2 // methods of reached types
@@ -58,9 +57,7 @@
n := d.ldr.NDef()
for i := 1; i < n; i++ {
s := loader.Sym(i)
- if !d.ldr.IsDup(s) {
- d.mark(s, 0)
- }
+ d.mark(s, 0)
}
return
}
@@ -88,9 +85,9 @@
// but we do keep the symbols it refers to.
exportsIdx := d.ldr.Lookup("go.plugin.exports", 0)
if exportsIdx != 0 {
- d.ReadRelocs(exportsIdx)
- for i := 0; i < len(d.rtmp); i++ {
- d.mark(d.rtmp[i].Sym, 0)
+ relocs := d.ldr.Relocs(exportsIdx)
+ for i := 0; i < relocs.Count; i++ {
+ d.mark(relocs.At2(i).Sym(), 0)
}
}
}
@@ -121,20 +118,19 @@
}
func (d *deadcodePass2) flood() {
- symRelocs := []loader.Reloc{}
auxSyms := []loader.Sym{}
for !d.wq.empty() {
symIdx := d.wq.pop()
d.reflectSeen = d.reflectSeen || d.ldr.IsReflectMethod(symIdx)
+ isgotype := d.ldr.IsGoType(symIdx)
relocs := d.ldr.Relocs(symIdx)
- symRelocs = relocs.ReadAll(symRelocs)
- if d.ldr.IsGoType(symIdx) {
+ if isgotype {
p := d.ldr.Data(symIdx)
if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface {
- for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs) {
+ for _, sig := range d.decodeIfaceMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs) {
if d.ctxt.Debugvlog > 1 {
d.ctxt.Logf("reached iface method: %s\n", sig)
}
@@ -145,11 +141,12 @@
var methods []methodref2
for i := 0; i < relocs.Count; i++ {
- r := symRelocs[i]
- if r.Type == objabi.R_WEAKADDROFF {
+ r := relocs.At2(i)
+ t := r.Type()
+ if t == objabi.R_WEAKADDROFF {
continue
}
- if r.Type == objabi.R_METHODOFF {
+ if t == objabi.R_METHODOFF {
if i+2 >= relocs.Count {
panic("expect three consecutive R_METHODOFF relocs")
}
@@ -157,13 +154,13 @@
i += 2
continue
}
- if r.Type == objabi.R_USETYPE {
+ if t == objabi.R_USETYPE {
// type symbol used for DWARF. we need to load the symbol but it may not
// be otherwise reachable in the program.
// do nothing for now as we still load all type symbols.
continue
}
- d.mark(r.Sym, symIdx)
+ d.mark(r.Sym(), symIdx)
}
auxSyms = d.ldr.ReadAuxSyms(symIdx, auxSyms)
for i := 0; i < len(auxSyms); i++ {
@@ -179,10 +176,13 @@
d.mark(d.ldr.SubSym(symIdx), symIdx)
if len(methods) != 0 {
+ if !isgotype {
+ panic("method found on non-type symbol")
+ }
// Decode runtime type information for type methods
// to help work out which methods can be called
// dynamically via interfaces.
- methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, symRelocs)
+ methodsigs := d.decodetypeMethods2(d.ldr, d.ctxt.Arch, symIdx, &relocs)
if len(methods) != len(methodsigs) {
panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs)))
}
@@ -195,9 +195,9 @@
}
func (d *deadcodePass2) mark(symIdx, parent loader.Sym) {
- if symIdx != 0 && !d.ldr.Reachable.Has(symIdx) {
+ if symIdx != 0 && !d.ldr.AttrReachable(symIdx) {
d.wq.push(symIdx)
- d.ldr.Reachable.Set(symIdx)
+ d.ldr.SetAttrReachable(symIdx, true)
if d.ctxt.Reachparent != nil {
d.ldr.Reachparent[symIdx] = parent
}
@@ -215,10 +215,10 @@
}
func (d *deadcodePass2) markMethod(m methodref2) {
- d.ReadRelocs(m.src)
- d.mark(d.rtmp[m.r].Sym, m.src)
- d.mark(d.rtmp[m.r+1].Sym, m.src)
- d.mark(d.rtmp[m.r+2].Sym, m.src)
+ relocs := d.ldr.Relocs(m.src)
+ d.mark(relocs.At2(m.r).Sym(), m.src)
+ d.mark(relocs.At2(m.r+1).Sym(), m.src)
+ d.mark(relocs.At2(m.r+2).Sym(), m.src)
}
func deadcode2(ctxt *Link) {
@@ -239,7 +239,7 @@
// Methods might be called via reflection. Give up on
// static analysis, mark all exported methods of
// all reachable types as reachable.
- d.reflectSeen = d.reflectSeen || (callSym != 0 && ldr.Reachable.Has(callSym)) || (methSym != 0 && ldr.Reachable.Has(methSym))
+ d.reflectSeen = d.reflectSeen || (callSym != 0 && ldr.AttrReachable(callSym)) || (methSym != 0 && ldr.AttrReachable(methSym))
// Mark all methods that could satisfy a discovered
// interface as reachable. We recheck old marked interfaces
@@ -271,8 +271,8 @@
s := loader.Sym(i)
if ldr.IsItabLink(s) {
relocs := ldr.Relocs(s)
- if relocs.Count > 0 && ldr.Reachable.Has(relocs.At(0).Sym) {
- ldr.Reachable.Set(s)
+ if relocs.Count > 0 && ldr.AttrReachable(relocs.At(0).Sym) {
+ ldr.SetAttrReachable(s, true)
}
}
}
@@ -301,15 +301,15 @@
// the function type.
//
// Conveniently this is the layout of both runtime.method and runtime.imethod.
-func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, off, size, count int) []methodsig {
+func (d *deadcodePass2) decodeMethodSig2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, off, size, count int) []methodsig {
var buf bytes.Buffer
var methods []methodsig
for i := 0; i < count; i++ {
- buf.WriteString(decodetypeName2(ldr, symIdx, symRelocs, off))
- mtypSym := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off+4))
+ buf.WriteString(decodetypeName3(ldr, symIdx, relocs, off))
+ mtypSym := decodeRelocSym3(ldr, symIdx, relocs, int32(off+4))
// FIXME: add some sort of caching here, since we may see some of the
// same symbols over time for param types.
- d.ReadRelocs(mtypSym)
+ mrelocs := ldr.Relocs(mtypSym)
mp := ldr.Data(mtypSym)
buf.WriteRune('(')
@@ -318,7 +318,7 @@
if i > 0 {
buf.WriteString(", ")
}
- a := d.decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i)
+ a := decodetypeFuncInType3(ldr, arch, mtypSym, &mrelocs, i)
buf.WriteString(ldr.SymName(a))
}
buf.WriteString(") (")
@@ -327,7 +327,7 @@
if i > 0 {
buf.WriteString(", ")
}
- a := d.decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, i)
+ a := decodetypeFuncOutType3(ldr, arch, mtypSym, &mrelocs, i)
buf.WriteString(ldr.SymName(a))
}
buf.WriteRune(')')
@@ -339,25 +339,26 @@
return methods
}
-func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig {
+func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
p := ldr.Data(symIdx)
if decodetypeKind(arch, p)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
}
- rel := decodeReloc2(ldr, symIdx, symRelocs, int32(commonsize(arch)+arch.PtrSize))
- if rel.Sym == 0 {
+ rel := decodeReloc3(ldr, symIdx, relocs, int32(commonsize(arch)+arch.PtrSize))
+ s := rel.Sym()
+ if s == 0 {
return nil
}
- if rel.Sym != symIdx {
+ if s != symIdx {
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", ldr.SymName(symIdx)))
}
- off := int(rel.Add) // array of reflect.imethod values
+ off := int(rel.Add()) // array of reflect.imethod values
numMethods := int(decodetypeIfaceMethodCount(arch, p))
sizeofIMethod := 4 + 4
- return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofIMethod, numMethods)
+ return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofIMethod, numMethods)
}
-func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig {
+func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
p := ldr.Data(symIdx)
if !decodetypeHasUncommon(arch, p) {
panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx)))
@@ -388,54 +389,5 @@
moff := int(decodeInuxi(arch, p[off+4+2+2:], 4))
off += moff // offset to array of reflect.method values
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
- return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofMethod, mcount)
-}
-
-func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Reloc {
- for j := 0; j < len(symRelocs); j++ {
- rel := symRelocs[j]
- if rel.Off == off {
- return rel
- }
- }
- return loader.Reloc{}
-}
-
-func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Sym {
- return decodeReloc2(ldr, symIdx, symRelocs, off).Sym
-}
-
-// decodetypeName2 decodes the name from a reflect.name.
-func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int) string {
- r := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off))
- if r == 0 {
- return ""
- }
-
- data := ldr.Data(r)
- namelen := int(uint16(data[1])<<8 | uint16(data[2]))
- return string(data[3 : 3+namelen])
-}
-
-func (d *deadcodePass2) decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
- uadd := commonsize(arch) + 4
- if arch.PtrSize == 8 {
- uadd += 4
- }
- if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
- uadd += uncommonSize()
- }
- return decodeRelocSym2(ldr, symIdx, symRelocs, int32(uadd+i*arch.PtrSize))
-}
-
-func (d *deadcodePass2) decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
- return d.decodetypeFuncInType2(ldr, arch, symIdx, symRelocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
-}
-
-// readRelocs reads the relocations for the specified symbol into the
-// deadcode relocs work array. Use with care, since the work array
-// is a singleton.
-func (d *deadcodePass2) ReadRelocs(symIdx loader.Sym) {
- relocs := d.ldr.Relocs(symIdx)
- d.rtmp = relocs.ReadAll(d.rtmp)
+ return d.decodeMethodSig2(ldr, arch, symIdx, relocs, off, sizeofMethod, mcount)
}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index 3271c85..5058608 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -125,11 +125,6 @@
func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
if ctxt.Arch.Family == sys.ARM64 {
- for _, shlib := range ctxt.Shlibs {
- if shlib.Path == s.File {
- return shlib.gcdataAddresses[s]
- }
- }
return 0
}
return decodeInuxi(ctxt.Arch, s.P[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
diff --git a/src/cmd/link/internal/ld/decodesym2.go b/src/cmd/link/internal/ld/decodesym2.go
new file mode 100644
index 0000000..e93cc91
--- /dev/null
+++ b/src/cmd/link/internal/ld/decodesym2.go
@@ -0,0 +1,187 @@
+// 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/sys"
+ "cmd/link/internal/loader"
+)
+
+// This file contains utilities to decode type.* symbols, for
+// loader.Sym symbols (uses new loader interfaces).
+
+// At some point we'll want to migrate the contents of this file
+// to decodesym.go once the rouetines there have been decprecated + removed.
+
+func decodeReloc2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Reloc {
+ for j := 0; j < len(symRelocs); j++ {
+ rel := symRelocs[j]
+ if rel.Off == off {
+ return rel
+ }
+ }
+ return loader.Reloc{}
+}
+
+func decodeReloc3(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Reloc2 {
+ for j := 0; j < relocs.Count; j++ {
+ rel := relocs.At2(j)
+ if rel.Off() == off {
+ return rel
+ }
+ }
+ return loader.Reloc2{}
+}
+
+func decodeRelocSym2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int32) loader.Sym {
+ return decodeReloc2(ldr, symIdx, symRelocs, off).Sym
+}
+
+func decodeRelocSym3(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Sym {
+ return decodeReloc3(ldr, symIdx, relocs, off).Sym()
+}
+
+// decodetypeName2 decodes the name from a reflect.name.
+func decodetypeName2(ldr *loader.Loader, symIdx loader.Sym, symRelocs []loader.Reloc, off int) string {
+ r := decodeRelocSym2(ldr, symIdx, symRelocs, int32(off))
+ if r == 0 {
+ return ""
+ }
+
+ data := ldr.Data(r)
+ namelen := int(uint16(data[1])<<8 | uint16(data[2]))
+ return string(data[3 : 3+namelen])
+}
+
+func decodetypeName3(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) string {
+ r := decodeRelocSym3(ldr, symIdx, relocs, int32(off))
+ if r == 0 {
+ return ""
+ }
+
+ data := ldr.Data(r)
+ namelen := int(uint16(data[1])<<8 | uint16(data[2]))
+ return string(data[3 : 3+namelen])
+}
+
+func decodetypeFuncInType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
+ uadd := commonsize(arch) + 4
+ if arch.PtrSize == 8 {
+ uadd += 4
+ }
+ if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
+ uadd += uncommonSize()
+ }
+ return decodeRelocSym2(ldr, symIdx, symRelocs, int32(uadd+i*arch.PtrSize))
+}
+
+func decodetypeFuncInType3(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
+ uadd := commonsize(arch) + 4
+ if arch.PtrSize == 8 {
+ uadd += 4
+ }
+ if decodetypeHasUncommon(arch, ldr.Data(symIdx)) {
+ uadd += uncommonSize()
+ }
+ return decodeRelocSym3(ldr, symIdx, relocs, int32(uadd+i*arch.PtrSize))
+}
+
+func decodetypeFuncOutType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc, i int) loader.Sym {
+ return decodetypeFuncInType2(ldr, arch, symIdx, symRelocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
+}
+
+func decodetypeFuncOutType3(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym {
+ return decodetypeFuncInType3(ldr, arch, symIdx, relocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx)))
+}
+
+func decodetypeArrayElem2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
+ // FIXME: it's inefficient to read the relocations each time. Add some
+ // sort of cache here, or pass in the relocs. Alternatively we could
+ // switch to relocs.At() to see if that performs better.
+ relocs := ldr.Relocs(symIdx)
+ rslice := relocs.ReadAll(nil)
+ return decodeRelocSym2(ldr, symIdx, rslice, int32(commonsize(arch))) // 0x1c / 0x30
+}
+
+func decodetypeArrayLen2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int64 {
+ data := ldr.Data(symIdx)
+ return int64(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
+}
+
+func decodetypeChanElem2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
+ // FIXME: it's inefficient to read the relocations each time. Add some
+ // sort of cache here, or pass in the relocs.
+ relocs := ldr.Relocs(symIdx)
+ rslice := relocs.ReadAll(nil)
+ return decodeRelocSym2(ldr, symIdx, rslice, int32(commonsize(arch))) // 0x1c / 0x30
+}
+
+func decodetypeMapKey2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
+ // FIXME: it's inefficient to read the relocations each time. Add some
+ // sort of cache here, or pass in the relocs. Alternatively we could
+ // switch to relocs.At() to see if that performs better.
+ relocs := ldr.Relocs(symIdx)
+ rslice := relocs.ReadAll(nil)
+ return decodeRelocSym2(ldr, symIdx, rslice, int32(commonsize(arch))) // 0x1c / 0x30
+}
+
+func decodetypeMapValue2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
+ // FIXME: it's inefficient to read the relocations each time. Add some
+ // sort of cache here, or pass in the relocs. Alternatively we could
+ // switch to relocs.At() to see if that performs better.
+ relocs := ldr.Relocs(symIdx)
+ rslice := relocs.ReadAll(nil)
+ return decodeRelocSym2(ldr, symIdx, rslice, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
+}
+
+func decodetypePtrElem2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym {
+ // FIXME: it's inefficient to read the relocations each time. Add some
+ // sort of cache here, or pass in the relocs. Alternatively we could
+ // switch to relocs.At() to see if that performs better.
+ relocs := ldr.Relocs(symIdx)
+ rslice := relocs.ReadAll(nil)
+ return decodeRelocSym2(ldr, symIdx, rslice, int32(commonsize(arch))) // 0x1c / 0x30
+}
+
+func decodetypeStructFieldCount2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int {
+ data := ldr.Data(symIdx)
+ return int(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
+}
+
+func decodetypeStructFieldArrayOff2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int {
+ data := ldr.Data(symIdx)
+ off := commonsize(arch) + 4*arch.PtrSize
+ if decodetypeHasUncommon(arch, data) {
+ off += uncommonSize()
+ }
+ off += i * structfieldSize(arch)
+ return off
+}
+
+func decodetypeStructFieldName2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) string {
+ off := decodetypeStructFieldArrayOff2(ldr, arch, symIdx, i)
+ // FIXME: it's inefficient to read the relocations each time. Add some
+ // sort of cache here, or pass in the relocs. Alternatively we could
+ // switch to relocs.At() to see if that performs better.
+ relocs := ldr.Relocs(symIdx)
+ rslice := relocs.ReadAll(nil)
+ return decodetypeName2(ldr, symIdx, rslice, off)
+}
+
+func decodetypeStructFieldType2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) loader.Sym {
+ off := decodetypeStructFieldArrayOff2(ldr, arch, symIdx, i)
+ // FIXME: it's inefficient to read the relocations each time. Add some
+ // sort of cache here, or pass in the relocs. Alternatively we could
+ // switch to relocs.At() to see if that performs better.
+ relocs := ldr.Relocs(symIdx)
+ rslice := relocs.ReadAll(nil)
+ return decodeRelocSym2(ldr, symIdx, rslice, int32(off+arch.PtrSize))
+}
+
+func decodetypeStructFieldOffsAnon2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int64 {
+ off := decodetypeStructFieldArrayOff2(ldr, arch, symIdx, i)
+ data := ldr.Data(symIdx)
+ return int64(decodeInuxi(arch, data[off+2*arch.PtrSize:], arch.PtrSize))
+}
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 6eba39b..dcc9576 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors. All rights reserved.
+// 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.
@@ -19,6 +19,7 @@
"cmd/internal/objabi"
"cmd/internal/src"
"cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"fmt"
"log"
@@ -26,105 +27,181 @@
"strings"
)
-type dwctxt struct {
+// dwctxt2 is a wrapper intended to satisfy the method set of
+// dwarf.Context, so that functions like dwarf.PutAttrs will work with
+// DIEs that use loader.Sym as opposed to *sym.Symbol. It is also
+// being used as a place to store tables/maps that are useful as part
+// of type conversion (this is just a convenience; it would be easy to
+// split these things out into another type if need be).
+type dwctxt2 struct {
linkctxt *Link
+ ldr *loader.Loader
+ arch *sys.Arch
+
+ // This maps type name string (e.g. "uintptr") to loader symbol for
+ // the DWARF DIE for that type (e.g. "go.info.type.uintptr")
+ tmap map[string]loader.Sym
+
+ // This maps loader symbol for the DWARF DIE symbol generated for
+ // a type (e.g. "go.info.uintptr") to the type symbol itself
+ // ("type.uintptr").
+ // FIXME: try converting this map (and the next one) to a single
+ // array indexed by loader.Sym -- this may perform better.
+ rtmap map[loader.Sym]loader.Sym
+
+ // This maps Go type symbol (e.g. "type.XXX") to loader symbol for
+ // the typedef DIE for that type (e.g. "go.info.XXX..def")
+ tdmap map[loader.Sym]loader.Sym
+
+ // Cache these type symbols, so as to avoid repeatedly looking them up
+ typeRuntimeEface loader.Sym
+ typeRuntimeIface loader.Sym
+ uintptrInfoSym loader.Sym
}
-func (c dwctxt) PtrSize() int {
- return c.linkctxt.Arch.PtrSize
-}
-func (c dwctxt) AddInt(s dwarf.Sym, size int, i int64) {
- ls := s.(*sym.Symbol)
- ls.AddUintXX(c.linkctxt.Arch, uint64(i), size)
-}
-func (c dwctxt) AddBytes(s dwarf.Sym, b []byte) {
- ls := s.(*sym.Symbol)
- ls.AddBytes(b)
-}
-func (c dwctxt) AddString(s dwarf.Sym, v string) {
- Addstring(s.(*sym.Symbol), v)
-}
-
-func (c dwctxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
- if value != 0 {
- value -= (data.(*sym.Symbol)).Value
+func newdwctxt2(linkctxt *Link, forTypeGen bool) dwctxt2 {
+ d := dwctxt2{
+ linkctxt: linkctxt,
+ ldr: linkctxt.loader,
+ arch: linkctxt.Arch,
+ tmap: make(map[string]loader.Sym),
+ tdmap: make(map[loader.Sym]loader.Sym),
+ rtmap: make(map[loader.Sym]loader.Sym),
}
- s.(*sym.Symbol).AddAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value)
+ d.typeRuntimeEface = d.lookupOrDiag("type.runtime.eface")
+ d.typeRuntimeIface = d.lookupOrDiag("type.runtime.iface")
+ return d
}
-func (c dwctxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
+// dwSym wraps a loader.Sym; this type is meant to obey the interface
+// rules for dwarf.Sym from the cmd/internal/dwarf package. DwDie and
+// DwAttr objects contain references to symbols via this type.
+type dwSym loader.Sym
+
+func (s dwSym) Length(dwarfContext interface{}) int64 {
+ l := dwarfContext.(dwctxt2).ldr
+ return int64(len(l.Data(loader.Sym(s))))
+}
+
+func (c dwctxt2) PtrSize() int {
+ return c.arch.PtrSize
+}
+
+func (c dwctxt2) AddInt(s dwarf.Sym, size int, i int64) {
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
+ dsu.AddUintXX(c.arch, uint64(i), size)
+}
+
+func (c dwctxt2) AddBytes(s dwarf.Sym, b []byte) {
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
+ dsu.AddBytes(b)
+}
+
+func (c dwctxt2) AddString(s dwarf.Sym, v string) {
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
+ dsu.Addstring(v)
+}
+
+func (c dwctxt2) AddAddress(s dwarf.Sym, data interface{}, value int64) {
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
if value != 0 {
- value -= (data.(*sym.Symbol)).Value
+ value -= dsu.Value()
}
- s.(*sym.Symbol).AddCURelativeAddrPlus(c.linkctxt.Arch, data.(*sym.Symbol), value)
+ tgtds := loader.Sym(data.(dwSym))
+ dsu.AddAddrPlus(c.arch, tgtds, value)
}
-func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
- ls := s.(*sym.Symbol)
+func (c dwctxt2) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
+ if value != 0 {
+ value -= dsu.Value()
+ }
+ tgtds := loader.Sym(data.(dwSym))
+ dsu.AddCURelativeAddrPlus(c.arch, tgtds, value)
+}
+
+func (c dwctxt2) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
+ tds := loader.Sym(t.(dwSym))
switch size {
default:
- Errorf(ls, "invalid size %d in adddwarfref\n", size)
+ c.linkctxt.Errorf(ds, "invalid size %d in adddwarfref\n", size)
fallthrough
- case c.linkctxt.Arch.PtrSize:
- ls.AddAddr(c.linkctxt.Arch, t.(*sym.Symbol))
+ case c.arch.PtrSize:
+ dsu.AddAddrPlus(c.arch, tds, 0)
case 4:
- ls.AddAddrPlus4(t.(*sym.Symbol), 0)
+ dsu.AddAddrPlus4(c.arch, tds, 0)
}
- r := &ls.R[len(ls.R)-1]
+ rsl := dsu.Relocs()
+ r := &rsl[len(rsl)-1]
r.Type = objabi.R_ADDROFF
r.Add = ofs
}
-func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
+func (c dwctxt2) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
size := 4
if isDwarf64(c.linkctxt) {
size = 8
}
c.AddSectionOffset(s, size, t, ofs)
- ls := s.(*sym.Symbol)
- ls.R[len(ls.R)-1].Type = objabi.R_DWARFSECREF
+
+ ds := loader.Sym(s.(dwSym))
+ dsu := c.ldr.MakeSymbolUpdater(ds)
+ rsl := dsu.Relocs()
+ r := &rsl[len(rsl)-1]
+ r.Type = objabi.R_DWARFSECREF
}
-func (c dwctxt) Logf(format string, args ...interface{}) {
+func (c dwctxt2) Logf(format string, args ...interface{}) {
c.linkctxt.Logf(format, args...)
}
// At the moment these interfaces are only used in the compiler.
-func (c dwctxt) AddFileRef(s dwarf.Sym, f interface{}) {
+func (c dwctxt2) AddFileRef(s dwarf.Sym, f interface{}) {
panic("should be used only in the compiler")
}
-func (c dwctxt) CurrentOffset(s dwarf.Sym) int64 {
+func (c dwctxt2) CurrentOffset(s dwarf.Sym) int64 {
panic("should be used only in the compiler")
}
-func (c dwctxt) RecordDclReference(s dwarf.Sym, t dwarf.Sym, dclIdx int, inlIndex int) {
+func (c dwctxt2) RecordDclReference(s dwarf.Sym, t dwarf.Sym, dclIdx int, inlIndex int) {
panic("should be used only in the compiler")
}
-func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
+func (c dwctxt2) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
panic("should be used only in the compiler")
}
-func isDwarf64(ctxt *Link) bool {
- return ctxt.HeadType == objabi.Haix
-}
-
var gdbscript string
-var dwarfp []*sym.Symbol
+var dwarfp2 []loader.Sym
-func writeabbrev(ctxt *Link) *sym.Symbol {
- s := ctxt.Syms.Lookup(".debug_abbrev", 0)
- s.Type = sym.SDWARFSECT
- s.AddBytes(dwarf.GetAbbrev())
- return s
+func (d *dwctxt2) writeabbrev() loader.Sym {
+ abrvs := d.ldr.AddExtSym(".debug_abbrev", 0)
+ u := d.ldr.MakeSymbolUpdater(abrvs)
+ u.SetType(sym.SDWARFSECT)
+ u.AddBytes(dwarf.GetAbbrev())
+ return abrvs
}
var dwtypes dwarf.DWDie
+// newattr attaches a new attribute to the specified DIE.
+//
+// FIXME: at the moment attributes are stored in a linked list in a
+// fairly space-inefficient way -- it might be better to instead look
+// up all attrs in a single large table, then store indices into the
+// table in the DIE. This would allow us to common up storage for
+// attributes that are shared by many DIEs (ex: byte size of N).
func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) *dwarf.DWAttr {
a := new(dwarf.DWAttr)
a.Link = die.Attr
@@ -165,7 +242,8 @@
// attribute (but it will only be written out if it is listed in the abbrev).
// The compiler does create nameless DWARF DIEs (ex: concrete subprogram
// instance).
-func newdie(ctxt *Link, parent *dwarf.DWDie, abbrev int, name string, version int) *dwarf.DWDie {
+// FIXME: it would be more efficient to bulk-allocate DIEs.
+func (d *dwctxt2) newdie(parent *dwarf.DWDie, abbrev int, name string, version int) *dwarf.DWDie {
die := new(dwarf.DWDie)
die.Abbrev = abbrev
die.Link = parent.Child
@@ -174,15 +252,22 @@
newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(name)), name)
if name != "" && (abbrev <= dwarf.DW_ABRV_VARIABLE || abbrev >= dwarf.DW_ABRV_NULLTYPE) {
+ // Q: do we need version here? My understanding is that all these
+ // symbols should be version 0.
if abbrev != dwarf.DW_ABRV_VARIABLE || version == 0 {
if abbrev == dwarf.DW_ABRV_COMPUNIT {
// Avoid collisions with "real" symbol names.
- name = fmt.Sprintf(".pkg.%s.%d", name, len(ctxt.compUnits))
+ name = fmt.Sprintf(".pkg.%s.%d", name, len(d.linkctxt.compUnits))
}
- s := ctxt.Syms.Lookup(dwarf.InfoPrefix+name, version)
- s.Attr |= sym.AttrNotInSymbolTable
- s.Type = sym.SDWARFINFO
- die.Sym = s
+ ds := d.ldr.LookupOrCreateSym(dwarf.InfoPrefix+name, version)
+ dsu := d.ldr.MakeSymbolUpdater(ds)
+ dsu.SetType(sym.SDWARFINFO)
+ d.ldr.SetAttrNotInSymbolTable(ds, true)
+ d.ldr.SetAttrReachable(ds, true)
+ die.Sym = dwSym(ds)
+ if abbrev >= dwarf.DW_ABRV_NULLTYPE && abbrev <= dwarf.DW_ABRV_TYPEDECL {
+ d.tmap[name] = ds
+ }
}
}
@@ -205,11 +290,22 @@
return die
}
-func walksymtypedef(ctxt *Link, s *sym.Symbol) *sym.Symbol {
- if t := ctxt.Syms.ROLookup(s.Name+"..def", int(s.Version)); t != nil {
- return t
+func (d *dwctxt2) walksymtypedef(symIdx loader.Sym) loader.Sym {
+
+ // We're being given the loader symbol for the type DIE, e.g.
+ // "go.info.type.uintptr". Map that first to the type symbol (e.g.
+ // "type.uintptr") and then to the typedef DIE for the type.
+ // FIXME: this seems clunky, maybe there is a better way to do this.
+
+ if ts, ok := d.rtmap[symIdx]; ok {
+ if def, ok := d.tdmap[ts]; ok {
+ return def
+ }
+ d.linkctxt.Errorf(ts, "internal error: no entry for sym %d in tdmap\n", ts)
+ return 0
}
- return s
+ d.linkctxt.Errorf(symIdx, "internal error: no entry for sym %d in rtmap\n", symIdx)
+ return 0
}
// Find child by AT_name using hashtable if available or linear scan
@@ -230,73 +326,72 @@
// Used to avoid string allocation when looking up dwarf symbols
var prefixBuf = []byte(dwarf.InfoPrefix)
-func find(ctxt *Link, name string) *sym.Symbol {
- n := append(prefixBuf, name...)
- // The string allocation below is optimized away because it is only used in a map lookup.
- s := ctxt.Syms.ROLookup(string(n), 0)
- prefixBuf = n[:len(dwarf.InfoPrefix)]
- if s != nil && s.Type == sym.SDWARFINFO {
- return s
- }
- return nil
+// find looks up the loader symbol for the DWARF DIE generated for the
+// type with the specified name.
+func (d *dwctxt2) find(name string) loader.Sym {
+ return d.tmap[name]
}
-func mustFind(ctxt *Link, name string) *sym.Symbol {
- r := find(ctxt, name)
- if r == nil {
+func (d *dwctxt2) mustFind(name string) loader.Sym {
+ r := d.find(name)
+ if r == 0 {
Exitf("dwarf find: cannot find %s", name)
}
return r
}
-func adddwarfref(ctxt *Link, s *sym.Symbol, t *sym.Symbol, size int) int64 {
+func (d *dwctxt2) adddwarfref(sb *loader.SymbolBuilder, t loader.Sym, size int) int64 {
var result int64
switch size {
default:
- Errorf(s, "invalid size %d in adddwarfref\n", size)
+ d.linkctxt.Errorf(sb.Sym(), "invalid size %d in adddwarfref\n", size)
fallthrough
- case ctxt.Arch.PtrSize:
- result = s.AddAddr(ctxt.Arch, t)
+ case d.arch.PtrSize:
+ result = sb.AddAddrPlus(d.arch, t, 0)
case 4:
- result = s.AddAddrPlus4(t, 0)
+ result = sb.AddAddrPlus4(d.arch, t, 0)
}
- r := &s.R[len(s.R)-1]
+ rsl := sb.Relocs()
+ r := &rsl[len(rsl)-1]
r.Type = objabi.R_DWARFSECREF
return result
}
-func newrefattr(die *dwarf.DWDie, attr uint16, ref *sym.Symbol) *dwarf.DWAttr {
- if ref == nil {
+func (d *dwctxt2) newrefattr(die *dwarf.DWDie, attr uint16, ref loader.Sym) *dwarf.DWAttr {
+ if ref == 0 {
return nil
}
- return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, ref)
+ return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, dwSym(ref))
}
-func dtolsym(s dwarf.Sym) *sym.Symbol {
+func (d *dwctxt2) dtolsym(s dwarf.Sym) loader.Sym {
if s == nil {
- return nil
+ return 0
}
- return s.(*sym.Symbol)
+ dws := loader.Sym(s.(dwSym))
+ return dws
}
-func putdie(linkctxt *Link, ctxt dwarf.Context, syms []*sym.Symbol, die *dwarf.DWDie) []*sym.Symbol {
- s := dtolsym(die.Sym)
- if s == nil {
+func (d *dwctxt2) putdie(syms []loader.Sym, die *dwarf.DWDie) []loader.Sym {
+ s := d.dtolsym(die.Sym)
+ if s == 0 {
s = syms[len(syms)-1]
} else {
- if s.Attr.OnList() {
- log.Fatalf("symbol %s listed multiple times", s.Name)
+ if d.ldr.AttrOnList(s) {
+ log.Fatalf("symbol %s listed multiple times", d.ldr.SymName(s))
}
- s.Attr |= sym.AttrOnList
+ d.ldr.SetAttrOnList(s, true)
syms = append(syms, s)
}
- dwarf.Uleb128put(ctxt, s, int64(die.Abbrev))
- dwarf.PutAttrs(ctxt, s, die.Abbrev, die.Attr)
+ sDwsym := dwSym(s)
+ dwarf.Uleb128put(d, sDwsym, int64(die.Abbrev))
+ dwarf.PutAttrs(d, sDwsym, die.Abbrev, die.Attr)
if dwarf.HasChildren(die) {
for die := die.Child; die != nil; die = die.Link {
- syms = putdie(linkctxt, ctxt, syms, die)
+ syms = d.putdie(syms, die)
}
- syms[len(syms)-1].AddUint8(0)
+ dsu := d.ldr.MakeSymbolUpdater(syms[len(syms)-1])
+ dsu.AddUint8(0)
}
return syms
}
@@ -329,42 +424,23 @@
// GDB doesn't like FORM_addr for AT_location, so emit a
// location expression that evals to a const.
-func newabslocexprattr(die *dwarf.DWDie, addr int64, sym *sym.Symbol) {
- newattr(die, dwarf.DW_AT_location, dwarf.DW_CLS_ADDRESS, addr, sym)
- // below
+func (d *dwctxt2) newabslocexprattr(die *dwarf.DWDie, addr int64, symIdx loader.Sym) {
+ newattr(die, dwarf.DW_AT_location, dwarf.DW_CLS_ADDRESS, addr, dwSym(symIdx))
}
-// Lookup predefined types
-func lookupOrDiag(ctxt *Link, n string) *sym.Symbol {
- s := ctxt.Syms.ROLookup(n, 0)
- if s == nil || s.Size == 0 {
+func (d *dwctxt2) lookupOrDiag(n string) loader.Sym {
+ symIdx := d.ldr.Lookup(n, 0)
+ if symIdx == 0 {
Exitf("dwarf: missing type: %s", n)
}
+ if len(d.ldr.Data(symIdx)) == 0 {
+ Exitf("dwarf: missing type (no data): %s", n)
+ }
- return s
+ return symIdx
}
-// dwarfFuncSym looks up a DWARF metadata symbol for function symbol s.
-// If the symbol does not exist, it creates it if create is true,
-// or returns nil otherwise.
-func dwarfFuncSym(ctxt *Link, s *sym.Symbol, meta string, create bool) *sym.Symbol {
- // All function ABIs use symbol version 0 for the DWARF data.
- //
- // TODO(austin): It may be useful to have DWARF info for ABI
- // wrappers, in which case we may want these versions to
- // align. Better yet, replace these name lookups with a
- // general way to attach metadata to a symbol.
- ver := 0
- if s.IsFileLocal() {
- ver = int(s.Version)
- }
- if create {
- return ctxt.Syms.Lookup(meta+s.Name, ver)
- }
- return ctxt.Syms.ROLookup(meta+s.Name, ver)
-}
-
-func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
+func (d *dwctxt2) dotypedef(parent *dwarf.DWDie, gotype loader.Sym, name string, def *dwarf.DWDie) *dwarf.DWDie {
// Only emit typedefs for real names.
if strings.HasPrefix(name, "map[") {
return nil
@@ -382,53 +458,66 @@
Errorf(nil, "dwarf: bad def in dotypedef")
}
- s := ctxt.Syms.Lookup(dtolsym(def.Sym).Name+"..def", 0)
- s.Attr |= sym.AttrNotInSymbolTable
- s.Type = sym.SDWARFINFO
- def.Sym = s
+ // Create a new loader symbol for the typedef. We no longer
+ // do lookups of typedef symbols by name, so this is going
+ // to be an anonymous symbol (we want this for perf reasons).
+ tds := d.ldr.CreateExtSym("")
+ tdsu := d.ldr.MakeSymbolUpdater(tds)
+ tdsu.SetType(sym.SDWARFINFO)
+ def.Sym = dwSym(tds)
+ d.ldr.SetAttrNotInSymbolTable(tds, true)
+ d.ldr.SetAttrReachable(tds, true)
// The typedef entry must be created after the def,
// so that future lookups will find the typedef instead
// of the real definition. This hooks the typedef into any
// circular definition loops, so that gdb can understand them.
- die := newdie(ctxt, parent, dwarf.DW_ABRV_TYPEDECL, name, 0)
+ die := d.newdie(parent, dwarf.DW_ABRV_TYPEDECL, name, 0)
- newrefattr(die, dwarf.DW_AT_type, s)
+ d.newrefattr(die, dwarf.DW_AT_type, tds)
return die
}
// Define gotype, for composite ones recurse into constituents.
-func defgotype(ctxt *Link, gotype *sym.Symbol) *sym.Symbol {
- if gotype == nil {
- return mustFind(ctxt, "<unspecified>")
+func (d *dwctxt2) defgotype(gotype loader.Sym) loader.Sym {
+ if gotype == 0 {
+ return d.mustFind("<unspecified>")
}
- if !strings.HasPrefix(gotype.Name, "type.") {
- Errorf(gotype, "dwarf: type name doesn't start with \"type.\"")
- return mustFind(ctxt, "<unspecified>")
+ // If we already have a tdmap entry for the gotype, return it.
+ if ds, ok := d.tdmap[gotype]; ok {
+ return ds
}
- name := gotype.Name[5:] // could also decode from Type.string
+ sn := d.ldr.SymName(gotype)
+ if !strings.HasPrefix(sn, "type.") {
+ d.linkctxt.Errorf(gotype, "dwarf: type name doesn't start with \"type.\"")
+ return d.mustFind("<unspecified>")
+ }
+ name := sn[5:] // could also decode from Type.string
- sdie := find(ctxt, name)
-
- if sdie != nil {
+ sdie := d.find(name)
+ if sdie != 0 {
return sdie
}
- return newtype(ctxt, gotype).Sym.(*sym.Symbol)
+ gtdwSym := d.newtype(gotype)
+ d.tdmap[gotype] = loader.Sym(gtdwSym.Sym.(dwSym))
+ return loader.Sym(gtdwSym.Sym.(dwSym))
}
-func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
- name := gotype.Name[5:] // could also decode from Type.string
- kind := decodetypeKind(ctxt.Arch, gotype.P)
- bytesize := decodetypeSize(ctxt.Arch, gotype.P)
+func (d *dwctxt2) newtype(gotype loader.Sym) *dwarf.DWDie {
+ sn := d.ldr.SymName(gotype)
+ name := sn[5:] // could also decode from Type.string
+ tdata := d.ldr.Data(gotype)
+ kind := decodetypeKind(d.arch, tdata)
+ bytesize := decodetypeSize(d.arch, tdata)
var die, typedefdie *dwarf.DWDie
switch kind {
case objabi.KindBool:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_boolean, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
@@ -437,7 +526,7 @@
objabi.KindInt16,
objabi.KindInt32,
objabi.KindInt64:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_signed, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
@@ -447,118 +536,126 @@
objabi.KindUint32,
objabi.KindUint64,
objabi.KindUintptr:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
case objabi.KindFloat32,
objabi.KindFloat64:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_float, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
case objabi.KindComplex64,
objabi.KindComplex128:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_complex_float, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
case objabi.KindArray:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name, 0)
+ typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- s := decodetypeArrayElem(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
- fld := newdie(ctxt, die, dwarf.DW_ABRV_ARRAYRANGE, "range", 0)
+ s := decodetypeArrayElem2(d.ldr, d.arch, gotype)
+ d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
+ fld := d.newdie(die, dwarf.DW_ABRV_ARRAYRANGE, "range", 0)
// use actual length not upper bound; correct for 0-length arrays.
- newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, decodetypeArrayLen(ctxt.Arch, gotype), 0)
+ newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, decodetypeArrayLen2(d.ldr, d.arch, gotype), 0)
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
+ d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
case objabi.KindChan:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_CHANTYPE, name, 0)
- s := decodetypeChanElem(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_go_elem, defgotype(ctxt, s))
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_CHANTYPE, name, 0)
+ s := decodetypeChanElem2(d.ldr, d.arch, gotype)
+ d.newrefattr(die, dwarf.DW_AT_go_elem, d.defgotype(s))
// Save elem type for synthesizechantypes. We could synthesize here
// but that would change the order of DIEs we output.
- newrefattr(die, dwarf.DW_AT_type, s)
+ d.newrefattr(die, dwarf.DW_AT_type, s)
case objabi.KindFunc:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
+ die = d.newdie(&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.P)
+ typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+ data := d.ldr.Data(gotype)
+ // FIXME: add caching or reuse reloc slice.
+ relocs := d.ldr.Relocs(gotype)
+ rslice := relocs.ReadAll(nil)
+ nfields := decodetypeFuncInCount(d.arch, data)
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))
+ s := decodetypeFuncInType2(d.ldr, d.arch, gotype, rslice, i)
+ sn := d.ldr.SymName(s)
+ fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:], 0)
+ d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
}
- if decodetypeFuncDotdotdot(ctxt.Arch, gotype.P) {
- newdie(ctxt, die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
+ if decodetypeFuncDotdotdot(d.arch, data) {
+ d.newdie(die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
}
- nfields = decodetypeFuncOutCount(ctxt.Arch, gotype.P)
+ nfields = decodetypeFuncOutCount(d.arch, data)
for i := 0; i < nfields; i++ {
- s := decodetypeFuncOutType(ctxt.Arch, gotype, i)
- fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
- newrefattr(fld, dwarf.DW_AT_type, defptrto(ctxt, defgotype(ctxt, s)))
+ s := decodetypeFuncOutType2(d.ldr, d.arch, gotype, rslice, i)
+ sn := d.ldr.SymName(s)
+ fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:], 0)
+ d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.defgotype(s)))
}
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.P))
- var s *sym.Symbol
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
+ typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+ data := d.ldr.Data(gotype)
+ nfields := int(decodetypeIfaceMethodCount(d.arch, data))
+ var s loader.Sym
if nfields == 0 {
- s = lookupOrDiag(ctxt, "type.runtime.eface")
+ s = d.typeRuntimeEface
} else {
- s = lookupOrDiag(ctxt, "type.runtime.iface")
+ s = d.typeRuntimeIface
}
- newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
+ d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
case objabi.KindMap:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_MAPTYPE, name, 0)
- s := decodetypeMapKey(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_go_key, defgotype(ctxt, s))
- s = decodetypeMapValue(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_go_elem, defgotype(ctxt, s))
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_MAPTYPE, name, 0)
+ s := decodetypeMapKey2(d.ldr, d.arch, gotype)
+ d.newrefattr(die, dwarf.DW_AT_go_key, d.defgotype(s))
+ s = decodetypeMapValue2(d.ldr, d.arch, gotype)
+ d.newrefattr(die, dwarf.DW_AT_go_elem, d.defgotype(s))
// Save gotype for use in synthesizemaptypes. We could synthesize here,
// but that would change the order of the DIEs.
- newrefattr(die, dwarf.DW_AT_type, gotype)
+ d.newrefattr(die, dwarf.DW_AT_type, gotype)
case objabi.KindPtr:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_PTRTYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
- s := decodetypePtrElem(ctxt.Arch, gotype)
- newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, name, 0)
+ typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
+ s := decodetypePtrElem2(d.ldr, d.arch, gotype)
+ d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
case objabi.KindSlice:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_SLICETYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_SLICETYPE, name, 0)
+ typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- s := decodetypeArrayElem(ctxt.Arch, gotype)
- elem := defgotype(ctxt, s)
- newrefattr(die, dwarf.DW_AT_go_elem, elem)
+ s := decodetypeArrayElem2(d.ldr, d.arch, gotype)
+ elem := d.defgotype(s)
+ d.newrefattr(die, dwarf.DW_AT_go_elem, elem)
case objabi.KindString:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_STRINGTYPE, name, 0)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRINGTYPE, name, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
case objabi.KindStruct:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name, 0)
- typedefdie = dotypedef(ctxt, &dwtypes, name, die)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name, 0)
+ typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
- nfields := decodetypeStructFieldCount(ctxt.Arch, gotype)
+ nfields := decodetypeStructFieldCount2(d.ldr, d.arch, gotype)
for i := 0; i < nfields; i++ {
- f := decodetypeStructFieldName(ctxt.Arch, gotype, i)
- s := decodetypeStructFieldType(ctxt.Arch, gotype, i)
+ f := decodetypeStructFieldName2(d.ldr, d.arch, gotype, i)
+ s := decodetypeStructFieldType2(d.ldr, d.arch, gotype, i)
if f == "" {
- f = s.Name[5:] // skip "type."
+ sn := d.ldr.SymName(s)
+ f = sn[5:] // skip "type."
}
- fld := newdie(ctxt, die, dwarf.DW_ABRV_STRUCTFIELD, f, 0)
- newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
- offsetAnon := decodetypeStructFieldOffsAnon(ctxt.Arch, gotype, i)
+ fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f, 0)
+ d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
+ offsetAnon := decodetypeStructFieldOffsAnon2(d.ldr, d.arch, gotype, i)
newmemberoffsetattr(fld, int32(offsetAnon>>1))
if offsetAnon&1 != 0 { // is embedded field
newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0)
@@ -566,21 +663,33 @@
}
case objabi.KindUnsafePointer:
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name, 0)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name, 0)
default:
- Errorf(gotype, "dwarf: definition of unknown kind %d", kind)
- die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_TYPEDECL, name, 0)
- newrefattr(die, dwarf.DW_AT_type, mustFind(ctxt, "<unspecified>"))
+ d.linkctxt.Errorf(gotype, "dwarf: definition of unknown kind %d", kind)
+ die = d.newdie(&dwtypes, dwarf.DW_ABRV_TYPEDECL, name, 0)
+ d.newrefattr(die, dwarf.DW_AT_type, d.mustFind("<unspecified>"))
}
newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(kind), 0)
- if gotype.Attr.Reachable() {
- newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, gotype)
+
+ if d.ldr.AttrReachable(gotype) {
+ newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, dwSym(gotype))
}
- if _, ok := prototypedies[gotype.Name]; ok {
- prototypedies[gotype.Name] = die
+ // Sanity check.
+ if _, ok := d.rtmap[gotype]; ok {
+ log.Fatalf("internal error: rtmap entry already installed\n")
+ }
+
+ ds := loader.Sym(die.Sym.(dwSym))
+ if typedefdie != nil {
+ ds = loader.Sym(typedefdie.Sym.(dwSym))
+ }
+ d.rtmap[ds] = gotype
+
+ if _, ok := prototypedies[sn]; ok {
+ prototypedies[sn] = die
}
if typedefdie != nil {
@@ -589,55 +698,67 @@
return die
}
-func nameFromDIESym(dwtype *sym.Symbol) string {
- return strings.TrimSuffix(dwtype.Name[len(dwarf.InfoPrefix):], "..def")
+func (d *dwctxt2) nameFromDIESym(dwtypeDIESym loader.Sym) string {
+ sn := d.ldr.SymName(dwtypeDIESym)
+ return sn[len(dwarf.InfoPrefix):]
}
-// Find or construct *T given T.
-func defptrto(ctxt *Link, dwtype *sym.Symbol) *sym.Symbol {
- ptrname := "*" + nameFromDIESym(dwtype)
- if die := find(ctxt, ptrname); die != nil {
+func (d *dwctxt2) defptrto(dwtype loader.Sym) loader.Sym {
+
+ // FIXME: it would be nice if the compiler attached an aux symbol
+ // ref from the element type to the pointer type -- it would be
+ // more efficient to do it this way as opposed to via name lookups.
+
+ ptrname := "*" + d.nameFromDIESym(dwtype)
+ if die := d.find(ptrname); die != 0 {
return die
}
- pdie := newdie(ctxt, &dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname, 0)
- newrefattr(pdie, dwarf.DW_AT_type, dwtype)
+ pdie := d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname, 0)
+ d.newrefattr(pdie, dwarf.DW_AT_type, dwtype)
// The DWARF info synthesizes pointer types that don't exist at the
// language level, like *hash<...> and *bucket<...>, and the data
// pointers of slices. Link to the ones we can find.
- gotype := ctxt.Syms.ROLookup("type."+ptrname, 0)
- if gotype != nil && gotype.Attr.Reachable() {
- newattr(pdie, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, gotype)
+ gts := d.ldr.Lookup("type."+ptrname, 0)
+ if gts != 0 && d.ldr.AttrReachable(gts) {
+ newattr(pdie, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, dwSym(gts))
}
- return dtolsym(pdie.Sym)
+
+ if gts != 0 {
+ ds := loader.Sym(pdie.Sym.(dwSym))
+ d.rtmap[ds] = gts
+ d.tdmap[gts] = ds
+ }
+
+ return d.dtolsym(pdie.Sym)
}
// Copies src's children into dst. Copies attributes by value.
// DWAttr.data is copied as pointer only. If except is one of
// the top-level children, it will not be copied.
-func copychildrenexcept(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie, except *dwarf.DWDie) {
+func (d *dwctxt2) copychildrenexcept(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie, except *dwarf.DWDie) {
for src = src.Child; src != nil; src = src.Link {
if src == except {
continue
}
- c := newdie(ctxt, dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string), 0)
+ c := d.newdie(dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string), 0)
for a := src.Attr; a != nil; a = a.Link {
newattr(c, a.Atr, int(a.Cls), a.Value, a.Data)
}
- copychildrenexcept(ctxt, c, src, nil)
+ d.copychildrenexcept(ctxt, c, src, nil)
}
reverselist(&dst.Child)
}
-func copychildren(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie) {
- copychildrenexcept(ctxt, dst, src, nil)
+func (d *dwctxt2) copychildren(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie) {
+ d.copychildrenexcept(ctxt, dst, src, nil)
}
// Search children (assumed to have TAG_member) for the one named
// field and set its AT_type to dwtype
-func substitutetype(structdie *dwarf.DWDie, field string, dwtype *sym.Symbol) {
+func (d *dwctxt2) substitutetype(structdie *dwarf.DWDie, field string, dwtype loader.Sym) {
child := findchild(structdie, field)
if child == nil {
Exitf("dwarf substitutetype: %s does not have member %s",
@@ -647,23 +768,26 @@
a := getattr(child, dwarf.DW_AT_type)
if a != nil {
- a.Data = dwtype
+ a.Data = dwSym(dwtype)
} else {
- newrefattr(child, dwarf.DW_AT_type, dwtype)
+ d.newrefattr(child, dwarf.DW_AT_type, dwtype)
}
}
-func findprotodie(ctxt *Link, name string) *dwarf.DWDie {
+func (d *dwctxt2) findprotodie(ctxt *Link, name string) *dwarf.DWDie {
die, ok := prototypedies[name]
if ok && die == nil {
- defgotype(ctxt, lookupOrDiag(ctxt, name))
+ d.defgotype(d.lookupOrDiag(name))
die = prototypedies[name]
}
+ if die == nil {
+ log.Fatalf("internal error: DIE generation failed for %s\n", name)
+ }
return die
}
-func synthesizestringtypes(ctxt *Link, die *dwarf.DWDie) {
- prototype := walktypedef(findprotodie(ctxt, "type.runtime.stringStructDWARF"))
+func (d *dwctxt2) synthesizestringtypes(ctxt *Link, die *dwarf.DWDie) {
+ prototype := walktypedef(d.findprotodie(ctxt, "type.runtime.stringStructDWARF"))
if prototype == nil {
return
}
@@ -672,12 +796,12 @@
if die.Abbrev != dwarf.DW_ABRV_STRINGTYPE {
continue
}
- copychildren(ctxt, die, prototype)
+ d.copychildren(ctxt, die, prototype)
}
}
-func synthesizeslicetypes(ctxt *Link, die *dwarf.DWDie) {
- prototype := walktypedef(findprotodie(ctxt, "type.runtime.slice"))
+func (d *dwctxt2) synthesizeslicetypes(ctxt *Link, die *dwarf.DWDie) {
+ prototype := walktypedef(d.findprotodie(ctxt, "type.runtime.slice"))
if prototype == nil {
return
}
@@ -686,9 +810,9 @@
if die.Abbrev != dwarf.DW_ABRV_SLICETYPE {
continue
}
- copychildren(ctxt, die, prototype)
- elem := getattr(die, dwarf.DW_AT_go_elem).Data.(*sym.Symbol)
- substitutetype(die, "array", defptrto(ctxt, elem))
+ d.copychildren(ctxt, die, prototype)
+ elem := loader.Sym(getattr(die, dwarf.DW_AT_go_elem).Data.(dwSym))
+ d.substitutetype(die, "array", d.defptrto(elem))
}
}
@@ -706,21 +830,21 @@
BucketSize = 8
)
-func mkinternaltype(ctxt *Link, abbrev int, typename, keyname, valname string, f func(*dwarf.DWDie)) *sym.Symbol {
+func (d *dwctxt2) mkinternaltype(ctxt *Link, abbrev int, typename, keyname, valname string, f func(*dwarf.DWDie)) loader.Sym {
name := mkinternaltypename(typename, keyname, valname)
symname := dwarf.InfoPrefix + name
- s := ctxt.Syms.ROLookup(symname, 0)
- if s != nil && s.Type == sym.SDWARFINFO {
+ s := d.ldr.Lookup(symname, 0)
+ if s != 0 && d.ldr.SymType(s) == sym.SDWARFINFO {
return s
}
- die := newdie(ctxt, &dwtypes, abbrev, name, 0)
+ die := d.newdie(&dwtypes, abbrev, name, 0)
f(die)
- return dtolsym(die.Sym)
+ return d.dtolsym(die.Sym)
}
-func synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
- hash := walktypedef(findprotodie(ctxt, "type.runtime.hmap"))
- bucket := walktypedef(findprotodie(ctxt, "type.runtime.bmap"))
+func (d *dwctxt2) synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
+ hash := walktypedef(d.findprotodie(ctxt, "type.runtime.hmap"))
+ bucket := walktypedef(d.findprotodie(ctxt, "type.runtime.bmap"))
if hash == nil {
return
@@ -730,92 +854,94 @@
if die.Abbrev != dwarf.DW_ABRV_MAPTYPE {
continue
}
- 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.P), decodetypeSize(ctxt.Arch, valtype.P)
- keytype, valtype = walksymtypedef(ctxt, defgotype(ctxt, keytype)), walksymtypedef(ctxt, defgotype(ctxt, valtype))
+ gotype := loader.Sym(getattr(die, dwarf.DW_AT_type).Data.(dwSym))
+ keytype := decodetypeMapKey2(d.ldr, d.arch, gotype)
+ valtype := decodetypeMapValue2(d.ldr, d.arch, gotype)
+ keydata := d.ldr.Data(keytype)
+ valdata := d.ldr.Data(valtype)
+ keysize, valsize := decodetypeSize(d.arch, keydata), decodetypeSize(d.arch, valdata)
+ keytype, valtype = d.walksymtypedef(d.defgotype(keytype)), d.walksymtypedef(d.defgotype(valtype))
// compute size info like hashmap.c does.
indirectKey, indirectVal := false, false
if keysize > MaxKeySize {
- keysize = int64(ctxt.Arch.PtrSize)
+ keysize = int64(d.arch.PtrSize)
indirectKey = true
}
if valsize > MaxValSize {
- valsize = int64(ctxt.Arch.PtrSize)
+ valsize = int64(d.arch.PtrSize)
indirectVal = true
}
// Construct type to represent an array of BucketSize keys
- keyname := nameFromDIESym(keytype)
- dwhks := mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *dwarf.DWDie) {
+ keyname := d.nameFromDIESym(keytype)
+ dwhks := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *dwarf.DWDie) {
newattr(dwhk, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*keysize, 0)
t := keytype
if indirectKey {
- t = defptrto(ctxt, keytype)
+ t = d.defptrto(keytype)
}
- newrefattr(dwhk, dwarf.DW_AT_type, t)
- fld := newdie(ctxt, dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
+ d.newrefattr(dwhk, dwarf.DW_AT_type, t)
+ fld := d.newdie(dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
+ d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
})
// Construct type to represent an array of BucketSize values
- valname := nameFromDIESym(valtype)
- dwhvs := mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *dwarf.DWDie) {
+ valname := d.nameFromDIESym(valtype)
+ dwhvs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *dwarf.DWDie) {
newattr(dwhv, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*valsize, 0)
t := valtype
if indirectVal {
- t = defptrto(ctxt, valtype)
+ t = d.defptrto(valtype)
}
- newrefattr(dwhv, dwarf.DW_AT_type, t)
- fld := newdie(ctxt, dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
+ d.newrefattr(dwhv, dwarf.DW_AT_type, t)
+ fld := d.newdie(dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
+ d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
})
// Construct bucket<K,V>
- dwhbs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *dwarf.DWDie) {
+ dwhbs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *dwarf.DWDie) {
// Copy over all fields except the field "data" from the generic
// bucket. "data" will be replaced with keys/values below.
- copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
+ d.copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
- fld := newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys", 0)
- newrefattr(fld, dwarf.DW_AT_type, dwhks)
+ fld := d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys", 0)
+ d.newrefattr(fld, dwarf.DW_AT_type, dwhks)
newmemberoffsetattr(fld, BucketSize)
- fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values", 0)
- newrefattr(fld, dwarf.DW_AT_type, dwhvs)
+ fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values", 0)
+ d.newrefattr(fld, dwarf.DW_AT_type, dwhvs)
newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
- fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow", 0)
- newrefattr(fld, dwarf.DW_AT_type, defptrto(ctxt, dtolsym(dwhb.Sym)))
+ fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow", 0)
+ d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.dtolsym(dwhb.Sym)))
newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
- if ctxt.Arch.RegSize > ctxt.Arch.PtrSize {
- fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad", 0)
- newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
- newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(ctxt.Arch.PtrSize))
+ if d.arch.RegSize > d.arch.PtrSize {
+ fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad", 0)
+ d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
+ newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(d.arch.PtrSize))
}
- newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(ctxt.Arch.RegSize), 0)
+ newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(d.arch.RegSize), 0)
})
// Construct hash<K,V>
- dwhs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *dwarf.DWDie) {
- copychildren(ctxt, dwh, hash)
- substitutetype(dwh, "buckets", defptrto(ctxt, dwhbs))
- substitutetype(dwh, "oldbuckets", defptrto(ctxt, dwhbs))
+ dwhs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *dwarf.DWDie) {
+ d.copychildren(ctxt, dwh, hash)
+ d.substitutetype(dwh, "buckets", d.defptrto(dwhbs))
+ d.substitutetype(dwh, "oldbuckets", d.defptrto(dwhbs))
newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hash, dwarf.DW_AT_byte_size).Value, nil)
})
// make map type a pointer to hash<K,V>
- newrefattr(die, dwarf.DW_AT_type, defptrto(ctxt, dwhs))
+ d.newrefattr(die, dwarf.DW_AT_type, d.defptrto(dwhs))
}
}
-func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) {
- sudog := walktypedef(findprotodie(ctxt, "type.runtime.sudog"))
- waitq := walktypedef(findprotodie(ctxt, "type.runtime.waitq"))
- hchan := walktypedef(findprotodie(ctxt, "type.runtime.hchan"))
+func (d *dwctxt2) synthesizechantypes(ctxt *Link, die *dwarf.DWDie) {
+ sudog := walktypedef(d.findprotodie(ctxt, "type.runtime.sudog"))
+ waitq := walktypedef(d.findprotodie(ctxt, "type.runtime.waitq"))
+ hchan := walktypedef(d.findprotodie(ctxt, "type.runtime.hchan"))
if sudog == nil || waitq == nil || hchan == nil {
return
}
@@ -826,130 +952,103 @@
if die.Abbrev != dwarf.DW_ABRV_CHANTYPE {
continue
}
- elemgotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol)
- elemname := elemgotype.Name[5:]
- elemtype := walksymtypedef(ctxt, defgotype(ctxt, elemgotype))
+ elemgotype := loader.Sym(getattr(die, dwarf.DW_AT_type).Data.(dwSym))
+ tname := d.ldr.SymName(elemgotype)
+ elemname := tname[5:]
+ elemtype := d.walksymtypedef(d.defgotype(d.lookupOrDiag(tname)))
// sudog<T>
- dwss := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *dwarf.DWDie) {
- copychildren(ctxt, dws, sudog)
- substitutetype(dws, "elem", defptrto(ctxt, elemtype))
+ dwss := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *dwarf.DWDie) {
+ d.copychildren(ctxt, dws, sudog)
+ d.substitutetype(dws, "elem", d.defptrto(elemtype))
newattr(dws, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(sudogsize), nil)
})
// waitq<T>
- dwws := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *dwarf.DWDie) {
+ dwws := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *dwarf.DWDie) {
- copychildren(ctxt, dww, waitq)
- substitutetype(dww, "first", defptrto(ctxt, dwss))
- substitutetype(dww, "last", defptrto(ctxt, dwss))
+ d.copychildren(ctxt, dww, waitq)
+ d.substitutetype(dww, "first", d.defptrto(dwss))
+ d.substitutetype(dww, "last", d.defptrto(dwss))
newattr(dww, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(waitq, dwarf.DW_AT_byte_size).Value, nil)
})
// hchan<T>
- dwhs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *dwarf.DWDie) {
- copychildren(ctxt, dwh, hchan)
- substitutetype(dwh, "recvq", dwws)
- substitutetype(dwh, "sendq", dwws)
+ dwhs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *dwarf.DWDie) {
+ d.copychildren(ctxt, dwh, hchan)
+ d.substitutetype(dwh, "recvq", dwws)
+ d.substitutetype(dwh, "sendq", dwws)
newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hchan, dwarf.DW_AT_byte_size).Value, nil)
})
- newrefattr(die, dwarf.DW_AT_type, defptrto(ctxt, dwhs))
+ d.newrefattr(die, dwarf.DW_AT_type, d.defptrto(dwhs))
}
}
-func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *sym.Symbol) {
+func (d *dwctxt2) dwarfDefineGlobal(ctxt *Link, symIdx loader.Sym, str string, v int64, gotype loader.Sym) {
// Find a suitable CU DIE to include the global.
// One would think it's as simple as just looking at the unit, but that might
// not have any reachable code. So, we go to the runtime's CU if our unit
// isn't otherwise reachable.
- var unit *sym.CompilationUnit
- if s.Unit != nil {
- unit = s.Unit
- } else {
+ unit := d.ldr.SymUnit(symIdx)
+ if unit == nil {
unit = ctxt.runtimeCU
}
- dv := newdie(ctxt, unit.DWInfo, dwarf.DW_ABRV_VARIABLE, str, int(s.Version))
- newabslocexprattr(dv, v, s)
- if !s.IsFileLocal() {
+ ver := d.ldr.SymVersion(symIdx)
+ dv := d.newdie(unit.DWInfo, dwarf.DW_ABRV_VARIABLE, str, int(ver))
+ d.newabslocexprattr(dv, v, symIdx)
+ if d.ldr.SymVersion(symIdx) < sym.SymVerStatic {
newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
}
- dt := defgotype(ctxt, gotype)
- newrefattr(dv, dwarf.DW_AT_type, dt)
-}
-
-// For use with pass.c::genasmsym
-func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, gotype *sym.Symbol) {
- if strings.HasPrefix(str, "go.string.") {
- return
- }
- if strings.HasPrefix(str, "runtime.gcbits.") {
- return
- }
-
- switch t {
- case DataSym, BSSSym:
- switch s.Type {
- case sym.SDATA, sym.SNOPTRDATA, sym.STYPE, sym.SBSS, sym.SNOPTRBSS, sym.STLSBSS:
- // ok
- case sym.SRODATA:
- if gotype != nil {
- defgotype(ctxt, gotype)
- }
- return
- default:
- return
- }
- if ctxt.LinkMode != LinkExternal && isStaticTemp(s.Name) {
- return
- }
- dwarfDefineGlobal(ctxt, s, str, v, gotype)
-
- case AutoSym, ParamSym, DeletedAutoSym:
- defgotype(ctxt, gotype)
- }
+ dt := d.defgotype(gotype)
+ d.newrefattr(dv, dwarf.DW_AT_type, dt)
}
// createUnitLength creates the initial length field with value v and update
// offset of unit_length if needed.
-func createUnitLength(ctxt *Link, s *sym.Symbol, v uint64) {
- if isDwarf64(ctxt) {
- s.AddUint32(ctxt.Arch, 0xFFFFFFFF)
+func (d *dwctxt2) createUnitLength(su *loader.SymbolBuilder, v uint64) {
+ if isDwarf64(d.linkctxt) {
+ su.AddUint32(d.arch, 0xFFFFFFFF)
}
- addDwarfAddrField(ctxt, s, v)
+ d.addDwarfAddrField(su, v)
}
// addDwarfAddrField adds a DWARF field in DWARF 64bits or 32bits.
-func addDwarfAddrField(ctxt *Link, s *sym.Symbol, v uint64) {
- if isDwarf64(ctxt) {
- s.AddUint(ctxt.Arch, v)
+func (d *dwctxt2) addDwarfAddrField(sb *loader.SymbolBuilder, v uint64) {
+ if isDwarf64(d.linkctxt) {
+ sb.AddUint(d.arch, v)
} else {
- s.AddUint32(ctxt.Arch, uint32(v))
+ sb.AddUint32(d.arch, uint32(v))
}
}
// addDwarfAddrRef adds a DWARF pointer in DWARF 64bits or 32bits.
-func addDwarfAddrRef(ctxt *Link, s *sym.Symbol, t *sym.Symbol) {
- if isDwarf64(ctxt) {
- adddwarfref(ctxt, s, t, 8)
+func (d *dwctxt2) addDwarfAddrRef(sb *loader.SymbolBuilder, t loader.Sym) {
+ if isDwarf64(d.linkctxt) {
+ d.adddwarfref(sb, t, 8)
} else {
- adddwarfref(ctxt, s, t, 4)
+ d.adddwarfref(sb, t, 4)
}
}
// calcCompUnitRanges calculates the PC ranges of the compilation units.
-func calcCompUnitRanges(ctxt *Link) {
+func (d *dwctxt2) calcCompUnitRanges() {
var prevUnit *sym.CompilationUnit
- for _, s := range ctxt.Textp {
- if s.FuncInfo == nil {
+ for _, s := range d.linkctxt.Textp2 {
+ sym := loader.Sym(s)
+
+ fi := d.ldr.FuncInfo(sym)
+ if !fi.Valid() {
continue
}
+
// Skip linker-created functions (ex: runtime.addmoduledata), since they
// don't have DWARF to begin with.
- if s.Unit == nil {
+ unit := d.ldr.SymUnit(sym)
+ if unit == nil {
continue
}
- unit := s.Unit
+
// Update PC ranges.
//
// We don't simply compare the end of the previous
@@ -957,11 +1056,13 @@
// often a little padding between them. Instead, we
// only create boundaries between symbols from
// different units.
+ sval := d.ldr.SymValue(sym)
+ u0val := d.ldr.SymValue(loader.Sym(unit.Textp2[0]))
if prevUnit != unit {
- unit.PCs = append(unit.PCs, dwarf.Range{Start: s.Value - unit.Textp[0].Value})
+ unit.PCs = append(unit.PCs, dwarf.Range{Start: sval - u0val})
prevUnit = unit
}
- unit.PCs[len(unit.PCs)-1].End = s.Value - unit.Textp[0].Value + s.Size
+ unit.PCs[len(unit.PCs)-1].End = sval - u0val + int64(len(d.ldr.Data(sym)))
}
}
@@ -977,24 +1078,6 @@
die.Link = parent.Child
}
-// If the pcln table contains runtime/proc.go, use that to set gdbscript path.
-func finddebugruntimepath(s *sym.Symbol) {
- if gdbscript != "" {
- return
- }
-
- for i := range s.FuncInfo.File {
- f := s.FuncInfo.File[i]
- // We can't use something that may be dead-code
- // eliminated from a binary here. proc.go contains
- // main and the scheduler, so it's not going anywhere.
- if i := strings.Index(f.Name, "runtime/proc.go"); i >= 0 {
- gdbscript = f.Name[:i] + "runtime/runtime-gdb.py"
- break
- }
- }
-}
-
/*
* Generate a sequence of opcodes that is as short as possible.
* See section 6.2.5
@@ -1020,115 +1103,134 @@
return "."
}
-func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) {
- dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
- dsym.Type = sym.SDWARFINFO
- for i := range dsym.R {
- r := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance
- if r.Type == objabi.R_DWARFSECREF && r.Sym.Size == 0 {
- n := nameFromDIESym(r.Sym)
- defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
+func (d *dwctxt2) importInfoSymbol(ctxt *Link, dsym loader.Sym) {
+ d.ldr.SetAttrReachable(dsym, true)
+ d.ldr.SetAttrNotInSymbolTable(dsym, true)
+ if d.ldr.SymType(dsym) != sym.SDWARFINFO {
+ log.Fatalf("error: DWARF info sym %d/%s with incorrect type %s", dsym, d.ldr.SymName(dsym), d.ldr.SymType(dsym).String())
+ }
+ drelocs := d.ldr.Relocs(dsym)
+ rslice := drelocs.ReadSyms(nil)
+ for i := 0; i < len(rslice); i++ {
+ r := &rslice[i]
+ if r.Type != objabi.R_DWARFSECREF {
+ continue
}
+ // If there is an entry for the symbol in our rtmap, then it
+ // means we've processed the type already, and can skip this one.
+ if _, ok := d.rtmap[r.Sym]; ok {
+ // type already generated
+ continue
+ }
+ // FIXME: is there a way we could avoid materializing the
+ // symbol name here?
+ sn := d.ldr.SymName(r.Sym)
+ tn := sn[len(dwarf.InfoPrefix):]
+ ts := d.ldr.Lookup("type."+tn, 0)
+ d.defgotype(ts)
}
}
-func writelines(ctxt *Link, unit *sym.CompilationUnit, ls *sym.Symbol) {
+func expandFile(fname string) string {
+ if strings.HasPrefix(fname, src.FileSymPrefix) {
+ fname = fname[len(src.FileSymPrefix):]
+ }
+ return expandGoroot(fname)
+}
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
+func expandFileSym(l *loader.Loader, fsym loader.Sym) string {
+ return expandFile(l.SymName(fsym))
+}
+
+func (d *dwctxt2) writelines(unit *sym.CompilationUnit, ls loader.Sym) {
+
is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles.
unitstart := int64(-1)
headerstart := int64(-1)
headerend := int64(-1)
- newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls)
+ lsu := d.ldr.MakeSymbolUpdater(ls)
+ newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, lsu.Size(), dwSym(ls))
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
- unitLengthOffset := ls.Size
- createUnitLength(ctxt, ls, 0) // unit_length (*), filled in at end
- unitstart = ls.Size
- ls.AddUint16(ctxt.Arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05
- headerLengthOffset := ls.Size
- addDwarfAddrField(ctxt, ls, 0) // header_length (*), filled in at end
- headerstart = ls.Size
+ unitLengthOffset := lsu.Size()
+ d.createUnitLength(lsu, 0) // unit_length (*), filled in at end
+
+ unitstart = lsu.Size()
+ lsu.AddUint16(d.arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05
+ headerLengthOffset := lsu.Size()
+ d.addDwarfAddrField(lsu, 0) // header_length (*), filled in at end
+ headerstart = lsu.Size()
// cpos == unitstart + 4 + 2 + 4
- ls.AddUint8(1) // minimum_instruction_length
- ls.AddUint8(is_stmt) // default_is_stmt
- ls.AddUint8(LINE_BASE & 0xFF) // line_base
- ls.AddUint8(LINE_RANGE) // line_range
- ls.AddUint8(OPCODE_BASE) // opcode_base
- ls.AddUint8(0) // standard_opcode_lengths[1]
- ls.AddUint8(1) // standard_opcode_lengths[2]
- ls.AddUint8(1) // standard_opcode_lengths[3]
- ls.AddUint8(1) // standard_opcode_lengths[4]
- ls.AddUint8(1) // standard_opcode_lengths[5]
- ls.AddUint8(0) // standard_opcode_lengths[6]
- ls.AddUint8(0) // standard_opcode_lengths[7]
- ls.AddUint8(0) // standard_opcode_lengths[8]
- ls.AddUint8(1) // standard_opcode_lengths[9]
- ls.AddUint8(0) // standard_opcode_lengths[10]
- ls.AddUint8(0) // include_directories (empty)
+ lsu.AddUint8(1) // minimum_instruction_length
+ lsu.AddUint8(is_stmt) // default_is_stmt
+ lsu.AddUint8(LINE_BASE & 0xFF) // line_base
+ lsu.AddUint8(LINE_RANGE) // line_range
+ lsu.AddUint8(OPCODE_BASE) // opcode_base
+ lsu.AddUint8(0) // standard_opcode_lengths[1]
+ lsu.AddUint8(1) // standard_opcode_lengths[2]
+ lsu.AddUint8(1) // standard_opcode_lengths[3]
+ lsu.AddUint8(1) // standard_opcode_lengths[4]
+ lsu.AddUint8(1) // standard_opcode_lengths[5]
+ lsu.AddUint8(0) // standard_opcode_lengths[6]
+ lsu.AddUint8(0) // standard_opcode_lengths[7]
+ lsu.AddUint8(0) // standard_opcode_lengths[8]
+ lsu.AddUint8(1) // standard_opcode_lengths[9]
+ lsu.AddUint8(0) // standard_opcode_lengths[10]
+ lsu.AddUint8(0) // include_directories (empty)
+
+ // Maps loader.Sym for file symbol to expanded filename.
+ expandedFiles := make(map[loader.Sym]string)
// Copy over the file table.
fileNums := make(map[string]int)
+ lsDwsym := dwSym(ls)
for i, name := range unit.DWARFFileTable {
- if len(name) != 0 {
- if strings.HasPrefix(name, src.FileSymPrefix) {
- name = name[len(src.FileSymPrefix):]
- }
- name = expandGoroot(name)
- } else {
- // Can't have empty filenames, and having a unique filename is quite useful
- // for debugging.
+ name := expandFile(name)
+ if len(name) == 0 {
+ // Can't have empty filenames, and having a unique
+ // filename is quite useful for debugging.
name = fmt.Sprintf("<missing>_%d", i)
}
fileNums[name] = i + 1
- dwarfctxt.AddString(ls, name)
- ls.AddUint8(0)
- ls.AddUint8(0)
- ls.AddUint8(0)
- }
- // Grab files for inlined functions.
- // TODO: With difficulty, this could be moved into the compiler.
- for _, s := range unit.Textp {
- dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, true)
- for ri := 0; ri < len(dsym.R); ri++ {
- r := &dsym.R[ri]
- if r.Type != objabi.R_DWARFFILEREF {
- continue
+ d.AddString(lsDwsym, name)
+ lsu.AddUint8(0)
+ lsu.AddUint8(0)
+ lsu.AddUint8(0)
+ if gdbscript == "" {
+ // We can't use something that may be dead-code
+ // eliminated from a binary here. proc.go contains
+ // main and the scheduler, so it's not going anywhere.
+ if i := strings.Index(name, "runtime/proc.go"); i >= 0 {
+ k := strings.Index(name, "runtime/proc.go")
+ gdbscript = name[:k] + "runtime/runtime-gdb.py"
}
- name := r.Sym.Name
- if _, ok := fileNums[name]; ok {
- continue
- }
- fileNums[name] = len(fileNums) + 1
- dwarfctxt.AddString(ls, name)
- ls.AddUint8(0)
- ls.AddUint8(0)
- ls.AddUint8(0)
}
}
// 4 zeros: the string termination + 3 fields.
- ls.AddUint8(0)
+ lsu.AddUint8(0)
// terminate file_names.
- headerend = ls.Size
+ headerend = lsu.Size()
// Output the state machine for each function remaining.
var lastAddr int64
- for _, s := range unit.Textp {
- finddebugruntimepath(s)
+ rslice := []loader.Reloc{}
+ for _, s := range unit.Textp2 {
+ fnSym := loader.Sym(s)
// Set the PC.
- ls.AddUint8(0)
- dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize))
- ls.AddUint8(dwarf.DW_LNE_set_address)
- addr := ls.AddAddr(ctxt.Arch, s)
+ lsu.AddUint8(0)
+ dwarf.Uleb128put(d, lsDwsym, 1+int64(d.arch.PtrSize))
+ lsu.AddUint8(dwarf.DW_LNE_set_address)
+ addr := lsu.AddAddrPlus(d.arch, fnSym, 0)
// Make sure the units are sorted.
if addr < lastAddr {
- Errorf(s, "address wasn't increasing %x < %x", addr, lastAddr)
+ d.linkctxt.Errorf(fnSym, "address wasn't increasing %x < %x",
+ addr, lastAddr)
}
lastAddr = addr
@@ -1138,25 +1240,25 @@
// together rather then the append() below. This would allow us to have
// the compiler emit the DW_LNE_set_address and a rope data structure
// to concat them all together in the output.
- lines := dwarfFuncSym(ctxt, s, dwarf.DebugLinesPrefix, false)
- if lines != nil {
- ls.P = append(ls.P, lines.P...)
+ _, _, _, lines := d.ldr.GetFuncDwarfAuxSyms(fnSym)
+ if lines != 0 {
+ lsu.AddBytes(d.ldr.Data(lines))
}
}
- ls.AddUint8(0) // start extended opcode
- dwarf.Uleb128put(dwarfctxt, ls, 1)
- ls.AddUint8(dwarf.DW_LNE_end_sequence)
+ lsu.AddUint8(0) // start extended opcode
+ dwarf.Uleb128put(d, lsDwsym, 1)
+ lsu.AddUint8(dwarf.DW_LNE_end_sequence)
- if ctxt.HeadType == objabi.Haix {
- saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(ls.Size-unitLengthOffset))
+ if d.linkctxt.HeadType == objabi.Haix {
+ saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(lsu.Size()-unitLengthOffset))
}
- if isDwarf64(ctxt) {
- ls.SetUint(ctxt.Arch, unitLengthOffset+4, uint64(ls.Size-unitstart)) // +4 because of 0xFFFFFFFF
- ls.SetUint(ctxt.Arch, headerLengthOffset, uint64(headerend-headerstart))
+ if isDwarf64(d.linkctxt) {
+ lsu.SetUint(d.arch, unitLengthOffset+4, uint64(lsu.Size()-unitstart)) // +4 because of 0xFFFFFFFF
+ lsu.SetUint(d.arch, headerLengthOffset, uint64(headerend-headerstart))
} else {
- ls.SetUint32(ctxt.Arch, unitLengthOffset, uint32(ls.Size-unitstart))
- ls.SetUint32(ctxt.Arch, headerLengthOffset, uint32(headerend-headerstart))
+ lsu.SetUint32(d.arch, unitLengthOffset, uint32(lsu.Size()-unitstart))
+ lsu.SetUint32(d.arch, headerLengthOffset, uint32(headerend-headerstart))
}
// Process any R_DWARFFILEREF relocations, since we now know the
@@ -1166,56 +1268,80 @@
// DIE flavors (ex: variables) then those DIEs would need to
// be included below.
missing := make(map[int]interface{})
- s := unit.Textp[0]
- for _, f := range unit.FuncDIEs {
- for ri := range f.R {
- r := &f.R[ri]
+ for _, f := range unit.FuncDIEs2 {
+ fnSym := loader.Sym(f)
+
+ // Create a symbol updater prior to looking at the relocations
+ // on the DWARF subprogram DIE symbol. We need to do this here
+ // so that any modifications to the reloc slice will get
+ // stored in loader payload for the symbol (as opposed to a
+ // temporary slice of relocs read from the object file). Copy
+ // back relocations with updated addends.
+ fnu := d.ldr.MakeSymbolUpdater(fnSym)
+
+ relocs := d.ldr.Relocs(fnSym)
+ rslice = relocs.ReadAll(rslice)
+
+ for ri := range rslice {
+ r := &rslice[ri]
if r.Type != objabi.R_DWARFFILEREF {
continue
}
- idx, ok := fileNums[r.Sym.Name]
+
+ fname, ok := expandedFiles[r.Sym]
+ if !ok {
+ fname = expandFileSym(d.ldr, r.Sym)
+ expandedFiles[r.Sym] = fname
+ }
+
+ idx, ok := fileNums[fname]
if ok {
if int(int32(idx)) != idx {
- Errorf(f, "bad R_DWARFFILEREF relocation: file index overflow")
+ d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation: file index overflow")
}
- if r.Siz != 4 {
- Errorf(f, "bad R_DWARFFILEREF relocation: has size %d, expected 4", r.Siz)
- }
- if r.Off < 0 || r.Off+4 > int32(len(f.P)) {
- Errorf(f, "bad R_DWARFFILEREF relocation offset %d + 4 would write past length %d", r.Off, len(s.P))
- continue
+ if r.Size != 4 {
+ d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation: has size %d, expected 4", r.Size)
}
if r.Add != 0 {
- Errorf(f, "bad R_DWARFFILEREF relocation: addend not zero")
+ d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation: addend not zero")
}
- r.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
+ if r.Off < 0 || r.Off+4 > int32(len(fnu.Data())) {
+ d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation offset %d + 4 would write past length %d", r.Off, len(fnu.Data()))
+ continue
+ }
+
+ d.ldr.SetAttrReachable(r.Sym, true)
+ d.ldr.SetAttrNotInSymbolTable(r.Sym, true)
r.Add = int64(idx) // record the index in r.Add, we'll apply it in the reloc phase.
} else {
- _, found := missing[int(r.Sym.Value)]
+ sv := d.ldr.SymValue(r.Sym)
+ _, found := missing[int(sv)]
if !found {
- Errorf(f, "R_DWARFFILEREF relocation file missing: %v idx %d", r.Sym, r.Sym.Value)
- missing[int(r.Sym.Value)] = nil
+ d.linkctxt.Errorf(fnSym, "R_DWARFFILEREF relocation file missing: %s idx %d symVal %d", d.ldr.SymName(r.Sym), r.Sym, sv)
+ missing[int(sv)] = nil
}
}
}
+ fnu.WriteRelocs(rslice)
}
}
// writepcranges generates the DW_AT_ranges table for compilation unit cu.
-func writepcranges(ctxt *Link, unit *sym.CompilationUnit, base *sym.Symbol, pcs []dwarf.Range, ranges *sym.Symbol) {
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
+func (d *dwctxt2) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs []dwarf.Range, ranges loader.Sym) {
- unitLengthOffset := ranges.Size
+ rsu := d.ldr.MakeSymbolUpdater(ranges)
+ rDwSym := dwSym(ranges)
+
+ unitLengthOffset := rsu.Size()
// Create PC ranges for this CU.
- newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, ranges.Size, ranges)
- newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, base.Value, base)
- dwarf.PutBasedRanges(dwarfctxt, ranges, pcs)
+ newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, rsu.Size(), rDwSym)
+ newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, 0, dwSym(base))
+ dwarf.PutBasedRanges(d, rDwSym, pcs)
- if ctxt.HeadType == objabi.Haix {
- addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(ranges.Size-unitLengthOffset))
+ if d.linkctxt.HeadType == objabi.Haix {
+ addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rsu.Size()-unitLengthOffset))
}
-
}
/*
@@ -1246,84 +1372,91 @@
return b
}
-func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
- fs := ctxt.Syms.Lookup(".debug_frame", 0)
- fs.Type = sym.SDWARFSECT
+func (d *dwctxt2) writeframes(syms []loader.Sym) []loader.Sym {
+ fs := d.ldr.AddExtSym(".debug_frame", 0)
+ fsd := dwSym(fs)
+ fsu := d.ldr.MakeSymbolUpdater(fs)
+ fsu.SetType(sym.SDWARFSECT)
syms = append(syms, fs)
+ isdw64 := isDwarf64(d.linkctxt)
+ haslr := haslinkregister(d.linkctxt)
// Length field is 4 bytes on Dwarf32 and 12 bytes on Dwarf64
lengthFieldSize := int64(4)
- if isDwarf64(ctxt) {
+ if isdw64 {
lengthFieldSize += 8
}
// Emit the CIE, Section 6.4.1
cieReserve := uint32(16)
- if haslinkregister(ctxt) {
+ if haslr {
cieReserve = 32
}
- if isDwarf64(ctxt) {
+ if isdw64 {
cieReserve += 4 // 4 bytes added for cid
}
- createUnitLength(ctxt, fs, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize
- addDwarfAddrField(ctxt, fs, ^uint64(0)) // cid
- fs.AddUint8(3) // dwarf version (appendix F)
- fs.AddUint8(0) // augmentation ""
- dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor
- dwarf.Sleb128put(dwarfctxt, fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr)) // return_address_register
+ d.createUnitLength(fsu, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize
+ d.addDwarfAddrField(fsu, ^uint64(0)) // cid
+ fsu.AddUint8(3) // dwarf version (appendix F)
+ fsu.AddUint8(0) // augmentation ""
+ dwarf.Uleb128put(d, fsd, 1) // code_alignment_factor
+ dwarf.Sleb128put(d, fsd, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor
+ dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfreglr)) // return_address_register
- fs.AddUint8(dwarf.DW_CFA_def_cfa) // Set the current frame address..
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
- if haslinkregister(ctxt) {
- dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...plus a 0 offset.
+ fsu.AddUint8(dwarf.DW_CFA_def_cfa) // Set the current frame address..
+ dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
+ if haslr {
+ dwarf.Uleb128put(d, fsd, int64(0)) // ...plus a 0 offset.
- fs.AddUint8(dwarf.DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr))
+ fsu.AddUint8(dwarf.DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
+ dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfreglr))
- fs.AddUint8(dwarf.DW_CFA_val_offset) // The previous value...
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfregsp)) // ...of the platform's SP register...
- dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...is CFA+0.
+ fsu.AddUint8(dwarf.DW_CFA_val_offset) // The previous value...
+ dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfregsp)) // ...of the platform's SP register...
+ dwarf.Uleb128put(d, fsd, int64(0)) // ...is CFA+0.
} else {
- dwarf.Uleb128put(dwarfctxt, fs, int64(ctxt.Arch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
+ dwarf.Uleb128put(d, fsd, int64(d.arch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
- fs.AddUint8(dwarf.DW_CFA_offset_extended) // The previous value...
- dwarf.Uleb128put(dwarfctxt, fs, int64(thearch.Dwarfreglr)) // ...of the return address...
- dwarf.Uleb128put(dwarfctxt, fs, int64(-ctxt.Arch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
+ fsu.AddUint8(dwarf.DW_CFA_offset_extended) // The previous value...
+ dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfreglr)) // ...of the return address...
+ dwarf.Uleb128put(d, fsd, int64(-d.arch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
}
- pad := int64(cieReserve) + lengthFieldSize - fs.Size
+ pad := int64(cieReserve) + lengthFieldSize - int64(len(d.ldr.Data(fs)))
if pad < 0 {
Exitf("dwarf: cieReserve too small by %d bytes.", -pad)
}
- fs.AddBytes(zeros[:pad])
+ fsu.AddBytes(zeros[:pad])
var deltaBuf []byte
- pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
- for _, s := range ctxt.Textp {
- if s.FuncInfo == nil {
+ pcsp := obj.NewPCIter(uint32(d.arch.MinLC))
+ for _, s := range d.linkctxt.Textp2 {
+ fn := loader.Sym(s)
+ fi := d.ldr.FuncInfo(fn)
+ if !fi.Valid() {
continue
}
+ fpcsp := fi.Pcsp()
// Emit a FDE, Section 6.4.1.
// First build the section contents into a byte buffer.
deltaBuf = deltaBuf[:0]
- if haslinkregister(ctxt) && s.Attr.TopFrame() {
+ if haslr && d.ldr.AttrTopFrame(fn) {
// Mark the link register as having an undefined value.
// This stops call stack unwinders progressing any further.
// TODO: similar mark on non-LR architectures.
deltaBuf = append(deltaBuf, dwarf.DW_CFA_undefined)
deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
}
- for pcsp.Init(s.FuncInfo.Pcsp.P); !pcsp.Done; pcsp.Next() {
+
+ for pcsp.Init(fpcsp); !pcsp.Done; pcsp.Next() {
nextpc := pcsp.NextPC
// pciterinit goes up to the end of the function,
// but DWARF expects us to stop just before the end.
- if int64(nextpc) == s.Size {
+ if int64(nextpc) == int64(len(d.ldr.Data(fn))) {
nextpc--
if nextpc < pcsp.PC {
continue
@@ -1331,12 +1464,12 @@
}
spdelta := int64(pcsp.Value)
- if !haslinkregister(ctxt) {
+ if !haslr {
// Return address has been pushed onto stack.
- spdelta += int64(ctxt.Arch.PtrSize)
+ spdelta += int64(d.arch.PtrSize)
}
- if haslinkregister(ctxt) && !s.Attr.TopFrame() {
+ if haslr && !d.ldr.AttrTopFrame(fn) {
// TODO(bryanpkc): This is imprecise. In general, the instruction
// that stores the return address to the stack frame is not the
// same one that allocates the frame.
@@ -1354,9 +1487,9 @@
}
}
- deltaBuf = appendPCDeltaCFA(ctxt.Arch, deltaBuf, int64(nextpc)-int64(pcsp.PC), spdelta)
+ deltaBuf = appendPCDeltaCFA(d.arch, deltaBuf, int64(nextpc)-int64(pcsp.PC), spdelta)
}
- pad := int(Rnd(int64(len(deltaBuf)), int64(ctxt.Arch.PtrSize))) - len(deltaBuf)
+ pad := int(Rnd(int64(len(deltaBuf)), int64(d.arch.PtrSize))) - len(deltaBuf)
deltaBuf = append(deltaBuf, zeros[:pad]...)
// Emit the FDE header, Section 6.4.1.
@@ -1365,48 +1498,61 @@
// ptrsize: initial location
// ptrsize: address range
- fdeLength := uint64(4 + 2*ctxt.Arch.PtrSize + len(deltaBuf))
- if isDwarf64(ctxt) {
+ fdeLength := uint64(4 + 2*d.arch.PtrSize + len(deltaBuf))
+ if isdw64 {
fdeLength += 4 // 4 bytes added for CIE pointer
}
- createUnitLength(ctxt, fs, fdeLength)
+ d.createUnitLength(fsu, fdeLength)
- if ctxt.LinkMode == LinkExternal {
- addDwarfAddrRef(ctxt, fs, fs)
+ if d.linkctxt.LinkMode == LinkExternal {
+ d.addDwarfAddrRef(fsu, fs)
} else {
- addDwarfAddrField(ctxt, fs, 0) // CIE offset
+ d.addDwarfAddrField(fsu, 0) // CIE offset
}
- fs.AddAddr(ctxt.Arch, s)
- fs.AddUintXX(ctxt.Arch, uint64(s.Size), ctxt.Arch.PtrSize) // address range
- fs.AddBytes(deltaBuf)
+ fsu.AddAddrPlus(d.arch, s, 0)
+ fsu.AddUintXX(d.arch, uint64(len(d.ldr.Data(fn))), d.arch.PtrSize) // address range
+ fsu.AddBytes(deltaBuf)
- if ctxt.HeadType == objabi.Haix {
- addDwsectCUSize(".debug_frame", s.File, fdeLength+uint64(lengthFieldSize))
+ if d.linkctxt.HeadType == objabi.Haix {
+ addDwsectCUSize(".debug_frame", d.ldr.SymFile(fn), fdeLength+uint64(lengthFieldSize))
}
}
+
return syms
}
/*
* Walk DWarfDebugInfoEntries, and emit .debug_info
*/
+
const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
)
-func writeinfo(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit, abbrevsym *sym.Symbol, pubNames, pubTypes *pubWriter) []*sym.Symbol {
- infosec := ctxt.Syms.Lookup(".debug_info", 0)
- infosec.Type = sym.SDWARFINFO
- infosec.Attr |= sym.AttrReachable
- syms = append(syms, infosec)
+// appendSyms appends the syms from 'src' into 'syms' and returns the
+// result. This can go away once we do away with sym.LoaderSym
+// entirely.
+func appendSyms(syms []loader.Sym, src []sym.LoaderSym) []loader.Sym {
+ for _, s := range src {
+ syms = append(syms, loader.Sym(s))
+ }
+ return syms
+}
- var dwarfctxt dwarf.Context = dwctxt{ctxt}
+func (d *dwctxt2) writeinfo(syms []loader.Sym, units []*sym.CompilationUnit, abbrevsym loader.Sym, pubNames, pubTypes *pubWriter2) []loader.Sym {
+
+ infosec := d.ldr.AddExtSym(".debug_info", 0)
+ disu := d.ldr.MakeSymbolUpdater(infosec)
+ disu.SetType(sym.SDWARFINFO)
+ d.ldr.SetAttrReachable(infosec, true)
+ syms = append(syms, infosec)
for _, u := range units {
compunit := u.DWInfo
- s := dtolsym(compunit.Sym)
+ s := d.dtolsym(compunit.Sym)
+ su := d.ldr.MakeSymbolUpdater(s)
- if len(u.Textp) == 0 && u.DWInfo.Child == nil {
+ if len(u.Textp2) == 0 && u.DWInfo.Child == nil {
continue
}
@@ -1416,59 +1562,62 @@
// Write .debug_info Compilation Unit Header (sec 7.5.1)
// Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above.
- createUnitLength(ctxt, s, 0) // unit_length (*), will be filled in later.
- s.AddUint16(ctxt.Arch, 4) // dwarf version (appendix F)
+ d.createUnitLength(su, 0) // unit_length (*), will be filled in later.
+ su.AddUint16(d.arch, 4) // dwarf version (appendix F)
// debug_abbrev_offset (*)
- addDwarfAddrRef(ctxt, s, abbrevsym)
+ d.addDwarfAddrRef(su, abbrevsym)
- s.AddUint8(uint8(ctxt.Arch.PtrSize)) // address_size
+ su.AddUint8(uint8(d.arch.PtrSize)) // address_size
- dwarf.Uleb128put(dwarfctxt, s, int64(compunit.Abbrev))
- dwarf.PutAttrs(dwarfctxt, s, compunit.Abbrev, compunit.Attr)
+ ds := dwSym(s)
+ dwarf.Uleb128put(d, ds, int64(compunit.Abbrev))
+ dwarf.PutAttrs(d, ds, compunit.Abbrev, compunit.Attr)
- cu := []*sym.Symbol{s}
- cu = append(cu, u.AbsFnDIEs...)
- cu = append(cu, u.FuncDIEs...)
- if u.Consts != nil {
- cu = append(cu, u.Consts)
+ cu := []loader.Sym{s}
+ cu = appendSyms(cu, u.AbsFnDIEs2)
+ cu = appendSyms(cu, u.FuncDIEs2)
+ if u.Consts2 != 0 {
+ cu = append(cu, loader.Sym(u.Consts2))
}
var cusize int64
for _, child := range cu {
- cusize += child.Size
+ cusize += int64(len(d.ldr.Data(child)))
}
for die := compunit.Child; die != nil; die = die.Link {
l := len(cu)
- lastSymSz := cu[l-1].Size
- cu = putdie(ctxt, dwarfctxt, cu, die)
+ lastSymSz := int64(len(d.ldr.Data(cu[l-1])))
+ cu = d.putdie(cu, die)
if ispubname(die) {
pubNames.add(die, cusize)
}
if ispubtype(die) {
pubTypes.add(die, cusize)
}
- if lastSymSz != cu[l-1].Size {
+ if lastSymSz != int64(len(d.ldr.Data(cu[l-1]))) {
// putdie will sometimes append directly to the last symbol of the list
- cusize = cusize - lastSymSz + cu[l-1].Size
+ cusize = cusize - lastSymSz + int64(len(d.ldr.Data(cu[l-1])))
}
for _, child := range cu[l:] {
- cusize += child.Size
+ cusize += int64(len(d.ldr.Data(child)))
}
}
- cu[len(cu)-1].AddUint8(0) // closes compilation unit DIE
+
+ culu := d.ldr.MakeSymbolUpdater(cu[len(cu)-1])
+ culu.AddUint8(0) // closes compilation unit DIE
cusize++
// Save size for AIX symbol table.
- if ctxt.HeadType == objabi.Haix {
- saveDwsectCUSize(".debug_info", getPkgFromCUSym(s), uint64(cusize))
+ if d.linkctxt.HeadType == objabi.Haix {
+ saveDwsectCUSize(".debug_info", d.getPkgFromCUSym(s), uint64(cusize))
}
- if isDwarf64(ctxt) {
- cusize -= 12 // exclude the length field.
- s.SetUint(ctxt.Arch, 4, uint64(cusize)) // 4 because of 0XFFFFFFFF
+ if isDwarf64(d.linkctxt) {
+ cusize -= 12 // exclude the length field.
+ su.SetUint(d.arch, 4, uint64(cusize)) // 4 because of 0XFFFFFFFF
} else {
cusize -= 4 // exclude the length field.
- s.SetUint32(ctxt.Arch, 0, uint32(cusize))
+ su.SetUint32(d.arch, 0, uint32(cusize))
}
pubNames.endCompUnit(compunit, uint32(cusize)+4)
pubTypes.endCompUnit(compunit, uint32(cusize)+4)
@@ -1481,6 +1630,61 @@
* Emit .debug_pubnames/_types. _info must have been written before,
* because we need die->offs and infoo/infosize;
*/
+
+type pubWriter2 struct {
+ d *dwctxt2
+ s loader.Sym
+ su *loader.SymbolBuilder
+ sname string
+
+ sectionstart int64
+ culengthOff int64
+}
+
+func newPubWriter2(d *dwctxt2, sname string) *pubWriter2 {
+ s := d.ldr.AddExtSym(sname, 0)
+ u := d.ldr.MakeSymbolUpdater(s)
+ u.SetType(sym.SDWARFSECT)
+ return &pubWriter2{d: d, s: s, su: u, sname: sname}
+}
+
+func (pw *pubWriter2) beginCompUnit(compunit *dwarf.DWDie) {
+ pw.sectionstart = pw.su.Size()
+
+ // Write .debug_pubnames/types Header (sec 6.1.1)
+ pw.d.createUnitLength(pw.su, 0) // unit_length (*), will be filled in later.
+ pw.su.AddUint16(pw.d.arch, 2) // dwarf version (appendix F)
+ pw.d.addDwarfAddrRef(pw.su, pw.d.dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
+ pw.culengthOff = pw.su.Size()
+ pw.d.addDwarfAddrField(pw.su, uint64(0)) // debug_info_length, will be filled in later.
+}
+
+func (pw *pubWriter2) add(die *dwarf.DWDie, offset int64) {
+ dwa := getattr(die, dwarf.DW_AT_name)
+ name := dwa.Data.(string)
+ if pw.d.dtolsym(die.Sym) == 0 {
+ fmt.Println("Missing sym for ", name)
+ }
+ pw.d.addDwarfAddrField(pw.su, uint64(offset))
+ pw.su.Addstring(name)
+}
+
+func (pw *pubWriter2) endCompUnit(compunit *dwarf.DWDie, culength uint32) {
+ pw.d.addDwarfAddrField(pw.su, 0) // Null offset
+
+ // On AIX, save the current size of this compilation unit.
+ if pw.d.linkctxt.HeadType == objabi.Haix {
+ saveDwsectCUSize(pw.sname, pw.d.getPkgFromCUSym(pw.d.dtolsym(compunit.Sym)), uint64(pw.su.Size()-pw.sectionstart))
+ }
+ if isDwarf64(pw.d.linkctxt) {
+ pw.su.SetUint(pw.d.arch, pw.sectionstart+4, uint64(pw.su.Size()-pw.sectionstart)-12) // exclude the length field.
+ pw.su.SetUint(pw.d.arch, pw.culengthOff, uint64(culength))
+ } else {
+ pw.su.SetUint32(pw.d.arch, pw.sectionstart, uint32(pw.su.Size()-pw.sectionstart)-4) // exclude the length field.
+ pw.su.SetUint32(pw.d.arch, pw.culengthOff, culength)
+ }
+}
+
func ispubname(die *dwarf.DWDie) bool {
switch die.Abbrev {
case dwarf.DW_ABRV_FUNCTION, dwarf.DW_ABRV_VARIABLE:
@@ -1495,65 +1699,12 @@
return die.Abbrev >= dwarf.DW_ABRV_NULLTYPE
}
-type pubWriter struct {
- ctxt *Link
- s *sym.Symbol
- sname string
-
- sectionstart int64
- culengthOff int64
-}
-
-func newPubWriter(ctxt *Link, sname string) *pubWriter {
- s := ctxt.Syms.Lookup(sname, 0)
- s.Type = sym.SDWARFSECT
- return &pubWriter{ctxt: ctxt, s: s, sname: sname}
-}
-
-func (pw *pubWriter) beginCompUnit(compunit *dwarf.DWDie) {
- pw.sectionstart = pw.s.Size
-
- // Write .debug_pubnames/types Header (sec 6.1.1)
- createUnitLength(pw.ctxt, pw.s, 0) // unit_length (*), will be filled in later.
- pw.s.AddUint16(pw.ctxt.Arch, 2) // dwarf version (appendix F)
- addDwarfAddrRef(pw.ctxt, pw.s, dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
- pw.culengthOff = pw.s.Size
- addDwarfAddrField(pw.ctxt, pw.s, uint64(0)) // debug_info_length, will be filled in later.
-
-}
-
-func (pw *pubWriter) add(die *dwarf.DWDie, offset int64) {
- dwa := getattr(die, dwarf.DW_AT_name)
- name := dwa.Data.(string)
- if die.Sym == nil {
- fmt.Println("Missing sym for ", name)
- }
- addDwarfAddrField(pw.ctxt, pw.s, uint64(offset))
- Addstring(pw.s, name)
-}
-
-func (pw *pubWriter) endCompUnit(compunit *dwarf.DWDie, culength uint32) {
- addDwarfAddrField(pw.ctxt, pw.s, 0) // Null offset
-
- // On AIX, save the current size of this compilation unit.
- if pw.ctxt.HeadType == objabi.Haix {
- saveDwsectCUSize(pw.sname, getPkgFromCUSym(dtolsym(compunit.Sym)), uint64(pw.s.Size-pw.sectionstart))
- }
- if isDwarf64(pw.ctxt) {
- pw.s.SetUint(pw.ctxt.Arch, pw.sectionstart+4, uint64(pw.s.Size-pw.sectionstart)-12) // exclude the length field.
- pw.s.SetUint(pw.ctxt.Arch, pw.culengthOff, uint64(culength))
- } else {
- pw.s.SetUint32(pw.ctxt.Arch, pw.sectionstart, uint32(pw.s.Size-pw.sectionstart)-4) // exclude the length field.
- pw.s.SetUint32(pw.ctxt.Arch, pw.culengthOff, culength)
- }
-}
-
-func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol {
+func (d *dwctxt2) writegdbscript(syms []loader.Sym) []loader.Sym {
// TODO (aix): make it available
- if ctxt.HeadType == objabi.Haix {
+ if d.linkctxt.HeadType == objabi.Haix {
return syms
}
- if ctxt.LinkMode == LinkExternal && ctxt.HeadType == objabi.Hwindows && ctxt.BuildMode == BuildModeCArchive {
+ if d.linkctxt.LinkMode == LinkExternal && d.linkctxt.HeadType == objabi.Hwindows && d.linkctxt.BuildMode == BuildModeCArchive {
// gcc on Windows places .debug_gdb_scripts in the wrong location, which
// causes the program not to run. See https://golang.org/issue/20183
// Non c-archives can avoid this issue via a linker script
@@ -1564,16 +1715,22 @@
}
if gdbscript != "" {
- s := ctxt.Syms.Lookup(".debug_gdb_scripts", 0)
- s.Type = sym.SDWARFSECT
- syms = append(syms, s)
- s.AddUint8(1) // magic 1 byte?
- Addstring(s, gdbscript)
+ gs := d.ldr.AddExtSym(".debug_gdb_scripts", 0)
+ u := d.ldr.MakeSymbolUpdater(gs)
+ u.SetType(sym.SDWARFSECT)
+
+ syms = append(syms, gs)
+ u.AddUint8(1) // magic 1 byte?
+ u.Addstring(gdbscript)
}
return syms
+
}
+// FIXME: might be worth looking replacing this map with a function
+// that switches based on symbol instead.
+
var prototypedies map[string]*dwarf.DWDie
func dwarfEnabled(ctxt *Link) bool {
@@ -1606,11 +1763,30 @@
return true
}
+// mkBuiltinType populates the dwctxt2 sym lookup maps for the
+// newly created builtin type DIE 'typeDie'.
+func (d *dwctxt2) mkBuiltinType(ctxt *Link, abrv int, tname string) *dwarf.DWDie {
+ // create type DIE
+ die := d.newdie(&dwtypes, abrv, tname, 0)
+
+ // Look up type symbol.
+ gotype := d.lookupOrDiag("type." + tname)
+
+ // Map from die sym to type sym
+ ds := loader.Sym(die.Sym.(dwSym))
+ d.rtmap[ds] = gotype
+
+ // Map from type to def sym
+ d.tdmap[gotype] = ds
+
+ return die
+}
+
// dwarfGenerateDebugInfo generated debug info entries for all types,
// variables and functions in the program.
// Along with dwarfGenerateDebugSyms they are the two main entry points into
// dwarf generation: dwarfGenerateDebugInfo does all the work that should be
-// done before symbol names are mangled while dwarfgeneratedebugsyms does
+// done before symbol names are mangled while dwarfGenerateDebugSyms does
// all the work that can only be done after addresses have been assigned to
// text symbols.
func dwarfGenerateDebugInfo(ctxt *Link) {
@@ -1618,25 +1794,29 @@
return
}
+ d := newdwctxt2(ctxt, true)
+
if ctxt.HeadType == objabi.Haix {
// Initial map used to store package size for each DWARF section.
dwsectCUSize = make(map[string]uint64)
}
- // Forctxt.Diagnostic messages.
+ // For ctxt.Diagnostic messages.
newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
- // Some types that must exist to define other ones.
- newdie(ctxt, &dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>", 0)
+ // Unspecified type. There are no references to this in the symbol table.
+ d.newdie(&dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>", 0)
- newdie(ctxt, &dwtypes, dwarf.DW_ABRV_NULLTYPE, "void", 0)
- newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer", 0)
-
- die := newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BASETYPE, "uintptr", 0) // needed for array size
+ // Some types that must exist to define other ones (uintptr in particular
+ // is needed for array size)
+ d.mkBuiltinType(ctxt, dwarf.DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer")
+ die := d.mkBuiltinType(ctxt, dwarf.DW_ABRV_BASETYPE, "uintptr")
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
- newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(ctxt.Arch.PtrSize), 0)
+ newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(d.arch.PtrSize), 0)
newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, objabi.KindUintptr, 0)
- newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_ADDRESS, 0, lookupOrDiag(ctxt, "type.uintptr"))
+ newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_ADDRESS, 0, dwSym(d.lookupOrDiag("type.uintptr")))
+
+ d.uintptrInfoSym = d.mustFind("uintptr")
// Prototypes needed for type synthesis.
prototypedies = map[string]*dwarf.DWDie{
@@ -1662,23 +1842,24 @@
"type.runtime.interfacetype",
"type.runtime.itab",
"type.runtime.imethod"} {
- defgotype(ctxt, lookupOrDiag(ctxt, typ))
+ d.defgotype(d.lookupOrDiag(typ))
}
// fake root DIE for compile unit DIEs
var dwroot dwarf.DWDie
flagVariants := make(map[string]bool)
+ var relocs []loader.Reloc
for _, lib := range ctxt.Library {
- consts := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+lib.Pkg, 0)
+
+ consts := d.ldr.Lookup(dwarf.ConstInfoPrefix+lib.Pkg, 0)
for _, unit := range lib.Units {
// We drop the constants into the first CU.
- if consts != nil {
- importInfoSymbol(ctxt, consts)
- unit.Consts = consts
- consts = nil
+ if consts != 0 {
+ unit.Consts2 = sym.LoaderSym(consts)
+ d.importInfoSymbol(ctxt, consts)
+ consts = 0
}
-
ctxt.compUnits = append(ctxt.compUnits, unit)
// We need at least one runtime unit.
@@ -1686,7 +1867,7 @@
ctxt.runtimeCU = unit
}
- unit.DWInfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, unit.Lib.Pkg, 0)
+ unit.DWInfo = d.newdie(&dwroot, dwarf.DW_ABRV_COMPUNIT, unit.Lib.Pkg, 0)
newattr(unit.DWInfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(dwarf.DW_LANG_Go), 0)
// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
compDir := getCompilationDir()
@@ -1694,17 +1875,21 @@
// the linker directory. If we move CU construction into the
// compiler, this should happen naturally.
newattr(unit.DWInfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir)
- producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+unit.Lib.Pkg, 0)
+
+ var peData []byte
+ if producerExtra := d.ldr.Lookup(dwarf.CUInfoPrefix+"producer."+unit.Lib.Pkg, 0); producerExtra != 0 {
+ peData = d.ldr.Data(producerExtra)
+ }
producer := "Go cmd/compile " + objabi.Version
- if len(producerExtra.P) > 0 {
+ if len(peData) > 0 {
// We put a semicolon before the flags to clearly
// separate them from the version, which can be long
// and have lots of weird things in it in development
// versions. We promise not to put a semicolon in the
// version, so it should be safe for readers to scan
// forward to the semicolon.
- producer += "; " + string(producerExtra.P)
- flagVariants[string(producerExtra.P)] = true
+ producer += "; " + string(peData)
+ flagVariants[string(peData)] = true
} else {
flagVariants[""] = true
}
@@ -1712,12 +1897,13 @@
newattr(unit.DWInfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer)
var pkgname string
- if s := ctxt.Syms.ROLookup(dwarf.CUInfoPrefix+"packagename."+unit.Lib.Pkg, 0); s != nil {
- pkgname = string(s.P)
+ if pnSymIdx := d.ldr.Lookup(dwarf.CUInfoPrefix+"packagename."+unit.Lib.Pkg, 0); pnSymIdx != 0 {
+ pnsData := d.ldr.Data(pnSymIdx)
+ pkgname = string(pnsData)
}
newattr(unit.DWInfo, dwarf.DW_AT_go_package_name, dwarf.DW_CLS_STRING, int64(len(pkgname)), pkgname)
- if len(unit.Textp) == 0 {
+ if len(unit.Textp2) == 0 {
unit.DWInfo.Abbrev = dwarf.DW_ABRV_COMPUNIT_TEXTLESS
}
@@ -1725,36 +1911,48 @@
// referenced types, create the file table for debug_line, find all
// referenced abstract functions.
// Collect all debug_range symbols in unit.rangeSyms
- for _, s := range unit.Textp { // textp has been dead-code-eliminated already.
- dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, false)
- dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
- dsym.Type = sym.SDWARFINFO
- unit.FuncDIEs = append(unit.FuncDIEs, dsym)
+ for _, s := range unit.Textp2 { // textp2 has been dead-code-eliminated already.
+ fnSym := loader.Sym(s)
+ infosym, _, rangesym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
+ d.ldr.SetAttrNotInSymbolTable(infosym, true)
+ d.ldr.SetAttrReachable(infosym, true)
- rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false)
- if rangeSym != nil && rangeSym.Size > 0 {
- rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
- rangeSym.Type = sym.SDWARFRANGE
+ unit.FuncDIEs2 = append(unit.FuncDIEs2, sym.LoaderSym(infosym))
+ if rangesym != 0 {
+ rs := len(d.ldr.Data(rangesym))
+ d.ldr.SetAttrNotInSymbolTable(rangesym, true)
+ d.ldr.SetAttrReachable(rangesym, true)
if ctxt.HeadType == objabi.Haix {
- addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rangeSym.Size))
+ addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rs))
}
- unit.RangeSyms = append(unit.RangeSyms, rangeSym)
+ unit.RangeSyms2 = append(unit.RangeSyms2, sym.LoaderSym(rangesym))
}
- for ri := 0; ri < len(dsym.R); ri++ {
- r := &dsym.R[ri]
+ drelocs := d.ldr.Relocs(infosym)
+ relocs = drelocs.ReadSyms(relocs)
+ for ri := 0; ri < drelocs.Count; ri++ {
+ r := &relocs[ri]
if r.Type == objabi.R_DWARFSECREF {
rsym := r.Sym
- if strings.HasPrefix(rsym.Name, dwarf.InfoPrefix) && strings.HasSuffix(rsym.Name, dwarf.AbstractFuncSuffix) && !rsym.Attr.OnList() {
- // abstract function
- rsym.Attr |= sym.AttrOnList
- unit.AbsFnDIEs = append(unit.AbsFnDIEs, rsym)
- importInfoSymbol(ctxt, rsym)
- } else if rsym.Size == 0 {
- // a type we do not have a DIE for
- n := nameFromDIESym(rsym)
- defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
+ rsn := d.ldr.SymName(rsym)
+ if len(rsn) == 0 {
+ continue
}
+ // NB: there should be a better way to do this that doesn't involve materializing the symbol name and doing string prefix+suffix checks.
+ if strings.HasPrefix(rsn, dwarf.InfoPrefix) && strings.HasSuffix(rsn, dwarf.AbstractFuncSuffix) && !d.ldr.AttrOnList(rsym) {
+ // abstract function
+ d.ldr.SetAttrOnList(rsym, true)
+ unit.AbsFnDIEs2 = append(unit.AbsFnDIEs2, sym.LoaderSym(rsym))
+ d.importInfoSymbol(ctxt, rsym)
+ continue
+ }
+ if _, ok := d.rtmap[rsym]; ok {
+ // type already generated
+ continue
+ }
+ tn := rsn[len(dwarf.InfoPrefix):]
+ ts := d.ldr.Lookup("type."+tn, 0)
+ d.defgotype(ts)
}
}
}
@@ -1769,19 +1967,56 @@
}
// Create DIEs for global variables and the types they use.
- genasmsym(ctxt, defdwsymb)
+ // FIXME: ideally this should be done in the compiler, since
+ // for globals there isn't any abiguity about which package
+ // a global belongs to.
+ for idx := loader.Sym(1); idx < loader.Sym(d.ldr.NDef()); idx++ {
+ if !d.ldr.AttrReachable(idx) ||
+ d.ldr.AttrNotInSymbolTable(idx) ||
+ d.ldr.SymVersion(idx) >= sym.SymVerStatic {
+ continue
+ }
+ t := d.ldr.SymType(idx)
+ switch t {
+ case sym.SRODATA, sym.SDATA, sym.SNOPTRDATA, sym.STYPE, sym.SBSS, sym.SNOPTRBSS, sym.STLSBSS:
+ // ok
+ default:
+ continue
+ }
+ // Skip things with no type
+ if d.ldr.SymGoType(idx) == 0 {
+ continue
+ }
+
+ sn := d.ldr.SymName(idx)
+ if ctxt.LinkMode != LinkExternal && isStaticTemp(sn) {
+ continue
+ }
+ if sn == "" {
+ // skip aux symbols
+ continue
+ }
+
+ // Create DIE for global.
+ sv := d.ldr.SymValue(idx)
+ gt := d.ldr.SymGoType(idx)
+ d.dwarfDefineGlobal(ctxt, idx, sn, sv, gt)
+ }
// Create DIEs for variable types indirectly referenced by function
// autos (which may not appear directly as param/var DIEs).
for _, lib := range ctxt.Library {
for _, unit := range lib.Units {
- lists := [][]*sym.Symbol{unit.AbsFnDIEs, unit.FuncDIEs}
+ lists := [][]sym.LoaderSym{unit.AbsFnDIEs2, unit.FuncDIEs2}
for _, list := range lists {
for _, s := range list {
- for i := 0; i < len(s.R); i++ {
- r := &s.R[i]
+ symIdx := loader.Sym(s)
+ srelocs := d.ldr.Relocs(symIdx)
+ relocs = srelocs.ReadSyms(relocs)
+ for i := 0; i < len(relocs); i++ {
+ r := &relocs[i]
if r.Type == objabi.R_USETYPE {
- defgotype(ctxt, r.Sym)
+ d.defgotype(r.Sym)
}
}
}
@@ -1789,76 +2024,117 @@
}
}
- synthesizestringtypes(ctxt, dwtypes.Child)
- synthesizeslicetypes(ctxt, dwtypes.Child)
- synthesizemaptypes(ctxt, dwtypes.Child)
- synthesizechantypes(ctxt, dwtypes.Child)
+ d.synthesizestringtypes(ctxt, dwtypes.Child)
+ d.synthesizeslicetypes(ctxt, dwtypes.Child)
+ d.synthesizemaptypes(ctxt, dwtypes.Child)
+ d.synthesizechantypes(ctxt, dwtypes.Child)
+
+ // NB: at this stage we have all the DIE objects constructed, but
+ // they have loader.Sym attributes and not sym.Symbol attributes.
+ // At the point when loadlibfull runs we will need to visit
+ // every DIE constructed and convert the symbols.
}
// dwarfGenerateDebugSyms constructs debug_line, debug_frame, debug_loc,
// debug_pubnames and debug_pubtypes. It also writes out the debug_info
-// section using symbols generated in dwarfGenerateDebugInfo.
+// section using symbols generated in dwarfGenerateDebugInfo2.
func dwarfGenerateDebugSyms(ctxt *Link) {
if !dwarfEnabled(ctxt) {
return
}
+ d := &dwctxt2{
+ linkctxt: ctxt,
+ ldr: ctxt.loader,
+ arch: ctxt.Arch,
+ }
+ d.dwarfGenerateDebugSyms()
+}
- abbrev := writeabbrev(ctxt)
- syms := []*sym.Symbol{abbrev}
+func (d *dwctxt2) dwarfGenerateDebugSyms() {
- calcCompUnitRanges(ctxt)
- sort.Sort(compilationUnitByStartPC(ctxt.compUnits))
+ // Hack: because the "wavefront" hasn't been pushed all the way
+ // up to dodata(), there will have been changes made to the sym.Symbol's
+ // that are not yet reflected in the loader. Call a temporary
+ // loader routine that copies any changes back.
+ // WARNING: changing a symbol's content will usually require
+ // calling the loader cloneToExternal method, meaning that there
+ // can be an increase in memory, so this is likely to mess up any
+ // benchmarking runs.
+ d.ldr.PropagateSymbolChangesBackToLoader()
+
+ abbrev := d.writeabbrev()
+ syms := []loader.Sym{abbrev}
+
+ d.calcCompUnitRanges()
+ sort.Sort(compilationUnitByStartPC(d.linkctxt.compUnits))
+
+ // Create .debug_line and .debug_ranges section symbols
+ debugLine := d.ldr.AddExtSym(".debug_line", 0)
+ dlu := d.ldr.MakeSymbolUpdater(debugLine)
+ dlu.SetType(sym.SDWARFSECT)
+ d.ldr.SetAttrReachable(debugLine, true)
+ syms = append(syms, debugLine)
+
+ debugRanges := d.ldr.AddExtSym(".debug_ranges", 0)
+ dru := d.ldr.MakeSymbolUpdater(debugRanges)
+ dru.SetType(sym.SDWARFRANGE)
+ d.ldr.SetAttrReachable(debugRanges, true)
// Write per-package line and range tables and start their CU DIEs.
- debugLine := ctxt.Syms.Lookup(".debug_line", 0)
- debugLine.Type = sym.SDWARFSECT
- debugRanges := ctxt.Syms.Lookup(".debug_ranges", 0)
- debugRanges.Type = sym.SDWARFRANGE
- debugRanges.Attr |= sym.AttrReachable
- syms = append(syms, debugLine)
- for _, u := range ctxt.compUnits {
+ for _, u := range d.linkctxt.compUnits {
reversetree(&u.DWInfo.Child)
if u.DWInfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS {
continue
}
- writelines(ctxt, u, debugLine)
- writepcranges(ctxt, u, u.Textp[0], u.PCs, debugRanges)
+ d.writelines(u, debugLine)
+ base := loader.Sym(u.Textp2[0])
+ d.writepcranges(u, base, u.PCs, debugRanges)
}
// newdie adds DIEs to the *beginning* of the parent's DIE list.
// Now that we're done creating DIEs, reverse the trees so DIEs
// appear in the order they were created.
reversetree(&dwtypes.Child)
- movetomodule(ctxt, &dwtypes)
+ movetomodule(d.linkctxt, &dwtypes)
- pubNames := newPubWriter(ctxt, ".debug_pubnames")
- pubTypes := newPubWriter(ctxt, ".debug_pubtypes")
+ pubNames := newPubWriter2(d, ".debug_pubnames")
+ pubTypes := newPubWriter2(d, ".debug_pubtypes")
// Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT
- infosyms := writeinfo(ctxt, nil, ctxt.compUnits, abbrev, pubNames, pubTypes)
+ infosyms := d.writeinfo(nil, d.linkctxt.compUnits, abbrev, pubNames, pubTypes)
- syms = writeframes(ctxt, syms)
+ syms = d.writeframes(syms)
syms = append(syms, pubNames.s, pubTypes.s)
- syms = writegdbscript(ctxt, syms)
- // Now we're done writing SDWARFSECT symbols, so we can write
+ syms = d.writegdbscript(syms)
+ // We are now done writing SDWARFSECT symbols, so we can write
// other SDWARF* symbols.
syms = append(syms, infosyms...)
- syms = collectlocs(ctxt, syms, ctxt.compUnits)
+ syms = d.collectlocs(syms, d.linkctxt.compUnits)
syms = append(syms, debugRanges)
- for _, unit := range ctxt.compUnits {
- syms = append(syms, unit.RangeSyms...)
+ for _, unit := range d.linkctxt.compUnits {
+ for _, s := range unit.RangeSyms2 {
+ syms = append(syms, loader.Sym(s))
+ }
}
- dwarfp = syms
+ dwarfp2 = syms
+ dwarfp = d.ldr.PropagateLoaderChangesToSymbols(dwarfp2, d.linkctxt.Syms)
}
-func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*sym.CompilationUnit) []*sym.Symbol {
+func (d *dwctxt2) collectlocs(syms []loader.Sym, units []*sym.CompilationUnit) []loader.Sym {
empty := true
+ rslice := []loader.Reloc{}
for _, u := range units {
- for _, fn := range u.FuncDIEs {
- for i := range fn.R {
- reloc := &fn.R[i] // Copying sym.Reloc has measurable impact on performance
- if reloc.Type == objabi.R_DWARFSECREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
- reloc.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
+ for _, fn := range u.FuncDIEs2 {
+ relocs := d.ldr.Relocs(loader.Sym(fn))
+ rslice := relocs.ReadSyms(rslice)
+ for i := range rslice {
+ reloc := &rslice[i]
+ if reloc.Type != objabi.R_DWARFSECREF {
+ continue
+ }
+ if d.ldr.SymType(reloc.Sym) == sym.SDWARFLOC {
+ d.ldr.SetAttrReachable(reloc.Sym, true)
+ d.ldr.SetAttrNotInSymbolTable(reloc.Sym, true)
syms = append(syms, reloc.Sym)
empty = false
// One location list entry per function, but many relocations to it. Don't duplicate.
@@ -1867,152 +2143,44 @@
}
}
}
+
// Don't emit .debug_loc if it's empty -- it makes the ARM linker mad.
if !empty {
- locsym := ctxt.Syms.Lookup(".debug_loc", 0)
- locsym.Type = sym.SDWARFLOC
- locsym.Attr |= sym.AttrReachable
+ locsym := d.ldr.AddExtSym(".debug_loc", 0)
+ u := d.ldr.MakeSymbolUpdater(locsym)
+ u.SetType(sym.SDWARFLOC)
+ d.ldr.SetAttrReachable(locsym, true)
syms = append(syms, locsym)
}
return syms
}
-// Read a pointer-sized uint from the beginning of buf.
-func readPtr(ctxt *Link, buf []byte) uint64 {
- switch ctxt.Arch.PtrSize {
- case 4:
- return uint64(ctxt.Arch.ByteOrder.Uint32(buf))
- case 8:
- return ctxt.Arch.ByteOrder.Uint64(buf)
- default:
- panic("unexpected pointer size")
- }
-}
-
/*
* Elf.
*/
-func dwarfaddshstrings(ctxt *Link, shstrtab *sym.Symbol) {
- if *FlagW { // disable dwarf
- return
- }
-
- secs := []string{"abbrev", "frame", "info", "loc", "line", "pubnames", "pubtypes", "gdb_scripts", "ranges"}
- for _, sec := range secs {
- Addstring(shstrtab, ".debug_"+sec)
- if ctxt.LinkMode == LinkExternal {
- Addstring(shstrtab, elfRelType+".debug_"+sec)
- } else {
- Addstring(shstrtab, ".zdebug_"+sec)
- }
- }
+func (d *dwctxt2) dwarfaddshstrings(ctxt *Link, shstrtab loader.Sym) {
+ panic("not yet implemented")
}
// Add section symbols for DWARF debug info. This is called before
// dwarfaddelfheaders.
-func dwarfaddelfsectionsyms(ctxt *Link) {
- if *FlagW { // disable dwarf
- return
- }
- if ctxt.LinkMode != LinkExternal {
- return
- }
-
- s := ctxt.Syms.Lookup(".debug_info", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_abbrev", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_line", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_frame", 0)
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- s = ctxt.Syms.Lookup(".debug_loc", 0)
- if s.Sect != nil {
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- }
- s = ctxt.Syms.Lookup(".debug_ranges", 0)
- if s.Sect != nil {
- putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
- }
+func (d *dwctxt2) dwarfaddelfsectionsyms(ctxt *Link) {
+ panic("not yet implemented")
}
// dwarfcompress compresses the DWARF sections. Relocations are applied
// on the fly. After this, dwarfp will contain a different (new) set of
// symbols, and sections may have been replaced.
-func dwarfcompress(ctxt *Link) {
- supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin
- if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal {
- return
- }
-
- var start int
- var newDwarfp []*sym.Symbol
- Segdwarf.Sections = Segdwarf.Sections[:0]
- for i, s := range dwarfp {
- // Find the boundaries between sections and compress
- // the whole section once we've found the last of its
- // symbols.
- if i+1 >= len(dwarfp) || s.Sect != dwarfp[i+1].Sect {
- s1 := compressSyms(ctxt, dwarfp[start:i+1])
- if s1 == nil {
- // Compression didn't help.
- newDwarfp = append(newDwarfp, dwarfp[start:i+1]...)
- Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
- } else {
- compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
- sect := addsection(ctxt.Arch, &Segdwarf, compressedSegName, 04)
- sect.Length = uint64(len(s1))
- newSym := ctxt.Syms.Lookup(compressedSegName, 0)
- newSym.P = s1
- newSym.Size = int64(len(s1))
- newSym.Sect = sect
- newDwarfp = append(newDwarfp, newSym)
- }
- start = i + 1
- }
- }
- dwarfp = newDwarfp
- ctxt.relocbuf = nil // no longer needed, don't hold it live
-
- // Re-compute the locations of the compressed DWARF symbols
- // and sections, since the layout of these within the file is
- // based on Section.Vaddr and Symbol.Value.
- pos := Segdwarf.Vaddr
- var prevSect *sym.Section
- for _, s := range dwarfp {
- s.Value = int64(pos)
- if s.Sect != prevSect {
- s.Sect.Vaddr = uint64(s.Value)
- prevSect = s.Sect
- }
- if s.Sub != nil {
- log.Fatalf("%s: unexpected sub-symbols", s)
- }
- pos += uint64(s.Size)
- if ctxt.HeadType == objabi.Hwindows {
- pos = uint64(Rnd(int64(pos), PEFILEALIGN))
- }
-
- }
- Segdwarf.Length = pos - Segdwarf.Vaddr
+func (d *dwctxt2) dwarfcompress(ctxt *Link) {
+ panic("not yet implemented")
}
-type compilationUnitByStartPC []*sym.CompilationUnit
-
-func (v compilationUnitByStartPC) Len() int { return len(v) }
-func (v compilationUnitByStartPC) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
-
-func (v compilationUnitByStartPC) Less(i, j int) bool {
- switch {
- case len(v[i].Textp) == 0 && len(v[j].Textp) == 0:
- return v[i].Lib.Pkg < v[j].Lib.Pkg
- case len(v[i].Textp) != 0 && len(v[j].Textp) == 0:
- return true
- case len(v[i].Textp) == 0 && len(v[j].Textp) != 0:
- return false
- default:
- return v[i].Textp[0].Value < v[j].Textp[0].Value
- }
+// getPkgFromCUSym returns the package name for the compilation unit
+// represented by s.
+// The prefix dwarf.InfoPrefix+".pkg." needs to be removed in order to get
+// the package name.
+func (d *dwctxt2) getPkgFromCUSym(s loader.Sym) string {
+ return strings.TrimPrefix(d.ldr.SymName(s), dwarf.InfoPrefix+".pkg.")
}
// On AIX, the symbol table needs to know where are the compilation units parts
@@ -2034,11 +2202,3 @@
func addDwsectCUSize(sname string, pkgname string, size uint64) {
dwsectCUSize[sname+"."+pkgname] += size
}
-
-// getPkgFromCUSym returns the package name for the compilation unit
-// represented by s.
-// The prefix dwarf.InfoPrefix+".pkg." needs to be removed in order to get
-// the package name.
-func getPkgFromCUSym(s *sym.Symbol) string {
- return strings.TrimPrefix(s.Name, dwarf.InfoPrefix+".pkg.")
-}
diff --git a/src/cmd/link/internal/ld/dwarf2.go b/src/cmd/link/internal/ld/dwarf2.go
new file mode 100644
index 0000000..233cd6a
--- /dev/null
+++ b/src/cmd/link/internal/ld/dwarf2.go
@@ -0,0 +1,172 @@
+// Copyright 2010 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.
+
+// TODO/NICETOHAVE:
+// - eliminate DW_CLS_ if not used
+// - package info in compilation units
+// - assign types to their packages
+// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
+// ptype struct '[]uint8' and qualifiers need to be quoted away
+// - file:line info for variables
+// - make strings a typedef so prettyprinters can see the underlying string type
+
+package ld
+
+import (
+ "cmd/internal/objabi"
+ "cmd/link/internal/loader"
+ "cmd/link/internal/sym"
+ "log"
+)
+
+func isDwarf64(ctxt *Link) bool {
+ return ctxt.HeadType == objabi.Haix
+}
+
+var dwarfp []*sym.Symbol
+
+/*
+ * Elf.
+ */
+func dwarfaddshstrings(ctxt *Link, shstrtab *loader.SymbolBuilder) {
+ if *FlagW { // disable dwarf
+ return
+ }
+
+ secs := []string{"abbrev", "frame", "info", "loc", "line", "pubnames", "pubtypes", "gdb_scripts", "ranges"}
+ for _, sec := range secs {
+ shstrtab.Addstring(".debug_" + sec)
+ if ctxt.IsExternal() {
+ shstrtab.Addstring(elfRelType + ".debug_" + sec)
+ } else {
+ shstrtab.Addstring(".zdebug_" + sec)
+ }
+ }
+}
+
+// Add section symbols for DWARF debug info. This is called before
+// dwarfaddelfheaders.
+func dwarfaddelfsectionsyms(ctxt *Link) {
+ if *FlagW { // disable dwarf
+ return
+ }
+ if ctxt.LinkMode != LinkExternal {
+ return
+ }
+
+ s := ctxt.Syms.Lookup(".debug_info", 0)
+ putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
+ s = ctxt.Syms.Lookup(".debug_abbrev", 0)
+ putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
+ s = ctxt.Syms.Lookup(".debug_line", 0)
+ putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
+ s = ctxt.Syms.Lookup(".debug_frame", 0)
+ putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
+ s = ctxt.Syms.Lookup(".debug_loc", 0)
+ if s.Sect != nil {
+ putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
+ }
+ s = ctxt.Syms.Lookup(".debug_ranges", 0)
+ if s.Sect != nil {
+ putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
+ }
+}
+
+// dwarfcompress compresses the DWARF sections. Relocations are applied
+// on the fly. After this, dwarfp will contain a different (new) set of
+// symbols, and sections may have been replaced.
+func dwarfcompress(ctxt *Link) {
+ // compressedSect is a helper type for parallelizing compression.
+ type compressedSect struct {
+ index int
+ compressed []byte
+ syms []*sym.Symbol
+ }
+
+ supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin
+ if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal {
+ return
+ }
+
+ var start, compressedCount int
+ resChannel := make(chan compressedSect)
+ for i, s := range dwarfp {
+ // Find the boundaries between sections and compress
+ // the whole section once we've found the last of its
+ // symbols.
+ if i+1 >= len(dwarfp) || s.Sect != dwarfp[i+1].Sect {
+ go func(resIndex int, syms []*sym.Symbol) {
+ resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms}
+ }(compressedCount, dwarfp[start:i+1])
+ compressedCount++
+ start = i + 1
+ }
+ }
+ res := make([]compressedSect, compressedCount)
+ for ; compressedCount > 0; compressedCount-- {
+ r := <-resChannel
+ res[r.index] = r
+ }
+
+ var newDwarfp []*sym.Symbol
+ Segdwarf.Sections = Segdwarf.Sections[:0]
+ for _, z := range res {
+ s := z.syms[0]
+ if z.compressed == nil {
+ // Compression didn't help.
+ newDwarfp = append(newDwarfp, z.syms...)
+ Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
+ } else {
+ compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
+ sect := addsection(ctxt.Arch, &Segdwarf, compressedSegName, 04)
+ sect.Length = uint64(len(z.compressed))
+ newSym := ctxt.Syms.Lookup(compressedSegName, 0)
+ newSym.P = z.compressed
+ newSym.Size = int64(len(z.compressed))
+ newSym.Sect = sect
+ newDwarfp = append(newDwarfp, newSym)
+ }
+ }
+ dwarfp = newDwarfp
+
+ // Re-compute the locations of the compressed DWARF symbols
+ // and sections, since the layout of these within the file is
+ // based on Section.Vaddr and Symbol.Value.
+ pos := Segdwarf.Vaddr
+ var prevSect *sym.Section
+ for _, s := range dwarfp {
+ s.Value = int64(pos)
+ if s.Sect != prevSect {
+ s.Sect.Vaddr = uint64(s.Value)
+ prevSect = s.Sect
+ }
+ if s.Sub != nil {
+ log.Fatalf("%s: unexpected sub-symbols", s)
+ }
+ pos += uint64(s.Size)
+ if ctxt.HeadType == objabi.Hwindows {
+ pos = uint64(Rnd(int64(pos), PEFILEALIGN))
+ }
+
+ }
+ Segdwarf.Length = pos - Segdwarf.Vaddr
+}
+
+type compilationUnitByStartPC []*sym.CompilationUnit
+
+func (v compilationUnitByStartPC) Len() int { return len(v) }
+func (v compilationUnitByStartPC) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
+
+func (v compilationUnitByStartPC) Less(i, j int) bool {
+ switch {
+ case len(v[i].Textp2) == 0 && len(v[j].Textp2) == 0:
+ return v[i].Lib.Pkg < v[j].Lib.Pkg
+ case len(v[i].Textp2) != 0 && len(v[j].Textp2) == 0:
+ return true
+ case len(v[i].Textp2) == 0 && len(v[j].Textp2) != 0:
+ return false
+ default:
+ return v[i].PCs[0].Start < v[j].PCs[0].Start
+ }
+}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index b7221f0..078b0a5 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -7,6 +7,7 @@
import (
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"crypto/sha1"
"encoding/binary"
@@ -742,7 +743,40 @@
return h
}
-func Elfwritedynent(ctxt *Link, s *sym.Symbol, tag int, val uint64) {
+func elfWriteDynEnt(arch *sys.Arch, s *sym.Symbol, tag int, val uint64) {
+ if elf64 {
+ s.AddUint64(arch, uint64(tag))
+ s.AddUint64(arch, val)
+ } else {
+ s.AddUint32(arch, uint32(tag))
+ s.AddUint32(arch, uint32(val))
+ }
+}
+
+func elfWriteDynEntSym(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol) {
+ Elfwritedynentsymplus(arch, s, tag, t, 0)
+}
+
+func Elfwritedynentsymplus(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol, add int64) {
+ if elf64 {
+ s.AddUint64(arch, uint64(tag))
+ } else {
+ s.AddUint32(arch, uint32(tag))
+ }
+ s.AddAddrPlus(arch, t, add)
+}
+
+func elfWriteDynEntSymSize(arch *sys.Arch, s *sym.Symbol, tag int, t *sym.Symbol) {
+ if elf64 {
+ s.AddUint64(arch, uint64(tag))
+ } else {
+ s.AddUint32(arch, uint32(tag))
+ }
+ s.AddSize(arch, t)
+}
+
+// temporary
+func Elfwritedynent2(ctxt *Link, s *loader.SymbolBuilder, tag int, val uint64) {
if elf64 {
s.AddUint64(ctxt.Arch, uint64(tag))
s.AddUint64(ctxt.Arch, val)
@@ -752,11 +786,11 @@
}
}
-func elfwritedynentsym(ctxt *Link, s *sym.Symbol, tag int, t *sym.Symbol) {
- Elfwritedynentsymplus(ctxt, s, tag, t, 0)
+func elfwritedynentsym2(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+ Elfwritedynentsymplus2(ctxt, s, tag, t, 0)
}
-func Elfwritedynentsymplus(ctxt *Link, s *sym.Symbol, tag int, t *sym.Symbol, add int64) {
+func Elfwritedynentsymplus2(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym, add int64) {
if elf64 {
s.AddUint64(ctxt.Arch, uint64(tag))
} else {
@@ -765,7 +799,7 @@
s.AddAddrPlus(ctxt.Arch, t, add)
}
-func elfwritedynentsymsize(ctxt *Link, s *sym.Symbol, tag int, t *sym.Symbol) {
+func elfwritedynentsymsize2(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
if elf64 {
s.AddUint64(ctxt.Arch, uint64(tag))
} else {
@@ -1121,23 +1155,23 @@
s = ctxt.Syms.Lookup(".dynamic", 0)
elfverneed = nfile
if elfverneed != 0 {
- elfwritedynentsym(ctxt, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
- Elfwritedynent(ctxt, s, DT_VERNEEDNUM, uint64(nfile))
- elfwritedynentsym(ctxt, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
+ elfWriteDynEntSym(ctxt.Arch, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
+ elfWriteDynEnt(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
+ elfWriteDynEntSym(ctxt.Arch, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
}
sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
if sy.Size > 0 {
if elfRelType == ".rela" {
- Elfwritedynent(ctxt, s, DT_PLTREL, DT_RELA)
+ elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_RELA)
} else {
- Elfwritedynent(ctxt, s, DT_PLTREL, DT_REL)
+ elfWriteDynEnt(ctxt.Arch, s, DT_PLTREL, DT_REL)
}
- elfwritedynentsymsize(ctxt, s, DT_PLTRELSZ, sy)
- elfwritedynentsym(ctxt, s, DT_JMPREL, sy)
+ elfWriteDynEntSymSize(ctxt.Arch, s, DT_PLTRELSZ, sy)
+ elfWriteDynEntSym(ctxt.Arch, s, DT_JMPREL, sy)
}
- Elfwritedynent(ctxt, s, DT_NULL, 0)
+ elfWriteDynEnt(ctxt.Arch, s, DT_NULL, 0)
}
func elfphload(seg *sym.Segment) *ElfPhdr {
@@ -1400,9 +1434,10 @@
}
func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) {
- s := ctxt.Syms.Lookup(sectionName, 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
+ ldr := ctxt.loader
+ s := ldr.CreateSymForUpdate(sectionName, 0)
+ s.SetReachable(true)
+ s.SetType(sym.SELFROSECT)
// namesz
s.AddUint32(ctxt.Arch, uint32(len(ELF_NOTE_GO_NAME)))
// descsz
@@ -1410,93 +1445,91 @@
// tag
s.AddUint32(ctxt.Arch, tag)
// name + padding
- s.P = append(s.P, ELF_NOTE_GO_NAME...)
- for len(s.P)%4 != 0 {
- s.P = append(s.P, 0)
+ s.AddBytes(ELF_NOTE_GO_NAME)
+ for len(s.Data())%4 != 0 {
+ s.AddUint8(0)
}
// desc + padding
- s.P = append(s.P, desc...)
- for len(s.P)%4 != 0 {
- s.P = append(s.P, 0)
+ s.AddBytes(desc)
+ for len(s.Data())%4 != 0 {
+ s.AddUint8(0)
}
- s.Size = int64(len(s.P))
- s.Align = 4
+ s.SetSize(int64(len(s.Data())))
+ s.SetAlign(4)
}
func (ctxt *Link) doelf() {
- if !ctxt.IsELF {
- return
- }
+ ldr := ctxt.loader
/* predefine strings we need for section headers */
- shstrtab := ctxt.Syms.Lookup(".shstrtab", 0)
+ shstrtab := ldr.CreateSymForUpdate(".shstrtab", 0)
- shstrtab.Type = sym.SELFROSECT
- shstrtab.Attr |= sym.AttrReachable
+ shstrtab.SetType(sym.SELFROSECT)
+ shstrtab.SetReachable(true)
- Addstring(shstrtab, "")
- Addstring(shstrtab, ".text")
- Addstring(shstrtab, ".noptrdata")
- Addstring(shstrtab, ".data")
- Addstring(shstrtab, ".bss")
- Addstring(shstrtab, ".noptrbss")
- Addstring(shstrtab, "__libfuzzer_extra_counters")
- Addstring(shstrtab, ".go.buildinfo")
+ shstrtab.Addstring("")
+ shstrtab.Addstring(".text")
+ shstrtab.Addstring(".noptrdata")
+ shstrtab.Addstring(".data")
+ shstrtab.Addstring(".bss")
+ shstrtab.Addstring(".noptrbss")
+ shstrtab.Addstring("__libfuzzer_extra_counters")
+ shstrtab.Addstring(".go.buildinfo")
// generate .tbss section for dynamic internal linker or external
// linking, so that various binutils could correctly calculate
// PT_TLS size. See https://golang.org/issue/5200.
- if !*FlagD || ctxt.LinkMode == LinkExternal {
- Addstring(shstrtab, ".tbss")
+ if !*FlagD || ctxt.IsExternal() {
+ shstrtab.Addstring(".tbss")
}
- if ctxt.HeadType == objabi.Hnetbsd {
- Addstring(shstrtab, ".note.netbsd.ident")
+ if ctxt.IsNetbsd() {
+ shstrtab.Addstring(".note.netbsd.ident")
}
- if ctxt.HeadType == objabi.Hopenbsd {
- Addstring(shstrtab, ".note.openbsd.ident")
+ if ctxt.IsOpenbsd() {
+ shstrtab.Addstring(".note.openbsd.ident")
}
if len(buildinfo) > 0 {
- Addstring(shstrtab, ".note.gnu.build-id")
+ shstrtab.Addstring(".note.gnu.build-id")
}
if *flagBuildid != "" {
- Addstring(shstrtab, ".note.go.buildid")
+ shstrtab.Addstring(".note.go.buildid")
}
- Addstring(shstrtab, ".elfdata")
- Addstring(shstrtab, ".rodata")
+ shstrtab.Addstring(".elfdata")
+ shstrtab.Addstring(".rodata")
// See the comment about data.rel.ro.FOO section names in data.go.
relro_prefix := ""
if ctxt.UseRelro() {
- Addstring(shstrtab, ".data.rel.ro")
+ shstrtab.Addstring(".data.rel.ro")
relro_prefix = ".data.rel.ro"
}
- Addstring(shstrtab, relro_prefix+".typelink")
- Addstring(shstrtab, relro_prefix+".itablink")
- Addstring(shstrtab, relro_prefix+".gosymtab")
- Addstring(shstrtab, relro_prefix+".gopclntab")
+ shstrtab.Addstring(relro_prefix + ".typelink")
+ shstrtab.Addstring(relro_prefix + ".itablink")
+ shstrtab.Addstring(relro_prefix + ".gosymtab")
+ shstrtab.Addstring(relro_prefix + ".gopclntab")
- if ctxt.LinkMode == LinkExternal {
+ if ctxt.IsExternal() {
*FlagD = true
- Addstring(shstrtab, elfRelType+".text")
- Addstring(shstrtab, elfRelType+".rodata")
- Addstring(shstrtab, elfRelType+relro_prefix+".typelink")
- Addstring(shstrtab, elfRelType+relro_prefix+".itablink")
- Addstring(shstrtab, elfRelType+relro_prefix+".gosymtab")
- Addstring(shstrtab, elfRelType+relro_prefix+".gopclntab")
- Addstring(shstrtab, elfRelType+".noptrdata")
- Addstring(shstrtab, elfRelType+".data")
+ shstrtab.Addstring(elfRelType + ".text")
+ shstrtab.Addstring(elfRelType + ".rodata")
+ shstrtab.Addstring(elfRelType + relro_prefix + ".typelink")
+ shstrtab.Addstring(elfRelType + relro_prefix + ".itablink")
+ shstrtab.Addstring(elfRelType + relro_prefix + ".gosymtab")
+ shstrtab.Addstring(elfRelType + relro_prefix + ".gopclntab")
+ shstrtab.Addstring(elfRelType + ".noptrdata")
+ shstrtab.Addstring(elfRelType + ".data")
if ctxt.UseRelro() {
- Addstring(shstrtab, elfRelType+".data.rel.ro")
+ shstrtab.Addstring(elfRelType + ".data.rel.ro")
}
- Addstring(shstrtab, elfRelType+".go.buildinfo")
+ shstrtab.Addstring(elfRelType + ".go.buildinfo")
// add a .note.GNU-stack section to mark the stack as non-executable
- Addstring(shstrtab, ".note.GNU-stack")
+ shstrtab.Addstring(".note.GNU-stack")
- if ctxt.BuildMode == BuildModeShared {
- Addstring(shstrtab, ".note.go.abihash")
- Addstring(shstrtab, ".note.go.pkg-list")
- Addstring(shstrtab, ".note.go.deps")
+ if ctxt.IsShared() {
+ shstrtab.Addstring(".note.go.abihash")
+ shstrtab.Addstring(".note.go.pkg-list")
+ shstrtab.Addstring(".note.go.deps")
}
}
@@ -1509,171 +1542,171 @@
}
if hasinitarr {
- Addstring(shstrtab, ".init_array")
- Addstring(shstrtab, elfRelType+".init_array")
+ shstrtab.Addstring(".init_array")
+ shstrtab.Addstring(elfRelType + ".init_array")
}
if !*FlagS {
- Addstring(shstrtab, ".symtab")
- Addstring(shstrtab, ".strtab")
+ shstrtab.Addstring(".symtab")
+ shstrtab.Addstring(".strtab")
dwarfaddshstrings(ctxt, shstrtab)
}
- Addstring(shstrtab, ".shstrtab")
+ shstrtab.Addstring(".shstrtab")
if !*FlagD { /* -d suppresses dynamic loader format */
- Addstring(shstrtab, ".interp")
- Addstring(shstrtab, ".hash")
- Addstring(shstrtab, ".got")
- if ctxt.Arch.Family == sys.PPC64 {
- Addstring(shstrtab, ".glink")
+ shstrtab.Addstring(".interp")
+ shstrtab.Addstring(".hash")
+ shstrtab.Addstring(".got")
+ if ctxt.IsPPC64() {
+ shstrtab.Addstring(".glink")
}
- Addstring(shstrtab, ".got.plt")
- Addstring(shstrtab, ".dynamic")
- Addstring(shstrtab, ".dynsym")
- Addstring(shstrtab, ".dynstr")
- Addstring(shstrtab, elfRelType)
- Addstring(shstrtab, elfRelType+".plt")
+ shstrtab.Addstring(".got.plt")
+ shstrtab.Addstring(".dynamic")
+ shstrtab.Addstring(".dynsym")
+ shstrtab.Addstring(".dynstr")
+ shstrtab.Addstring(elfRelType)
+ shstrtab.Addstring(elfRelType + ".plt")
- Addstring(shstrtab, ".plt")
- Addstring(shstrtab, ".gnu.version")
- Addstring(shstrtab, ".gnu.version_r")
+ shstrtab.Addstring(".plt")
+ shstrtab.Addstring(".gnu.version")
+ shstrtab.Addstring(".gnu.version_r")
/* dynamic symbol table - first entry all zeros */
- s := ctxt.Syms.Lookup(".dynsym", 0)
+ dynsym := ldr.CreateSymForUpdate(".dynsym", 0)
- s.Type = sym.SELFROSECT
- s.Attr |= sym.AttrReachable
+ dynsym.SetType(sym.SELFROSECT)
+ dynsym.SetReachable(true)
if elf64 {
- s.Size += ELF64SYMSIZE
+ dynsym.SetSize(dynsym.Size() + ELF64SYMSIZE)
} else {
- s.Size += ELF32SYMSIZE
+ dynsym.SetSize(dynsym.Size() + ELF32SYMSIZE)
}
/* dynamic string table */
- s = ctxt.Syms.Lookup(".dynstr", 0)
+ dynstr := ldr.CreateSymForUpdate(".dynstr", 0)
- s.Type = sym.SELFROSECT
- s.Attr |= sym.AttrReachable
- if s.Size == 0 {
- Addstring(s, "")
+ dynstr.SetType(sym.SELFROSECT)
+ dynstr.SetReachable(true)
+ if dynstr.Size() == 0 {
+ dynstr.Addstring("")
}
- dynstr := s
/* relocation table */
- s = ctxt.Syms.Lookup(elfRelType, 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
+ s := ldr.CreateSymForUpdate(elfRelType, 0)
+ s.SetReachable(true)
+ s.SetType(sym.SELFROSECT)
/* global offset table */
- s = ctxt.Syms.Lookup(".got", 0)
-
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFGOT // writable
+ got := ldr.CreateSymForUpdate(".got", 0)
+ got.SetReachable(true)
+ got.SetType(sym.SELFGOT) // writable
/* ppc64 glink resolver */
- if ctxt.Arch.Family == sys.PPC64 {
- s := ctxt.Syms.Lookup(".glink", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFRXSECT
+ if ctxt.IsPPC64() {
+ s := ldr.CreateSymForUpdate(".glink", 0)
+ s.SetReachable(true)
+ s.SetType(sym.SELFRXSECT)
}
/* hash */
- s = ctxt.Syms.Lookup(".hash", 0)
+ hash := ldr.CreateSymForUpdate(".hash", 0)
+ hash.SetReachable(true)
+ hash.SetType(sym.SELFROSECT)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
+ gotplt := ldr.CreateSymForUpdate(".got.plt", 0)
+ gotplt.SetReachable(true)
+ gotplt.SetType(sym.SELFSECT) // writable
- s = ctxt.Syms.Lookup(".got.plt", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFSECT // writable
-
- s = ctxt.Syms.Lookup(".plt", 0)
-
- s.Attr |= sym.AttrReachable
- if ctxt.Arch.Family == sys.PPC64 {
+ plt := ldr.CreateSymForUpdate(".plt", 0)
+ plt.SetReachable(true)
+ if ctxt.IsPPC64() {
// In the ppc64 ABI, .plt is a data section
// written by the dynamic linker.
- s.Type = sym.SELFSECT
+ plt.SetType(sym.SELFSECT)
} else {
- s.Type = sym.SELFRXSECT
+ plt.SetType(sym.SELFRXSECT)
}
- thearch.Elfsetupplt(ctxt)
+ s = ldr.CreateSymForUpdate(elfRelType+".plt", 0)
+ s.SetReachable(true)
+ s.SetType(sym.SELFROSECT)
- s = ctxt.Syms.Lookup(elfRelType+".plt", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
+ s = ldr.CreateSymForUpdate(".gnu.version", 0)
+ s.SetReachable(true)
+ s.SetType(sym.SELFROSECT)
- s = ctxt.Syms.Lookup(".gnu.version", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
-
- s = ctxt.Syms.Lookup(".gnu.version_r", 0)
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFROSECT
+ s = ldr.CreateSymForUpdate(".gnu.version_r", 0)
+ s.SetReachable(true)
+ s.SetType(sym.SELFROSECT)
/* define dynamic elf table */
- s = ctxt.Syms.Lookup(".dynamic", 0)
+ dynamic := ldr.CreateSymForUpdate(".dynamic", 0)
+ dynamic.SetReachable(true)
+ dynamic.SetType(sym.SELFSECT) // writable
- s.Attr |= sym.AttrReachable
- s.Type = sym.SELFSECT // writable
+ if ctxt.IsS390X() {
+ // S390X uses .got instead of .got.plt
+ gotplt = got
+ }
+ thearch.Elfsetupplt(ctxt, plt, gotplt, dynamic.Sym())
/*
* .dynamic table
*/
- elfwritedynentsym(ctxt, s, DT_HASH, ctxt.Syms.Lookup(".hash", 0))
+ elfwritedynentsym2(ctxt, dynamic, DT_HASH, hash.Sym())
- elfwritedynentsym(ctxt, s, DT_SYMTAB, ctxt.Syms.Lookup(".dynsym", 0))
+ elfwritedynentsym2(ctxt, dynamic, DT_SYMTAB, dynsym.Sym())
if elf64 {
- Elfwritedynent(ctxt, s, DT_SYMENT, ELF64SYMSIZE)
+ Elfwritedynent2(ctxt, dynamic, DT_SYMENT, ELF64SYMSIZE)
} else {
- Elfwritedynent(ctxt, s, DT_SYMENT, ELF32SYMSIZE)
+ Elfwritedynent2(ctxt, dynamic, DT_SYMENT, ELF32SYMSIZE)
}
- elfwritedynentsym(ctxt, s, DT_STRTAB, ctxt.Syms.Lookup(".dynstr", 0))
- elfwritedynentsymsize(ctxt, s, DT_STRSZ, ctxt.Syms.Lookup(".dynstr", 0))
+ elfwritedynentsym2(ctxt, dynamic, DT_STRTAB, dynstr.Sym())
+ elfwritedynentsymsize2(ctxt, dynamic, DT_STRSZ, dynstr.Sym())
if elfRelType == ".rela" {
- elfwritedynentsym(ctxt, s, DT_RELA, ctxt.Syms.Lookup(".rela", 0))
- elfwritedynentsymsize(ctxt, s, DT_RELASZ, ctxt.Syms.Lookup(".rela", 0))
- Elfwritedynent(ctxt, s, DT_RELAENT, ELF64RELASIZE)
+ rela := ldr.LookupOrCreateSym(".rela", 0)
+ elfwritedynentsym2(ctxt, dynamic, DT_RELA, rela)
+ elfwritedynentsymsize2(ctxt, dynamic, DT_RELASZ, rela)
+ Elfwritedynent2(ctxt, dynamic, DT_RELAENT, ELF64RELASIZE)
} else {
- elfwritedynentsym(ctxt, s, DT_REL, ctxt.Syms.Lookup(".rel", 0))
- elfwritedynentsymsize(ctxt, s, DT_RELSZ, ctxt.Syms.Lookup(".rel", 0))
- Elfwritedynent(ctxt, s, DT_RELENT, ELF32RELSIZE)
+ rel := ldr.LookupOrCreateSym(".rel", 0)
+ elfwritedynentsym2(ctxt, dynamic, DT_REL, rel)
+ elfwritedynentsymsize2(ctxt, dynamic, DT_RELSZ, rel)
+ Elfwritedynent2(ctxt, dynamic, DT_RELENT, ELF32RELSIZE)
}
if rpath.val != "" {
- Elfwritedynent(ctxt, s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
+ Elfwritedynent2(ctxt, dynamic, DT_RUNPATH, uint64(dynstr.Addstring(rpath.val)))
}
- if ctxt.Arch.Family == sys.PPC64 {
- elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".plt", 0))
- } else if ctxt.Arch.Family == sys.S390X {
- elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got", 0))
+ if ctxt.IsPPC64() {
+ elfwritedynentsym2(ctxt, dynamic, DT_PLTGOT, plt.Sym())
} else {
- elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got.plt", 0))
+ elfwritedynentsym2(ctxt, dynamic, DT_PLTGOT, gotplt.Sym())
}
- if ctxt.Arch.Family == sys.PPC64 {
- Elfwritedynent(ctxt, s, DT_PPC64_OPT, 0)
+ if ctxt.IsPPC64() {
+ Elfwritedynent2(ctxt, dynamic, DT_PPC64_OPT, 0)
}
// Solaris dynamic linker can't handle an empty .rela.plt if
// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
// size of .rel(a).plt section.
- Elfwritedynent(ctxt, s, DT_DEBUG, 0)
+ Elfwritedynent2(ctxt, dynamic, DT_DEBUG, 0)
}
- if ctxt.BuildMode == BuildModeShared {
+ if ctxt.IsShared() {
// The go.link.abihashbytes symbol will be pointed at the appropriate
// part of the .note.go.abihash section in data.go:func address().
- s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
- s.Attr |= sym.AttrLocal
- s.Type = sym.SRODATA
- s.Attr |= sym.AttrSpecial
- s.Attr |= sym.AttrReachable
- s.Size = int64(sha1.Size)
+ s := ldr.LookupOrCreateSym("go.link.abihashbytes", 0)
+ sb := ldr.MakeSymbolUpdater(s)
+ ldr.SetAttrLocal(s, true)
+ sb.SetType(sym.SRODATA)
+ ldr.SetAttrSpecial(s, true)
+ sb.SetReachable(true)
+ sb.SetSize(sha1.Size)
sort.Sort(byPkg(ctxt.Library))
h := sha1.New()
@@ -2271,15 +2304,15 @@
}
}
-func elfadddynsym(ctxt *Link, s *sym.Symbol) {
+func elfadddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
if elf64 {
s.Dynid = int32(Nelfsym)
Nelfsym++
- d := ctxt.Syms.Lookup(".dynsym", 0)
+ d := syms.DynSym
name := s.Extname()
- d.AddUint32(ctxt.Arch, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))
+ d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
/* type */
t := STB_GLOBAL << 4
@@ -2296,52 +2329,52 @@
/* section where symbol is defined */
if s.Type == sym.SDYNIMPORT {
- d.AddUint16(ctxt.Arch, SHN_UNDEF)
+ d.AddUint16(target.Arch, SHN_UNDEF)
} else {
- d.AddUint16(ctxt.Arch, 1)
+ d.AddUint16(target.Arch, 1)
}
/* value */
if s.Type == sym.SDYNIMPORT {
- d.AddUint64(ctxt.Arch, 0)
+ d.AddUint64(target.Arch, 0)
} else {
- d.AddAddr(ctxt.Arch, s)
+ d.AddAddr(target.Arch, s)
}
/* size of object */
- d.AddUint64(ctxt.Arch, uint64(s.Size))
+ d.AddUint64(target.Arch, uint64(s.Size))
- if ctxt.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib() != "" && !seenlib[s.Dynimplib()] {
- Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(ctxt.Syms.Lookup(".dynstr", 0), s.Dynimplib())))
+ if target.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib() != "" && !seenlib[s.Dynimplib()] {
+ elfWriteDynEnt(target.Arch, syms.Dynamic, DT_NEEDED, uint64(Addstring(syms.DynStr, s.Dynimplib())))
}
} else {
s.Dynid = int32(Nelfsym)
Nelfsym++
- d := ctxt.Syms.Lookup(".dynsym", 0)
+ d := syms.DynSym
/* name */
name := s.Extname()
- d.AddUint32(ctxt.Arch, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))
+ d.AddUint32(target.Arch, uint32(Addstring(syms.DynStr, name)))
/* value */
if s.Type == sym.SDYNIMPORT {
- d.AddUint32(ctxt.Arch, 0)
+ d.AddUint32(target.Arch, 0)
} else {
- d.AddAddr(ctxt.Arch, s)
+ d.AddAddr(target.Arch, s)
}
/* size of object */
- d.AddUint32(ctxt.Arch, uint32(s.Size))
+ d.AddUint32(target.Arch, uint32(s.Size))
/* type */
t := STB_GLOBAL << 4
// TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
- if ctxt.Arch.Family == sys.I386 && s.Attr.CgoExport() && s.Type == sym.STEXT {
+ if target.Arch.Family == sys.I386 && s.Attr.CgoExport() && s.Type == sym.STEXT {
t |= STT_FUNC
- } else if ctxt.Arch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type == sym.STEXT {
+ } else if target.Arch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type == sym.STEXT {
t |= STT_FUNC
} else {
t |= STT_OBJECT
@@ -2351,9 +2384,9 @@
/* shndx */
if s.Type == sym.SDYNIMPORT {
- d.AddUint16(ctxt.Arch, SHN_UNDEF)
+ d.AddUint16(target.Arch, SHN_UNDEF)
} else {
- d.AddUint16(ctxt.Arch, 1)
+ d.AddUint16(target.Arch, 1)
}
}
}
diff --git a/src/cmd/link/internal/ld/errors.go b/src/cmd/link/internal/ld/errors.go
new file mode 100644
index 0000000..0cb0c5b
--- /dev/null
+++ b/src/cmd/link/internal/ld/errors.go
@@ -0,0 +1,62 @@
+// Copyright 2020 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/obj"
+ "cmd/link/internal/sym"
+ "sync"
+)
+
+type unresolvedSymKey struct {
+ from *sym.Symbol // Symbol that referenced unresolved "to"
+ to *sym.Symbol // Unresolved symbol referenced by "from"
+}
+
+type lookupFn func(name string, version int) *sym.Symbol
+
+// ErrorReporter is used to make error reporting thread safe.
+type ErrorReporter struct {
+ unresOnce sync.Once
+ unresSyms map[unresolvedSymKey]bool
+ unresMutex sync.Mutex
+ lookup lookupFn
+}
+
+// errorUnresolved prints unresolved symbol error for r.Sym that is referenced from s.
+func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) {
+ reporter.unresOnce.Do(func() { reporter.unresSyms = make(map[unresolvedSymKey]bool) })
+
+ k := unresolvedSymKey{from: s, to: r.Sym}
+ reporter.unresMutex.Lock()
+ defer reporter.unresMutex.Unlock()
+ if !reporter.unresSyms[k] {
+ reporter.unresSyms[k] = true
+
+ // Try to find symbol under another ABI.
+ var reqABI, haveABI obj.ABI
+ haveABI = ^obj.ABI(0)
+ reqABI, ok := sym.VersionToABI(int(r.Sym.Version))
+ if ok {
+ for abi := obj.ABI(0); abi < obj.ABICount; abi++ {
+ v := sym.ABIToVersion(abi)
+ if v == -1 {
+ continue
+ }
+ if rs := reporter.lookup(r.Sym.Name, v); rs != nil && rs.Type != sym.Sxxx {
+ haveABI = abi
+ }
+ }
+ }
+
+ // Give a special error message for main symbol (see #24809).
+ if r.Sym.Name == "main.main" {
+ Errorf(s, "function main is undeclared in the main package")
+ } else if haveABI != ^obj.ABI(0) {
+ Errorf(s, "relocation target %s not defined for %s (but is defined for %s)", r.Sym.Name, reqABI, haveABI)
+ } else {
+ Errorf(s, "relocation target %s not defined", r.Sym.Name)
+ }
+ }
+}
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 21457fd..55d8265 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -10,6 +10,8 @@
"bytes"
"cmd/internal/bio"
"cmd/internal/objabi"
+ "cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"encoding/json"
"fmt"
@@ -145,16 +147,14 @@
}
}
- if *flagNewobj {
- // Record the directives. We'll process them later after Symbols are created.
- ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
- } else {
- setCgoAttr(ctxt, ctxt.Syms.Lookup, file, pkg, directives)
- }
+ // Record the directives. We'll process them later after Symbols are created.
+ ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
}
// Set symbol attributes or flags based on cgo directives.
-func setCgoAttr(ctxt *Link, lookup func(string, int) *sym.Symbol, file string, pkg string, directives [][]string) {
+// Any newly discovered HOSTOBJ syms are added to 'hostObjSyms'.
+func setCgoAttr(ctxt *Link, lookup func(string, int) loader.Sym, file string, pkg string, directives [][]string, hostObjSyms map[loader.Sym]struct{}) {
+ l := ctxt.loader
for _, f := range directives {
switch f[0] {
case "cgo_import_dynamic":
@@ -197,12 +197,16 @@
remote, q = remote[:i], remote[i+1:]
}
s := lookup(local, 0)
- if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS || s.Type == sym.SHOSTOBJ {
- s.SetDynimplib(lib)
- s.SetExtname(remote)
- s.SetDynimpvers(q)
- if s.Type != sym.SHOSTOBJ {
- s.Type = sym.SDYNIMPORT
+ st := l.SymType(s)
+ if st == 0 || st == sym.SXREF || st == sym.SBSS || st == sym.SNOPTRBSS || st == sym.SHOSTOBJ {
+ l.SetSymDynimplib(s, lib)
+ l.SetSymExtname(s, remote)
+ l.SetSymDynimpvers(s, q)
+ if st != sym.SHOSTOBJ {
+ su := l.MakeSymbolUpdater(s)
+ su.SetType(sym.SDYNIMPORT)
+ } else {
+ hostObjSyms[s] = struct{}{}
}
havedynamic = 1
}
@@ -216,8 +220,10 @@
local := f[1]
s := lookup(local, 0)
- s.Type = sym.SHOSTOBJ
- s.Size = 0
+ su := l.MakeSymbolUpdater(s)
+ su.SetType(sym.SHOSTOBJ)
+ su.SetSize(0)
+ hostObjSyms[s] = struct{}{}
continue
case "cgo_export_static", "cgo_export_dynamic":
@@ -238,6 +244,10 @@
// yet know it's an alias).
s := lookup(local, 0)
+ if l.SymType(s) == sym.SHOSTOBJ {
+ hostObjSyms[s] = struct{}{}
+ }
+
switch ctxt.BuildMode {
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
if s == lookup("main", 0) {
@@ -247,24 +257,27 @@
// export overrides import, for openbsd/cgo.
// see issue 4878.
- if s.Dynimplib() != "" {
- s.ResetDyninfo()
- s.SetExtname("")
- s.Type = 0
+ if l.SymDynimplib(s) != "" {
+ l.SetSymDynimplib(s, "")
+ l.SetSymDynimpvers(s, "")
+ l.SetSymExtname(s, "")
+ var su *loader.SymbolBuilder
+ su = l.MakeSymbolUpdater(s)
+ su.SetType(0)
}
- if !s.Attr.CgoExport() {
- s.SetExtname(remote)
- } else if s.Extname() != remote {
- fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote)
+ if !(l.AttrCgoExportStatic(s) || l.AttrCgoExportDynamic(s)) {
+ l.SetSymExtname(s, remote)
+ } else if l.SymExtname(s) != remote {
+ fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], l.SymName(s), l.SymExtname(s), remote)
nerrors++
return
}
if f[0] == "cgo_export_static" {
- s.Attr |= sym.AttrCgoExportStatic
+ l.SetAttrCgoExportStatic(s, true)
} else {
- s.Attr |= sym.AttrCgoExportDynamic
+ l.SetAttrCgoExportDynamic(s, true)
}
continue
@@ -295,6 +308,7 @@
fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
nerrors++
}
+ return
}
var seenlib = make(map[string]bool)
@@ -306,62 +320,62 @@
seenlib[lib] = true
if ctxt.IsELF {
- s := ctxt.Syms.Lookup(".dynstr", 0)
+ s := ctxt.DynStr
if s.Size == 0 {
Addstring(s, "")
}
- Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
+ elfWriteDynEnt(ctxt.Arch, ctxt.Dynamic, DT_NEEDED, uint64(Addstring(s, lib)))
} else {
Errorf(nil, "adddynlib: unsupported binary format")
}
}
-func Adddynsym(ctxt *Link, s *sym.Symbol) {
- if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal {
+func Adddynsym(target *Target, syms *ArchSyms, s *sym.Symbol) {
+ if s.Dynid >= 0 || target.LinkMode == LinkExternal {
return
}
- if ctxt.IsELF {
- elfadddynsym(ctxt, s)
- } else if ctxt.HeadType == objabi.Hdarwin {
+ if target.IsELF {
+ elfadddynsym(target, syms, s)
+ } else if target.HeadType == objabi.Hdarwin {
Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname())
- } else if ctxt.HeadType == objabi.Hwindows {
+ } else if target.HeadType == objabi.Hwindows {
// already taken care of
} else {
Errorf(s, "adddynsym: unsupported binary format")
}
}
-func fieldtrack(ctxt *Link) {
- // record field tracking references
+func fieldtrack(arch *sys.Arch, l *loader.Loader) {
var buf bytes.Buffer
- for _, s := range ctxt.Syms.Allsym {
- if strings.HasPrefix(s.Name, "go.track.") {
- s.Attr |= sym.AttrSpecial // do not lay out in data segment
- s.Attr |= sym.AttrNotInSymbolTable
- if s.Attr.Reachable() {
- buf.WriteString(s.Name[9:])
- for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] {
+ for i := loader.Sym(1); i < loader.Sym(l.NSym()); i++ {
+ if name := l.SymName(i); strings.HasPrefix(name, "go.track.") {
+ bld := l.MakeSymbolUpdater(i)
+ bld.SetSpecial(true)
+ bld.SetNotInSymbolTable(true)
+ if bld.Reachable() {
+ buf.WriteString(name[9:])
+ for p := l.Reachparent[i]; p != 0; p = l.Reachparent[p] {
buf.WriteString("\t")
- buf.WriteString(p.Name)
+ buf.WriteString(l.SymName(p))
}
buf.WriteString("\n")
- }
- s.Type = sym.SCONST
- s.Value = 0
+ bld.SetType(sym.SCONST)
+ bld.SetValue(0)
+ }
}
}
-
if *flagFieldTrack == "" {
return
}
- s := ctxt.Syms.ROLookup(*flagFieldTrack, 0)
- if s == nil || !s.Attr.Reachable() {
+ s := l.Lookup(*flagFieldTrack, 0)
+ if s == 0 || !l.AttrReachable(s) {
return
}
- s.Type = sym.SDATA
- addstrdata(ctxt, *flagFieldTrack, buf.String())
+ bld := l.MakeSymbolUpdater(s)
+ bld.SetType(sym.SDATA)
+ addstrdata(arch, l, *flagFieldTrack, buf.String())
}
func (ctxt *Link) addexport() {
@@ -389,7 +403,7 @@
}
for _, exp := range dynexp {
- Adddynsym(ctxt, exp)
+ Adddynsym(&ctxt.Target, &ctxt.ArchSyms, exp)
}
for _, lib := range dynlib {
adddynlib(ctxt, lib)
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index a4b4b60..d7d52a5 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -42,7 +42,6 @@
"cmd/link/internal/loadmacho"
"cmd/link/internal/loadpe"
"cmd/link/internal/loadxcoff"
- "cmd/link/internal/objfile"
"cmd/link/internal/sym"
"crypto/sha1"
"debug/elf"
@@ -95,6 +94,40 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+type LookupFn func(name string, version int) *sym.Symbol
+
+// ArchSyms holds a number of architecture specific symbols used during
+// relocation. Rather than allowing them universal access to all symbols,
+// we keep a subset for relocation application.
+type ArchSyms struct {
+ TOC *sym.Symbol
+ DotTOC *sym.Symbol
+ GOT *sym.Symbol
+ PLT *sym.Symbol
+ GOTPLT *sym.Symbol
+
+ Tlsg *sym.Symbol
+ Tlsoffset int
+
+ Dynamic *sym.Symbol
+ DynSym *sym.Symbol
+ DynStr *sym.Symbol
+}
+
+// setArchSyms sets up the ArchSyms structure, and must be called before
+// relocations are applied.
+func (ctxt *Link) setArchSyms() {
+ ctxt.TOC = ctxt.Syms.Lookup("TOC", 0)
+ ctxt.DotTOC = ctxt.Syms.Lookup(".TOC.", 0)
+ ctxt.GOT = ctxt.Syms.Lookup(".got", 0)
+ ctxt.PLT = ctxt.Syms.Lookup(".plt", 0)
+ ctxt.GOTPLT = ctxt.Syms.Lookup(".got.plt", 0)
+
+ ctxt.Dynamic = ctxt.Syms.Lookup(".dynamic", 0)
+ ctxt.DynSym = ctxt.Syms.Lookup(".dynsym", 0)
+ ctxt.DynStr = ctxt.Syms.Lookup(".dynstr", 0)
+}
+
type Arch struct {
Funcalign int
Maxalign int
@@ -108,7 +141,7 @@
Openbsddynld string
Dragonflydynld string
Solarisdynld string
- Adddynrel func(*Link, *sym.Symbol, *sym.Reloc) bool
+ Adddynrel func(*Link, *Target, *ArchSyms, *sym.Symbol, *sym.Reloc) bool
Archinit func(*Link)
// Archreloc is an arch-specific hook that assists in
// relocation processing (invoked by 'relocsym'); it handles
@@ -119,7 +152,7 @@
// value is the appropriately relocated value (to be written back
// to the same spot in sym.P) and a boolean indicating
// success/failure (a failing value indicates a fatal error).
- Archreloc func(link *Link, rel *sym.Reloc, sym *sym.Symbol,
+ Archreloc func(target *Target, syms *ArchSyms, rel *sym.Reloc, sym *sym.Symbol,
offset int64) (relocatedOffset int64, success bool)
// Archrelocvariant is a second arch-specific hook used for
// relocation processing; it handles relocations where r.Type is
@@ -129,7 +162,7 @@
// relocation applies, and "off" is the contents of the
// to-be-relocated data item (from sym.P). Return is an updated
// offset value.
- Archrelocvariant func(link *Link, rel *sym.Reloc, sym *sym.Symbol,
+ Archrelocvariant func(target *Target, syms *ArchSyms, rel *sym.Reloc, sym *sym.Symbol,
offset int64) (relocatedOffset int64)
Trampoline func(*Link, *sym.Reloc, *sym.Symbol)
@@ -141,7 +174,7 @@
Asmb2 func(*Link)
Elfreloc1 func(*Link, *sym.Reloc, int64) bool
- Elfsetupplt func(*Link)
+ Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
Gentext func(*Link)
Machoreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
PEreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool
@@ -381,18 +414,16 @@
}
func (ctxt *Link) loadlib() {
- if *flagNewobj {
- var flags uint32
- switch *FlagStrictDups {
- case 0:
- // nothing to do
- case 1, 2:
- flags = loader.FlagStrictDups
- default:
- log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
- }
- ctxt.loader = loader.NewLoader(flags)
+ var flags uint32
+ switch *FlagStrictDups {
+ case 0:
+ // nothing to do
+ case 1, 2:
+ flags = loader.FlagStrictDups
+ default:
+ log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
}
+ ctxt.loader = loader.NewLoader(flags, elfsetstring)
ctxt.cgo_export_static = make(map[string]bool)
ctxt.cgo_export_dynamic = make(map[string]bool)
@@ -423,35 +454,33 @@
loadobjfile(ctxt, lib)
}
}
+ // At this point, the Go objects are "preloaded". Not all the symbols are
+ // added to the symbol table (only defined package symbols are). Looking
+ // up symbol by name may not get expected result.
- if *flagNewobj {
- iscgo = ctxt.loader.Lookup("x_cgo_init", 0) != 0
- ctxt.canUsePlugins = ctxt.loader.Lookup("plugin.Open", sym.SymVerABIInternal) != 0
- } else {
- iscgo = ctxt.Syms.ROLookup("x_cgo_init", 0) != nil
- ctxt.canUsePlugins = ctxt.Syms.ROLookup("plugin.Open", sym.SymVerABIInternal) != nil
- }
+ iscgo = ctxt.LibraryByPkg["runtime/cgo"] != nil
+ ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil
// We now have enough information to determine the link mode.
determineLinkMode(ctxt)
- if ctxt.LinkMode == LinkExternal && !iscgo && ctxt.LibraryByPkg["runtime/cgo"] == nil && !(objabi.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && (ctxt.Arch.Family == sys.AMD64 || ctxt.Arch.Family == sys.I386)) {
+ if ctxt.LinkMode == LinkExternal && !iscgo && !(objabi.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && (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
// whether to initialize the TLS. So give it one. This could
// be handled differently but it's an unusual case.
- if lib := loadinternal(ctxt, "runtime/cgo"); lib != nil {
- if lib.Shlib != "" {
- ldshlibsyms(ctxt, lib.Shlib)
- } else {
- if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
- Exitf("cannot implicitly include runtime/cgo in a shared library")
- }
- loadobjfile(ctxt, lib)
+ if lib := loadinternal(ctxt, "runtime/cgo"); lib != nil && lib.Shlib == "" {
+ if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
+ Exitf("cannot implicitly include runtime/cgo in a shared library")
}
+ loadobjfile(ctxt, lib)
}
}
+ // Add non-package symbols and references of externally defined symbols.
+ ctxt.loader.LoadNonpkgSyms(ctxt.Syms)
+
+ // Load symbols from shared libraries, after all Go object symbols are loaded.
for _, lib := range ctxt.Library {
if lib.Shlib != "" {
if ctxt.Debugvlog > 1 {
@@ -461,63 +490,20 @@
}
}
- if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
- if *flagNewobj {
- // In newobj mode, we typically create sym.Symbols later therefore
- // also set cgo attributes later. However, for internal cgo linking,
- // the host object loaders still work with sym.Symbols (for now),
- // and they need cgo attributes set to work properly. So process
- // them now.
- lookup := func(name string, ver int) *sym.Symbol { return ctxt.loader.LookupOrCreate(name, ver, ctxt.Syms) }
- for _, d := range ctxt.cgodata {
- setCgoAttr(ctxt, lookup, d.file, d.pkg, d.directives)
- }
- ctxt.cgodata = nil
- }
-
- // Drop all the cgo_import_static declarations.
- // Turns out we won't be needing them.
- for _, s := range ctxt.Syms.Allsym {
- if s.Type == sym.SHOSTOBJ {
- // If a symbol was marked both
- // cgo_import_static and cgo_import_dynamic,
- // then we want to make it cgo_import_dynamic
- // now.
- if s.Extname() != "" && s.Dynimplib() != "" && !s.Attr.CgoExport() {
- s.Type = sym.SDYNIMPORT
- } else {
- s.Type = 0
- }
- }
- }
- }
+ // Process cgo directives (has to be done before host object loading).
+ ctxt.loadcgodirectives()
// Conditionally load host objects, or setup for external linking.
hostobjs(ctxt)
hostlinksetup(ctxt)
- if *flagNewobj {
- // Add references of externally defined symbols.
- ctxt.loader.LoadRefs(ctxt.Arch, ctxt.Syms)
- }
-
- // Now that we know the link mode, set the dynexp list.
- if !*flagNewobj { // set this later in newobj mode
- setupdynexp(ctxt)
- }
-
if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
// 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
- }
- }
+ undefs := ctxt.loader.UndefinedRelocTargets(1)
+ if len(undefs) > 0 {
+ any = true
}
if any {
if *flagLibGCC == "" {
@@ -561,9 +547,7 @@
importcycles()
- if *flagNewobj {
- strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
- }
+ strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
}
// Set up dynexp list.
@@ -596,19 +580,50 @@
ctxt.cgo_export_dynamic = nil
}
+// loadcgodirectives reads the previously discovered cgo directives, creating
+// symbols in preparation for host object loading or use later in the link.
+func (ctxt *Link) loadcgodirectives() {
+ l := ctxt.loader
+ hostObjSyms := make(map[loader.Sym]struct{})
+ for _, d := range ctxt.cgodata {
+ setCgoAttr(ctxt, ctxt.loader.LookupOrCreateSym, d.file, d.pkg, d.directives, hostObjSyms)
+ }
+ ctxt.cgodata = nil
+
+ if ctxt.LinkMode == LinkInternal {
+ // Drop all the cgo_import_static declarations.
+ // Turns out we won't be needing them.
+ for symIdx := range hostObjSyms {
+ if l.SymType(symIdx) == sym.SHOSTOBJ {
+ // If a symbol was marked both
+ // cgo_import_static and cgo_import_dynamic,
+ // then we want to make it cgo_import_dynamic
+ // now.
+ su := l.MakeSymbolUpdater(symIdx)
+ if l.SymExtname(symIdx) != "" && l.SymDynimplib(symIdx) != "" && !(l.AttrCgoExportStatic(symIdx) || l.AttrCgoExportDynamic(symIdx)) {
+ su.SetType(sym.SDYNIMPORT)
+ } else {
+ su.SetType(0)
+ }
+ }
+ }
+ }
+}
+
// Set up flags and special symbols depending on the platform build mode.
+// This version works with loader.Loader.
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)
+ symIdx := ctxt.loader.LookupOrCreateSym("runtime.islibrary", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(symIdx)
+ sb.SetType(sym.SNOPTRDATA)
+ sb.AddUint8(1)
case BuildModeCArchive:
- s := ctxt.Syms.Lookup("runtime.isarchive", 0)
- s.Type = sym.SNOPTRDATA
- s.Attr |= sym.AttrDuplicateOK
- s.AddUint8(1)
+ symIdx := ctxt.loader.LookupOrCreateSym("runtime.isarchive", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(symIdx)
+ sb.SetType(sym.SNOPTRDATA)
+ sb.AddUint8(1)
}
// Recalculate pe parameters now that we have ctxt.LinkMode set.
@@ -637,69 +652,77 @@
}
if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
- toc := ctxt.Syms.Lookup(".TOC.", 0)
- toc.Type = sym.SDYNIMPORT
+ toc := ctxt.loader.LookupOrCreateSym(".TOC.", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(toc)
+ sb.SetType(sym.SDYNIMPORT)
}
// The Android Q linker started to complain about underalignment of the our TLS
- // section. We don't actually use the section on android, so dont't
+ // section. We don't actually use the section on android, so don't
// generate it.
if objabi.GOOS != "android" {
- tlsg := ctxt.Syms.Lookup("runtime.tlsg", 0)
+ tlsg := ctxt.loader.LookupOrCreateSym("runtime.tlsg", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(tlsg)
// runtime.tlsg is used for external linking on platforms that do not define
// a variable to hold g in assembly (currently only intel).
- if tlsg.Type == 0 {
- tlsg.Type = sym.STLSBSS
- tlsg.Size = int64(ctxt.Arch.PtrSize)
- } else if tlsg.Type != sym.SDYNIMPORT {
- Errorf(nil, "runtime declared tlsg variable %v", tlsg.Type)
+ if sb.Type() == 0 {
+ sb.SetType(sym.STLSBSS)
+ sb.SetSize(int64(ctxt.Arch.PtrSize))
+ } else if sb.Type() != sym.SDYNIMPORT {
+ Errorf(nil, "runtime declared tlsg variable %v", sb.Type())
}
- tlsg.Attr |= sym.AttrReachable
- ctxt.Tlsg = tlsg
+ ctxt.loader.SetAttrReachable(tlsg, true)
+ ctxt.Tlsg2 = tlsg
}
- var moduledata *sym.Symbol
+ var moduledata loader.Sym
+ var mdsb *loader.SymbolBuilder
if ctxt.BuildMode == BuildModePlugin {
- moduledata = ctxt.Syms.Lookup("local.pluginmoduledata", 0)
- moduledata.Attr |= sym.AttrLocal
+ moduledata = ctxt.loader.LookupOrCreateSym("local.pluginmoduledata", 0)
+ mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
+ ctxt.loader.SetAttrLocal(moduledata, true)
} else {
- moduledata = ctxt.Syms.Lookup("runtime.firstmoduledata", 0)
+ moduledata = ctxt.loader.LookupOrCreateSym("runtime.firstmoduledata", 0)
+ mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
}
- if moduledata.Type != 0 && moduledata.Type != sym.SDYNIMPORT {
+ if mdsb.Type() != 0 && mdsb.Type() != sym.SDYNIMPORT {
// If the module (toolchain-speak for "executable or shared
// library") we are linking contains the runtime package, it
// will define the runtime.firstmoduledata symbol and we
// truncate it back to 0 bytes so we can define its entire
// contents in symtab.go:symtab().
- moduledata.Size = 0
+ mdsb.SetSize(0)
// In addition, on ARM, the runtime depends on the linker
// recording the value of GOARM.
if ctxt.Arch.Family == sys.ARM {
- s := ctxt.Syms.Lookup("runtime.goarm", 0)
- s.Type = sym.SDATA
- s.Size = 0
- s.AddUint8(uint8(objabi.GOARM))
+ goarm := ctxt.loader.LookupOrCreateSym("runtime.goarm", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(goarm)
+ sb.SetType(sym.SDATA)
+ sb.SetSize(0)
+ sb.AddUint8(uint8(objabi.GOARM))
}
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
- s := ctxt.Syms.Lookup("runtime.framepointer_enabled", 0)
- s.Type = sym.SDATA
- s.Size = 0
- s.AddUint8(1)
+ fpe := ctxt.loader.LookupOrCreateSym("runtime.framepointer_enabled", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(fpe)
+ sb.SetType(sym.SNOPTRDATA)
+ sb.SetSize(0)
+ sb.AddUint8(1)
}
} else {
// If OTOH the module does not contain the runtime package,
// create a local symbol for the moduledata.
- moduledata = ctxt.Syms.Lookup("local.moduledata", 0)
- moduledata.Attr |= sym.AttrLocal
+ moduledata = ctxt.loader.LookupOrCreateSym("local.moduledata", 0)
+ mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
+ ctxt.loader.SetAttrLocal(moduledata, true)
}
// In all cases way we mark the moduledata as noptrdata to hide it from
// the GC.
- moduledata.Type = sym.SNOPTRDATA
- moduledata.Attr |= sym.AttrReachable
- ctxt.Moduledata = moduledata
+ mdsb.SetType(sym.SNOPTRDATA)
+ ctxt.loader.SetAttrReachable(moduledata, true)
+ ctxt.Moduledata2 = moduledata
// If package versioning is required, generate a hash of the
// packages used in the link.
@@ -713,11 +736,25 @@
if ctxt.Arch == sys.Arch386 && ctxt.HeadType != objabi.Hwindows {
if (ctxt.BuildMode == BuildModeCArchive && ctxt.IsELF) || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE || ctxt.DynlinkingGo() {
- got := ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
- got.Type = sym.SDYNIMPORT
- got.Attr |= sym.AttrReachable
+ got := ctxt.loader.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(got)
+ sb.SetType(sym.SDYNIMPORT)
+ ctxt.loader.SetAttrReachable(got, true)
}
}
+
+ // DWARF-gen and other phases require that the unit Textp2 slices
+ // be populated, so that it can walk the functions in each unit.
+ // Call into the loader to do this (requires that we collect the
+ // set of internal libraries first). NB: might be simpler if we
+ // moved isRuntimeDepPkg to cmd/internal and then did the test in
+ // loader.AssignTextSymbolOrder.
+ ctxt.Library = postorder(ctxt.Library)
+ intlibs := []bool{}
+ for _, lib := range ctxt.Library {
+ intlibs = append(intlibs, isRuntimeDepPkg(lib.Pkg))
+ }
+ ctxt.Textp2 = ctxt.loader.AssignTextSymbolOrder(ctxt.Library, intlibs, ctxt.Textp2)
}
// mangleTypeSym shortens the names of symbols that represent Go types
@@ -741,7 +778,7 @@
for _, s := range ctxt.Syms.Allsym {
newName := typeSymbolMangle(s.Name)
if newName != s.Name {
- ctxt.Syms.Rename(s.Name, newName, int(s.Version), ctxt.Reachparent)
+ ctxt.Syms.Rename(s.Name, newName, int(s.Version))
}
}
}
@@ -1702,107 +1739,55 @@
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
if magic == 0x7f454c46 { // \x7F E L F
- if *flagNewobj {
- ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn, ehdr.flags)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ehdr.flags = flags
- ctxt.Textp = append(ctxt.Textp, textp...)
+ ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+ textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn, ehdr.flags)
+ if err != nil {
+ Errorf(nil, "%v", err)
+ return
}
- return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelf.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn, ehdr.flags)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ehdr.flags = flags
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
+ ehdr.flags = flags
+ ctxt.Textp2 = append(ctxt.Textp2, textp...)
}
+ return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
}
if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
- if *flagNewobj {
- ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
+ ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+ textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn)
+ if err != nil {
+ Errorf(nil, "%v", err)
+ return
}
- return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadmacho.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
+ ctxt.Textp2 = append(ctxt.Textp2, textp...)
}
+ return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
}
if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
- if *flagNewobj {
- ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- if rsrc != nil {
- setpersrc(ctxt, rsrc)
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
+ ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+ textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn)
+ if err != nil {
+ Errorf(nil, "%v", err)
+ return
}
- return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, rsrc, err := loadpe.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- if rsrc != nil {
- setpersrc(ctxt, rsrc)
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
+ if rsrc != 0 {
+ setpersrc(ctxt, rsrc)
}
- return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
+ ctxt.Textp2 = append(ctxt.Textp2, textp...)
}
+ return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
}
if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
- if *flagNewobj {
- ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
+ ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+ textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn)
+ if err != nil {
+ Errorf(nil, "%v", err)
+ return
}
- return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
- } else {
- ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, err := loadxcoff.LoadOld(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
- if err != nil {
- Errorf(nil, "%v", err)
- return
- }
- ctxt.Textp = append(ctxt.Textp, textp...)
- }
- return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
+ ctxt.Textp2 = append(ctxt.Textp2, textp...)
}
+ return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
}
/* check the header */
@@ -1887,24 +1872,7 @@
ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
f.MustSeek(import1, 0)
- flags := 0
- switch *FlagStrictDups {
- case 0:
- break
- case 1:
- flags = objfile.StrictDupsWarnFlag
- case 2:
- flags = objfile.StrictDupsErrFlag
- default:
- log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
- }
- var c int
- if *flagNewobj {
- ctxt.loader.Preload(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
+ ctxt.loader.Preload(ctxt.Syms, f, lib, unit, eof-f.Offset(), 0)
addImports(ctxt, lib, pn)
return nil
}
@@ -2045,7 +2013,7 @@
Errorf(nil, "cannot read symbols from shared library: %s", libpath)
return
}
- gcdataLocations := make(map[uint64]*sym.Symbol)
+ gcdataLocations := make(map[uint64]loader.Sym)
for _, elfsym := range syms {
if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
continue
@@ -2058,37 +2026,44 @@
ver = sym.SymVerABIInternal
}
- var lsym *sym.Symbol
- if *flagNewobj {
- i := ctxt.loader.AddExtSym(elfsym.Name, ver)
- if i == 0 {
- continue
- }
- lsym = ctxt.Syms.Newsym(elfsym.Name, ver)
- ctxt.loader.Syms[i] = lsym
- } else {
- lsym = ctxt.Syms.Lookup(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
- // "win").
- if lsym.Type != 0 && lsym.Type != sym.SDYNIMPORT {
+ l := ctxt.loader
+ s := l.LookupOrCreateSym(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 "win").
+ if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
continue
}
- lsym.Type = sym.SDYNIMPORT
- lsym.SetElfType(elf.ST_TYPE(elfsym.Info))
- lsym.Size = int64(elfsym.Size)
+ su := l.MakeSymbolUpdater(s)
+ su.SetType(sym.SDYNIMPORT)
+ l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
+ su.SetSize(int64(elfsym.Size))
if elfsym.Section != elf.SHN_UNDEF {
+ // If it's not undefined, mark the symbol as reachable
+ // so as to protect it from dead code elimination,
+ // even if there aren't any explicit references to it.
+ // Under the previous sym.Symbol based regime this
+ // wasn't necessary, but for the loader-based deadcode
+ // it is definitely needed.
+ //
+ // FIXME: have a more general/flexible mechanism for this?
+ //
+ l.SetAttrReachable(s, true)
+
// Set .File for the library that actually defines the symbol.
- lsym.File = libpath
+ l.SetSymFile(s, libpath)
+
// The decodetype_* functions in decodetype.go need access to
// the type data.
- if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
- lsym.P = readelfsymboldata(ctxt, f, &elfsym)
- gcdataLocations[elfsym.Value+2*uint64(ctxt.Arch.PtrSize)+8+1*uint64(ctxt.Arch.PtrSize)] = lsym
+ sname := l.SymName(s)
+ if strings.HasPrefix(sname, "type.") && !strings.HasPrefix(sname, "type..") {
+ su.SetData(readelfsymboldata(ctxt, f, &elfsym))
+ gcdataLocations[elfsym.Value+2*uint64(ctxt.Arch.PtrSize)+8+1*uint64(ctxt.Arch.PtrSize)] = s
}
}
+
// For function symbols, we don't know what ABI is
// available, so alias it under both ABIs.
//
@@ -2097,25 +2072,15 @@
// mangle Go function names in the .so to include the
// ABI.
if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
- var alias *sym.Symbol
- if *flagNewobj {
- i := ctxt.loader.AddExtSym(elfsym.Name, sym.SymVerABIInternal)
- if i == 0 {
- continue
- }
- alias = ctxt.Syms.Newsym(elfsym.Name, sym.SymVerABIInternal)
- ctxt.loader.Syms[i] = alias
- } else {
- alias = ctxt.Syms.Lookup(elfsym.Name, sym.SymVerABIInternal)
- }
- if alias.Type != 0 {
+ alias := ctxt.loader.LookupOrCreateSym(elfsym.Name, sym.SymVerABIInternal)
+ if l.SymType(alias) != 0 {
continue
}
- alias.Type = sym.SABIALIAS
- alias.R = []sym.Reloc{{Sym: lsym}}
+ su := l.MakeSymbolUpdater(alias)
+ su.SetType(sym.SABIALIAS)
+ su.AddReloc(loader.Reloc{Sym: s})
}
}
- gcdataAddresses := make(map[*sym.Symbol]uint64)
if ctxt.Arch.Family == sys.ARM64 {
for _, sect := range f.Sections {
if sect.Type == elf.SHT_RELA {
@@ -2133,15 +2098,12 @@
if t != elf.R_AARCH64_RELATIVE {
continue
}
- if lsym, ok := gcdataLocations[rela.Off]; ok {
- gcdataAddresses[lsym] = uint64(rela.Addend)
- }
}
}
}
}
- ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdataAddresses: gcdataAddresses})
+ ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
}
func addsection(arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
@@ -2155,16 +2117,11 @@
}
type chain struct {
- sym *sym.Symbol
+ sym loader.Sym
up *chain
limit int // limit on entry to sym
}
-var morestack *sym.Symbol
-
-// TODO: Record enough information in new object files to
-// allow stack checks here.
-
func haslinkregister(ctxt *Link) bool {
return ctxt.FixedFrameSize() != 0
}
@@ -2176,10 +2133,23 @@
return ctxt.Arch.RegSize
}
-func (ctxt *Link) dostkcheck() {
- var ch chain
+type stkChk struct {
+ ldr *loader.Loader
+ ctxt *Link
+ morestack loader.Sym
+ done loader.Bitmap
+}
- morestack = ctxt.Syms.Lookup("runtime.morestack", 0)
+// Walk the call tree and check that there is always enough stack space
+// for the call frames, especially for a chain of nosplit functions.
+func (ctxt *Link) dostkcheck() {
+ ldr := ctxt.loader
+ sc := stkChk{
+ ldr: ldr,
+ ctxt: ctxt,
+ morestack: ldr.Lookup("runtime.morestack", 0),
+ done: loader.MakeBitmap(ldr.NSym()),
+ }
// Every splitting function ensures that there are at least StackLimit
// bytes available below SP when the splitting prologue finishes.
@@ -2188,8 +2158,7 @@
// Check that every function behaves correctly with this amount
// of stack, following direct calls in order to piece together chains
// of non-splitting functions.
- ch.up = nil
-
+ var ch chain
ch.limit = objabi.StackLimit - callsize(ctxt)
if objabi.GOARCH == "arm64" {
// need extra 8 bytes below SP to save FP
@@ -2198,118 +2167,115 @@
// Check every function, but do the nosplit functions in a first pass,
// to make the printed failure chains as short as possible.
- for _, s := range ctxt.Textp {
- // runtime.racesymbolizethunk is called from gcc-compiled C
- // code running on the operating system thread stack.
- // It uses more than the usual amount of stack but that's okay.
- if s.Name == "runtime.racesymbolizethunk" {
- continue
- }
-
- if s.Attr.NoSplit() {
+ for _, s := range ctxt.Textp2 {
+ if ldr.IsNoSplit(s) {
ch.sym = s
- stkcheck(ctxt, &ch, 0)
+ sc.check(&ch, 0)
}
}
- for _, s := range ctxt.Textp {
- if !s.Attr.NoSplit() {
+ for _, s := range ctxt.Textp2 {
+ if !ldr.IsNoSplit(s) {
ch.sym = s
- stkcheck(ctxt, &ch, 0)
+ sc.check(&ch, 0)
}
}
}
-func stkcheck(ctxt *Link, up *chain, depth int) int {
+func (sc *stkChk) check(up *chain, depth int) int {
limit := up.limit
s := up.sym
+ ldr := sc.ldr
+ ctxt := sc.ctxt
// Don't duplicate work: only need to consider each
// function at top of safe zone once.
top := limit == objabi.StackLimit-callsize(ctxt)
if top {
- if s.Attr.StackCheck() {
+ if sc.done.Has(s) {
return 0
}
- s.Attr |= sym.AttrStackCheck
+ sc.done.Set(s)
}
if depth > 500 {
- Errorf(s, "nosplit stack check too deep")
- stkbroke(ctxt, up, 0)
+ sc.ctxt.Errorf(s, "nosplit stack check too deep")
+ sc.broke(up, 0)
return -1
}
- if s.Attr.External() || s.FuncInfo == nil {
+ if ldr.AttrExternal(s) {
// external function.
// should never be called directly.
// onlyctxt.Diagnose the direct caller.
// TODO(mwhudson): actually think about this.
// TODO(khr): disabled for now. Calls to external functions can only happen on the g0 stack.
// See the trampolines in src/runtime/sys_darwin_$ARCH.go.
- if depth == 1 && s.Type != sym.SXREF && !ctxt.DynlinkingGo() &&
- ctxt.BuildMode != BuildModeCArchive && ctxt.BuildMode != BuildModePIE && ctxt.BuildMode != BuildModeCShared && ctxt.BuildMode != BuildModePlugin {
- //Errorf(s, "call to external function")
- }
+ //if depth == 1 && ldr.SymType(s) != sym.SXREF && !ctxt.DynlinkingGo() &&
+ // ctxt.BuildMode != BuildModeCArchive && ctxt.BuildMode != BuildModePIE && ctxt.BuildMode != BuildModeCShared && ctxt.BuildMode != BuildModePlugin {
+ // Errorf(s, "call to external function")
+ //}
+ return -1
+ }
+ info := ldr.FuncInfo(s)
+ if !info.Valid() { // external function. see above.
return -1
}
if limit < 0 {
- stkbroke(ctxt, up, limit)
+ sc.broke(up, limit)
return -1
}
// morestack looks like it calls functions,
// but it switches the stack pointer first.
- if s == morestack {
+ if s == sc.morestack {
return 0
}
var ch chain
ch.up = up
- if !s.Attr.NoSplit() {
+ if !ldr.IsNoSplit(s) {
// Ensure we have enough stack to call morestack.
ch.limit = limit - callsize(ctxt)
- ch.sym = morestack
- if stkcheck(ctxt, &ch, depth+1) < 0 {
+ ch.sym = sc.morestack
+ if sc.check(&ch, depth+1) < 0 {
return -1
}
if !top {
return 0
}
// Raise limit to allow frame.
- locals := int32(0)
- if s.FuncInfo != nil {
- locals = s.FuncInfo.Locals
- }
+ locals := info.Locals()
limit = objabi.StackLimit + int(locals) + int(ctxt.FixedFrameSize())
}
// Walk through sp adjustments in function, consuming relocs.
- ri := 0
-
- endr := len(s.R)
+ relocs := ldr.Relocs(s)
var ch1 chain
pcsp := obj.NewPCIter(uint32(ctxt.Arch.MinLC))
- var r *sym.Reloc
- for pcsp.Init(s.FuncInfo.Pcsp.P); !pcsp.Done; pcsp.Next() {
+ for pcsp.Init(info.Pcsp()); !pcsp.Done; pcsp.Next() {
// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
// Check stack size in effect for this span.
if int32(limit)-pcsp.Value < 0 {
- stkbroke(ctxt, up, int(int32(limit)-pcsp.Value))
+ sc.broke(up, int(int32(limit)-pcsp.Value))
return -1
}
// Process calls in this span.
- for ; ri < endr && uint32(s.R[ri].Off) < pcsp.NextPC; ri++ {
- r = &s.R[ri]
+ for i := 0; i < relocs.Count; i++ {
+ r := relocs.At2(i)
+ if uint32(r.Off()) >= pcsp.NextPC {
+ break
+ }
+ t := r.Type()
switch {
- case r.Type.IsDirectCall():
+ case t.IsDirectCall():
ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
- ch.sym = r.Sym
- if stkcheck(ctxt, &ch, depth+1) < 0 {
+ ch.sym = r.Sym()
+ if sc.check(&ch, depth+1) < 0 {
return -1
}
@@ -2317,13 +2283,13 @@
// so we have to make sure it can call morestack.
// Arrange the data structures to report both calls, so that
// if there is an error, stkprint shows all the steps involved.
- case r.Type == objabi.R_CALLIND:
+ case t == objabi.R_CALLIND:
ch.limit = int(int32(limit) - pcsp.Value - int32(callsize(ctxt)))
- ch.sym = nil
+ ch.sym = 0
ch1.limit = ch.limit - callsize(ctxt) // for morestack in called prologue
ch1.up = &ch
- ch1.sym = morestack
- if stkcheck(ctxt, &ch1, depth+2) < 0 {
+ ch1.sym = sc.morestack
+ if sc.check(&ch1, depth+2) < 0 {
return -1
}
}
@@ -2333,17 +2299,18 @@
return 0
}
-func stkbroke(ctxt *Link, ch *chain, limit int) {
- Errorf(ch.sym, "nosplit stack overflow")
- stkprint(ctxt, ch, limit)
+func (sc *stkChk) broke(ch *chain, limit int) {
+ sc.ctxt.Errorf(ch.sym, "nosplit stack overflow")
+ sc.print(ch, limit)
}
-func stkprint(ctxt *Link, ch *chain, limit int) {
+func (sc *stkChk) print(ch *chain, limit int) {
+ ldr := sc.ldr
+ ctxt := sc.ctxt
var name string
-
- if ch.sym != nil {
- name = ch.sym.Name
- if ch.sym.Attr.NoSplit() {
+ if ch.sym != 0 {
+ name = ldr.SymName(ch.sym)
+ if ldr.IsNoSplit(ch.sym) {
name += " (nosplit)"
}
} else {
@@ -2351,14 +2318,14 @@
}
if ch.up == nil {
- // top of chain. ch->sym != nil.
- if ch.sym.Attr.NoSplit() {
+ // top of chain. ch.sym != 0.
+ if ldr.IsNoSplit(ch.sym) {
fmt.Printf("\t%d\tassumed on entry to %s\n", ch.limit, name)
} else {
fmt.Printf("\t%d\tguaranteed after split check in %s\n", ch.limit, name)
}
} else {
- stkprint(ctxt, ch.up, ch.limit+callsize(ctxt))
+ sc.print(ch.up, ch.limit+callsize(ctxt))
if !haslinkregister(ctxt) {
fmt.Printf("\t%d\ton entry to %s\n", ch.limit, name)
}
@@ -2706,34 +2673,19 @@
// Load full symbol contents, resolve indexed references.
ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms)
- // Pull the symbols out.
- ctxt.loader.ExtractSymbols(ctxt.Syms)
-
- // Load cgo directives.
- for _, d := range ctxt.cgodata {
- setCgoAttr(ctxt, ctxt.Syms.Lookup, d.file, d.pkg, d.directives)
+ // Convert ctxt.Moduledata2 to ctxt.Moduledata, etc
+ if ctxt.Moduledata2 != 0 {
+ ctxt.Moduledata = ctxt.loader.Syms[ctxt.Moduledata2]
+ ctxt.Tlsg = ctxt.loader.Syms[ctxt.Tlsg2]
}
+ // Pull the symbols out.
+ ctxt.loader.ExtractSymbols(ctxt.Syms, ctxt.Reachparent)
+ ctxt.lookup = ctxt.Syms.ROLookup
+
setupdynexp(ctxt)
- // Populate ctxt.Reachparent if appropriate.
- if ctxt.Reachparent != nil {
- for i := 0; i < len(ctxt.loader.Reachparent); i++ {
- p := ctxt.loader.Reachparent[i]
- if p == 0 {
- continue
- }
- if p == loader.Sym(i) {
- panic("self-cycle in reachparent")
- }
- sym := ctxt.loader.Syms[i]
- psym := ctxt.loader.Syms[p]
- ctxt.Reachparent[sym] = psym
- }
- }
-
- // Drop the reference.
- ctxt.loader = nil
+ // Drop the cgodata reference.
ctxt.cgodata = nil
addToTextp(ctxt)
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index 124f7d9..e867857 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -32,7 +32,6 @@
import (
"bufio"
- "cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
@@ -42,62 +41,51 @@
)
type Shlib struct {
- Path string
- Hash []byte
- Deps []string
- File *elf.File
- gcdataAddresses map[*sym.Symbol]uint64
+ Path string
+ Hash []byte
+ Deps []string
+ File *elf.File
}
// Link holds the context for writing object code from a compiler
// or for reading that input into the linker.
type Link struct {
+ Target
+ ErrorReporter
+ ArchSyms
Out *OutBuf
Syms *sym.Symbols
- Arch *sys.Arch
Debugvlog int
Bso *bufio.Writer
Loaded bool // set after all inputs have been loaded as symbols
- IsELF bool
- HeadType objabi.HeadType
-
- linkShared bool // link against installed Go shared libraries
- LinkMode LinkMode
- BuildMode BuildMode
- canUsePlugins bool // initialized when Loaded is set to true
compressDWARF bool
- Tlsg *sym.Symbol
+ Tlsg2 loader.Sym
Libdir []string
Library []*sym.Library
LibraryByPkg map[string]*sym.Library
Shlibs []Shlib
- Tlsoffset int
Textp []*sym.Symbol
+ Textp2 []loader.Sym
Filesyms []*sym.Symbol
Moduledata *sym.Symbol
+ Moduledata2 loader.Sym
PackageFile map[string]string
PackageShlib map[string]string
tramps []*sym.Symbol // trampolines
- // unresolvedSymSet is a set of erroneous unresolved references.
- // Used to avoid duplicated error messages.
- unresolvedSymSet map[unresolvedSymKey]bool
-
// Used to implement field tracking.
Reachparent map[*sym.Symbol]*sym.Symbol
compUnits []*sym.CompilationUnit // DWARF compilation units
runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen.
- relocbuf []byte // temporary buffer for applying relocations
-
loader *loader.Loader
cgodata []cgodata // cgo directives to load, three strings are args for loadcgo
@@ -111,48 +99,6 @@
directives [][]string
}
-type unresolvedSymKey struct {
- from *sym.Symbol // Symbol that referenced unresolved "to"
- to *sym.Symbol // Unresolved symbol referenced by "from"
-}
-
-// ErrorUnresolved prints unresolved symbol error for r.Sym that is referenced from s.
-func (ctxt *Link) ErrorUnresolved(s *sym.Symbol, r *sym.Reloc) {
- if ctxt.unresolvedSymSet == nil {
- ctxt.unresolvedSymSet = make(map[unresolvedSymKey]bool)
- }
-
- k := unresolvedSymKey{from: s, to: r.Sym}
- if !ctxt.unresolvedSymSet[k] {
- ctxt.unresolvedSymSet[k] = true
-
- // Try to find symbol under another ABI.
- var reqABI, haveABI obj.ABI
- haveABI = ^obj.ABI(0)
- reqABI, ok := sym.VersionToABI(int(r.Sym.Version))
- if ok {
- for abi := obj.ABI(0); abi < obj.ABICount; abi++ {
- v := sym.ABIToVersion(abi)
- if v == -1 {
- continue
- }
- if rs := ctxt.Syms.ROLookup(r.Sym.Name, v); rs != nil && rs.Type != sym.Sxxx {
- haveABI = abi
- }
- }
- }
-
- // Give a special error message for main symbol (see #24809).
- if r.Sym.Name == "main.main" {
- Errorf(s, "function main is undeclared in the main package")
- } else if haveABI != ^obj.ABI(0) {
- Errorf(s, "relocation target %s not defined for %s (but is defined for %s)", r.Sym.Name, reqABI, haveABI)
- } else {
- Errorf(s, "relocation target %s not defined", r.Sym.Name)
- }
- }
-}
-
// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index e50eddd..3f45cc0 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -428,42 +428,49 @@
}
// empirically, string table must begin with " \x00".
- s := ctxt.Syms.Lookup(".machosymstr", 0)
+ s := ctxt.loader.LookupOrCreateSym(".machosymstr", 0)
+ sb := ctxt.loader.MakeSymbolUpdater(s)
- s.Type = sym.SMACHOSYMSTR
- s.Attr |= sym.AttrReachable
- s.AddUint8(' ')
- s.AddUint8('\x00')
+ sb.SetType(sym.SMACHOSYMSTR)
+ sb.SetReachable(true)
+ sb.AddUint8(' ')
+ sb.AddUint8('\x00')
- s = ctxt.Syms.Lookup(".machosymtab", 0)
- s.Type = sym.SMACHOSYMTAB
- s.Attr |= sym.AttrReachable
+ s = ctxt.loader.LookupOrCreateSym(".machosymtab", 0)
+ sb = ctxt.loader.MakeSymbolUpdater(s)
+ sb.SetType(sym.SMACHOSYMTAB)
+ sb.SetReachable(true)
- if ctxt.LinkMode != LinkExternal {
- s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub
- s.Type = sym.SMACHOPLT
- s.Attr |= sym.AttrReachable
+ if ctxt.IsInternal() {
+ s = ctxt.loader.LookupOrCreateSym(".plt", 0) // will be __symbol_stub
+ sb = ctxt.loader.MakeSymbolUpdater(s)
+ sb.SetType(sym.SMACHOPLT)
+ sb.SetReachable(true)
- s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr
- s.Type = sym.SMACHOGOT
- s.Attr |= sym.AttrReachable
- s.Align = 4
+ s = ctxt.loader.LookupOrCreateSym(".got", 0) // will be __nl_symbol_ptr
+ sb = ctxt.loader.MakeSymbolUpdater(s)
+ sb.SetType(sym.SMACHOGOT)
+ sb.SetReachable(true)
+ sb.SetAlign(4)
- s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt
- s.Type = sym.SMACHOINDIRECTPLT
- s.Attr |= sym.AttrReachable
+ s = ctxt.loader.LookupOrCreateSym(".linkedit.plt", 0) // indirect table for .plt
+ sb = ctxt.loader.MakeSymbolUpdater(s)
+ sb.SetType(sym.SMACHOINDIRECTPLT)
+ sb.SetReachable(true)
- s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got
- s.Type = sym.SMACHOINDIRECTGOT
- s.Attr |= sym.AttrReachable
+ s = ctxt.loader.LookupOrCreateSym(".linkedit.got", 0) // indirect table for .got
+ sb = ctxt.loader.MakeSymbolUpdater(s)
+ sb.SetType(sym.SMACHOINDIRECTGOT)
+ sb.SetReachable(true)
}
// Add a dummy symbol that will become the __asm marker section.
- if ctxt.LinkMode == LinkExternal {
- s := ctxt.Syms.Lookup(".llvmasm", 0)
- s.Type = sym.SMACHO
- s.Attr |= sym.AttrReachable
- s.AddUint8(0)
+ if ctxt.IsExternal() {
+ s = ctxt.loader.LookupOrCreateSym(".llvmasm", 0)
+ sb = ctxt.loader.MakeSymbolUpdater(s)
+ sb.SetType(sym.SMACHO)
+ sb.SetReachable(true)
+ sb.AddUint8(0)
}
}
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 9f9395b..c3b7295 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -34,6 +34,7 @@
"bufio"
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/benchmark"
"cmd/link/internal/sym"
"flag"
"log"
@@ -87,8 +88,6 @@
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`")
flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
@@ -96,6 +95,9 @@
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
memprofile = flag.String("memprofile", "", "write memory profile to `file`")
memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
+
+ benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
+ benchmarkFileFlag = flag.String("benchmarkprofile", "", "set to enable per-phase pprof profiling")
)
// Main is the main entry point for the linker code.
@@ -170,13 +172,29 @@
interpreter = *flagInterpreter
+ // enable benchmarking
+ var bench *benchmark.Metrics
+ if len(*benchmarkFlag) != 0 {
+ if *benchmarkFlag == "mem" {
+ bench = benchmark.New(benchmark.GC, *benchmarkFileFlag)
+ } else if *benchmarkFlag == "cpu" {
+ bench = benchmark.New(benchmark.NoGC, *benchmarkFileFlag)
+ } else {
+ Errorf(nil, "unknown benchmark flag: %q", *benchmarkFlag)
+ usage()
+ }
+ }
+
+ bench.Start("libinit")
libinit(ctxt) // creates outfile
if ctxt.HeadType == objabi.Hunknown {
ctxt.HeadType.Set(objabi.GOOS)
}
+ bench.Start("computeTLSOffset")
ctxt.computeTLSOffset()
+ bench.Start("Archinit")
thearch.Archinit(ctxt)
if ctxt.linkShared && !ctxt.IsELF {
@@ -207,47 +225,83 @@
default:
addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "")
}
+ bench.Start("loadlib")
ctxt.loadlib()
+ bench.Start("deadcode")
deadcode(ctxt)
- if *flagNewobj {
- ctxt.loadlibfull() // XXX do it here for now
- }
- ctxt.linksetup()
- ctxt.dostrdata()
- dwarfGenerateDebugInfo(ctxt)
+ bench.Start("linksetup")
+ ctxt.linksetup()
+
+ bench.Start("dostrdata")
+ ctxt.dostrdata()
if objabi.Fieldtrack_enabled != 0 {
- fieldtrack(ctxt)
+ bench.Start("fieldtrack")
+ fieldtrack(ctxt.Arch, ctxt.loader)
}
- ctxt.mangleTypeSym()
+
+ bench.Start("dwarfGenerateDebugInfo")
+ dwarfGenerateDebugInfo(ctxt)
+
+ bench.Start("callgraph")
ctxt.callgraph()
- ctxt.doelf()
- if ctxt.HeadType == objabi.Hdarwin {
+ bench.Start("dostkcheck")
+ ctxt.dostkcheck()
+
+ if ctxt.IsELF {
+ bench.Start("doelf")
+ ctxt.doelf()
+ }
+ if ctxt.IsDarwin() {
+ bench.Start("domacho")
ctxt.domacho()
}
- ctxt.dostkcheck()
- if ctxt.HeadType == objabi.Hwindows {
+ if ctxt.IsWindows() {
+ bench.Start("dope")
ctxt.dope()
- ctxt.windynrelocsyms()
}
- if ctxt.HeadType == objabi.Haix {
+ bench.Start("loadlibfull")
+ ctxt.loadlibfull() // XXX do it here for now
+ if ctxt.IsAIX() {
+ bench.Start("doxcoff")
ctxt.doxcoff()
}
+ if ctxt.IsWindows() {
+ bench.Start("windynrelocsyms")
+ ctxt.windynrelocsyms()
+ }
+ bench.Start("mangleTypeSym")
+ ctxt.mangleTypeSym()
+
+ ctxt.setArchSyms()
+ bench.Start("addexport")
ctxt.addexport()
+ bench.Start("Gentext")
thearch.Gentext(ctxt) // trampolines, call stubs, etc.
+ bench.Start("textbuildid")
ctxt.textbuildid()
+ bench.Start("textaddress")
ctxt.textaddress()
+ bench.Start("pclntab")
ctxt.pclntab()
+ bench.Start("findfunctab")
ctxt.findfunctab()
+ bench.Start("typelink")
ctxt.typelink()
+ bench.Start("symtab")
ctxt.symtab()
+ bench.Start("buildinfo")
ctxt.buildinfo()
+ bench.Start("dodata")
ctxt.dodata()
+ bench.Start("address")
order := ctxt.address()
+ bench.Start("dwarfcompress")
dwarfcompress(ctxt)
+ bench.Start("layout")
filesize := ctxt.layout(order)
// Write out the output file.
@@ -266,25 +320,36 @@
if outputMmapped {
// Asmb will redirect symbols to the output file mmap, and relocations
// will be applied directly there.
+ bench.Start("Asmb")
thearch.Asmb(ctxt)
+ bench.Start("reloc")
ctxt.reloc()
+ bench.Start("Munmap")
ctxt.Out.Munmap()
} else {
// If we don't mmap, we need to apply relocations before
// writing out.
+ bench.Start("reloc")
ctxt.reloc()
+ bench.Start("Asmb")
thearch.Asmb(ctxt)
}
+ bench.Start("Asmb2")
thearch.Asmb2(ctxt)
+ bench.Start("undef")
ctxt.undef()
+ bench.Start("hostlink")
ctxt.hostlink()
if ctxt.Debugvlog != 0 {
ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
ctxt.Logf("%d liveness data\n", liveness)
}
+ bench.Start("Flush")
ctxt.Bso.Flush()
+ bench.Start("archive")
ctxt.archive()
+ bench.Report(os.Stdout)
errorexit()
}
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index f775132..fdfb996 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -10,6 +10,7 @@
import (
"cmd/internal/objabi"
"cmd/internal/sys"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/pe"
"encoding/binary"
@@ -237,7 +238,7 @@
}
type Imp struct {
- s *sym.Symbol
+ s loader.Sym
off uint64
next *Imp
argsize int
@@ -252,13 +253,13 @@
}
var (
- rsrcsym *sym.Symbol
+ rsrcsym loader.Sym
PESECTHEADR int32
PEFILEHEADR int32
pe64 int
dr *Dll
- dexport [1024]*sym.Symbol
- nexport int
+
+ dexport = make([]loader.Sym, 0, 1024)
)
// peStringTable is a COFF string table.
@@ -957,8 +958,15 @@
if ctxt.LinkMode == LinkInternal {
// some mingw libs depend on this symbol, for example, FindPESectionByName
- ctxt.xdefine("__image_base__", sym.SDATA, PEBASE)
- ctxt.xdefine("_image_base__", sym.SDATA, PEBASE)
+ for _, name := range [2]string{"__image_base__", "_image_base__"} {
+ s := ctxt.loader.LookupOrCreateSym(name, 0)
+ sb := ctxt.loader.MakeSymbolUpdater(s)
+ sb.SetType(sym.SDATA)
+ sb.SetValue(PEBASE)
+ ctxt.loader.SetAttrReachable(s, true)
+ ctxt.loader.SetAttrSpecial(s, true)
+ ctxt.loader.SetAttrLocal(s, true)
+ }
}
HEADR = PEFILEHEADR
@@ -996,16 +1004,18 @@
}
func initdynimport(ctxt *Link) *Dll {
+ ldr := ctxt.loader
var d *Dll
dr = nil
var m *Imp
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.Reachable() || s.Type != sym.SDYNIMPORT {
+ for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
+ if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
continue
}
+ dynlib := ldr.SymDynimplib(s)
for d = dr; d != nil; d = d.next {
- if d.name == s.Dynimplib() {
+ if d.name == dynlib {
m = new(Imp)
break
}
@@ -1013,7 +1023,7 @@
if d == nil {
d = new(Dll)
- d.name = s.Dynimplib()
+ d.name = dynlib
d.next = dr
dr = d
m = new(Imp)
@@ -1024,15 +1034,15 @@
// of uinptrs this function consumes. Store the argsize and discard
// the %n suffix if any.
m.argsize = -1
- extName := s.Extname()
+ extName := ldr.SymExtname(s)
if i := strings.IndexByte(extName, '%'); i >= 0 {
var err error
m.argsize, err = strconv.Atoi(extName[i+1:])
if err != nil {
- Errorf(s, "failed to parse stdcall decoration: %v", err)
+ ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
}
m.argsize *= ctxt.Arch.PtrSize
- s.SetExtname(extName[:i])
+ ldr.SetSymExtname(s, extName[:i])
}
m.s = s
@@ -1040,42 +1050,38 @@
d.ms = m
}
- if ctxt.LinkMode == LinkExternal {
+ if ctxt.IsExternal() {
// Add real symbol name
for d := dr; d != nil; d = d.next {
for m = d.ms; m != nil; m = m.next {
- m.s.Type = sym.SDATA
- m.s.Grow(int64(ctxt.Arch.PtrSize))
- dynName := m.s.Extname()
+ sb := ldr.MakeSymbolUpdater(m.s)
+ sb.SetType(sym.SDATA)
+ sb.Grow(int64(ctxt.Arch.PtrSize))
+ dynName := sb.Extname()
// only windows/386 requires stdcall decoration
- if ctxt.Arch.Family == sys.I386 && m.argsize >= 0 {
+ if ctxt.Is386() && m.argsize >= 0 {
dynName += fmt.Sprintf("@%d", m.argsize)
}
- dynSym := ctxt.Syms.Lookup(dynName, 0)
- dynSym.Attr |= sym.AttrReachable
- dynSym.Type = sym.SHOSTOBJ
- r := m.s.AddRel()
- r.Sym = dynSym
- r.Off = 0
- r.Siz = uint8(ctxt.Arch.PtrSize)
- r.Type = objabi.R_ADDR
+ dynSym := ldr.CreateSymForUpdate(dynName, 0)
+ dynSym.SetReachable(true)
+ dynSym.SetType(sym.SHOSTOBJ)
+ sb.AddReloc(loader.Reloc{Sym: dynSym.Sym(), Type: objabi.R_ADDR, Off: 0, Size: uint8(ctxt.Arch.PtrSize)})
}
}
} else {
- dynamic := ctxt.Syms.Lookup(".windynamic", 0)
- dynamic.Attr |= sym.AttrReachable
- dynamic.Type = sym.SWINDOWS
+ dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
+ dynamic.SetReachable(true)
+ dynamic.SetType(sym.SWINDOWS)
for d := dr; d != nil; d = d.next {
for m = d.ms; m != nil; m = m.next {
- m.s.Type = sym.SWINDOWS
- m.s.Attr |= sym.AttrSubSymbol
- m.s.Sub = dynamic.Sub
- dynamic.Sub = m.s
- m.s.Value = dynamic.Size
- dynamic.Size += int64(ctxt.Arch.PtrSize)
+ sb := ldr.MakeSymbolUpdater(m.s)
+ sb.SetType(sym.SWINDOWS)
+ dynamic.PrependSub(m.s)
+ sb.SetValue(dynamic.Size())
+ dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
}
- dynamic.Size += int64(ctxt.Arch.PtrSize)
+ dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
}
}
@@ -1095,6 +1101,7 @@
}
func addimports(ctxt *Link, datsect *peSection) {
+ ldr := ctxt.loader
startoff := ctxt.Out.Offset()
dynamic := ctxt.Syms.Lookup(".windynamic", 0)
@@ -1117,7 +1124,7 @@
for m := d.ms; m != nil; m = m.next {
m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
ctxt.Out.Write16(0) // hint
- strput(ctxt.Out, m.s.Extname())
+ strput(ctxt.Out, ldr.SymExtname(m.s))
}
}
@@ -1198,36 +1205,31 @@
out.SeekSet(endoff)
}
-type byExtname []*sym.Symbol
-
-func (s byExtname) Len() int { return len(s) }
-func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s byExtname) Less(i, j int) bool { return s[i].Extname() < s[j].Extname() }
-
func initdynexport(ctxt *Link) {
- nexport = 0
- for _, s := range ctxt.Syms.Allsym {
- if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() {
+ ldr := ctxt.loader
+ for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
+ if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
continue
}
- if nexport+1 > len(dexport) {
- Errorf(s, "pe dynexport table is full")
+ if len(dexport)+1 > cap(dexport) {
+ ctxt.Errorf(s, "pe dynexport table is full")
errorexit()
}
- dexport[nexport] = s
- nexport++
+ dexport = append(dexport, s)
}
- sort.Sort(byExtname(dexport[:nexport]))
+ sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
}
func addexports(ctxt *Link) {
+ ldr := ctxt.loader
var e IMAGE_EXPORT_DIRECTORY
+ nexport := len(dexport)
size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
- for i := 0; i < nexport; i++ {
- size += len(dexport[i].Extname()) + 1
+ for _, s := range dexport {
+ size += len(ldr.Syms[s].Extname()) + 1
}
if nexport == 0 {
@@ -1262,16 +1264,16 @@
binary.Write(out, binary.LittleEndian, &e)
// put EXPORT Address Table
- for i := 0; i < nexport; i++ {
- out.Write32(uint32(dexport[i].Value - PEBASE))
+ for _, s := range dexport {
+ out.Write32(uint32(ldr.Syms[s].Value - PEBASE))
}
// put EXPORT Name Pointer Table
v := int(e.Name + uint32(len(*flagOutfile)) + 1)
- for i := 0; i < nexport; i++ {
+ for _, s := range dexport {
out.Write32(uint32(v))
- v += len(dexport[i].Extname()) + 1
+ v += len(ldr.Syms[s].Extname()) + 1
}
// put EXPORT Ordinal Table
@@ -1282,8 +1284,9 @@
// put Names
out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
- for i := 0; i < nexport; i++ {
- out.WriteStringN(dexport[i].Extname(), len(dexport[i].Extname())+1)
+ for _, s := range dexport {
+ ss := ldr.Syms[s]
+ out.WriteStringN(ss.Extname(), len(ss.Extname())+1)
}
sect.pad(out, uint32(size))
}
@@ -1455,27 +1458,30 @@
initdynexport(ctxt)
}
-func setpersrc(ctxt *Link, sym *sym.Symbol) {
- if rsrcsym != nil {
- Errorf(sym, "too many .rsrc sections")
+func setpersrc(ctxt *Link, sym loader.Sym) {
+ if rsrcsym != 0 {
+ Errorf(nil, "too many .rsrc sections")
}
rsrcsym = sym
}
func addpersrc(ctxt *Link) {
- if rsrcsym == nil {
+ if rsrcsym == 0 {
return
}
- h := pefile.addSection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
+ data := ctxt.loader.Data(rsrcsym)
+ size := len(data)
+ h := pefile.addSection(".rsrc", size, size)
h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
h.checkOffset(ctxt.Out.Offset())
// relocation
- for ri := range rsrcsym.R {
- r := &rsrcsym.R[ri]
- p := rsrcsym.P[r.Off:]
+ relocs := ctxt.loader.Relocs(rsrcsym)
+ for i := 0; i < relocs.Count; i++ {
+ r := relocs.At(i)
+ p := data[r.Off:]
val := uint32(int64(h.virtualAddress) + r.Add)
// 32-bit little-endian
@@ -1486,8 +1492,8 @@
p[3] = byte(val >> 24)
}
- ctxt.Out.Write(rsrcsym.P)
- h.pad(ctxt.Out, uint32(rsrcsym.Size))
+ ctxt.Out.Write(data)
+ h.pad(ctxt.Out, uint32(size))
// update data directory
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index eb48ac8..62e6af2 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -40,9 +40,9 @@
func linknew(arch *sys.Arch) *Link {
ctxt := &Link{
+ Target: Target{Arch: arch},
Syms: sym.NewSymbols(),
Out: &OutBuf{arch: arch},
- Arch: arch,
LibraryByPkg: make(map[string]*sym.Library),
}
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index bba623e..b6734f6 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -326,12 +326,11 @@
}
func (ctxt *Link) symtab() {
- switch ctxt.BuildMode {
- case BuildModeCArchive, BuildModeCShared:
- for _, s := range ctxt.Syms.Allsym {
- // Create a new entry in the .init_array section that points to the
- // library initializer function.
- if s.Name == *flagEntrySymbol && ctxt.HeadType != objabi.Haix {
+ if ctxt.HeadType != objabi.Haix {
+ switch ctxt.BuildMode {
+ case BuildModeCArchive, BuildModeCShared:
+ s := ctxt.Syms.ROLookup(*flagEntrySymbol, sym.SymVerABI0)
+ if s != nil {
addinitarrdata(ctxt, s)
}
}
diff --git a/src/cmd/link/internal/ld/target.go b/src/cmd/link/internal/ld/target.go
new file mode 100644
index 0000000..197c412
--- /dev/null
+++ b/src/cmd/link/internal/ld/target.go
@@ -0,0 +1,133 @@
+// Copyright 2020 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"
+ "encoding/binary"
+)
+
+// Target holds the configuration we're building for.
+type Target struct {
+ Arch *sys.Arch
+
+ HeadType objabi.HeadType
+
+ LinkMode LinkMode
+ BuildMode BuildMode
+
+ linkShared bool
+ canUsePlugins bool
+ IsELF bool
+}
+
+//
+// Target type functions
+//
+
+func (t *Target) IsShared() bool {
+ return t.BuildMode == BuildModeShared
+}
+
+func (t *Target) IsPlugin() bool {
+ return t.BuildMode == BuildModePlugin
+}
+
+func (t *Target) IsInternal() bool {
+ return t.LinkMode == LinkInternal
+}
+
+func (t *Target) IsExternal() bool {
+ return t.LinkMode == LinkExternal
+}
+
+func (t *Target) IsPIE() bool {
+ return t.BuildMode == BuildModePIE
+}
+
+func (t *Target) IsSharedGoLink() bool {
+ return t.linkShared
+}
+
+func (t *Target) CanUsePlugins() bool {
+ return t.canUsePlugins
+}
+
+func (t *Target) IsElf() bool {
+ return t.IsELF
+}
+
+func (t *Target) IsDynlinkingGo() bool {
+ return t.IsShared() || t.IsSharedGoLink() || t.IsPlugin() || t.CanUsePlugins()
+}
+
+//
+// Processor functions
+//
+
+func (t *Target) Is386() bool {
+ return t.Arch.Family == sys.I386
+}
+
+func (t *Target) IsARM() bool {
+ return t.Arch.Family == sys.ARM
+}
+
+func (t *Target) IsAMD64() bool {
+ return t.Arch.Family == sys.AMD64
+}
+
+func (t *Target) IsPPC64() bool {
+ return t.Arch.Family == sys.PPC64
+}
+
+func (t *Target) IsS390X() bool {
+ return t.Arch.Family == sys.S390X
+}
+
+//
+// OS Functions
+//
+
+func (t *Target) IsLinux() bool {
+ return t.HeadType == objabi.Hlinux
+}
+
+func (t *Target) IsDarwin() bool {
+ return t.HeadType == objabi.Hdarwin
+}
+
+func (t *Target) IsWindows() bool {
+ return t.HeadType == objabi.Hwindows
+}
+
+func (t *Target) IsPlan9() bool {
+ return t.HeadType == objabi.Hplan9
+}
+
+func (t *Target) IsAIX() bool {
+ return t.HeadType == objabi.Haix
+}
+
+func (t *Target) IsSolaris() bool {
+ return t.HeadType == objabi.Hsolaris
+}
+
+func (t *Target) IsNetbsd() bool {
+ return t.HeadType == objabi.Hnetbsd
+}
+
+func (t *Target) IsOpenbsd() bool {
+ return t.HeadType == objabi.Hopenbsd
+}
+
+//
+// MISC
+//
+
+func (t *Target) IsBigEndian() bool {
+ return t.Arch.ByteOrder == binary.BigEndian
+}
diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
index 9d236db..9f257b8 100644
--- a/src/cmd/link/internal/ld/util.go
+++ b/src/cmd/link/internal/ld/util.go
@@ -5,6 +5,7 @@
package ld
import (
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"encoding/binary"
"fmt"
@@ -38,6 +39,18 @@
Exit(2)
}
+// afterErrorAction updates 'nerrors' on error and invokes exit or
+// panics in the proper circumstances.
+func afterErrorAction() {
+ nerrors++
+ if *flagH {
+ panic("error")
+ }
+ if nerrors > 20 {
+ Exitf("too many errors")
+ }
+}
+
// Errorf logs an error message.
//
// If more than 20 errors have been printed, exit with an error.
@@ -50,13 +63,25 @@
}
format += "\n"
fmt.Fprintf(os.Stderr, format, args...)
- nerrors++
- if *flagH {
- panic("error")
+ afterErrorAction()
+}
+
+// Errorf method logs an error message.
+//
+// If more than 20 errors have been printed, exit with an error.
+//
+// Logging an error means that on exit cmd/link will delete any
+// output file and return a non-zero error code.
+func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) {
+ if s != 0 && ctxt.loader != nil {
+ sn := ctxt.loader.SymName(s)
+ format = sn + ": " + format
+ } else {
+ format = fmt.Sprintf("sym %d: %s", s, format)
}
- if nerrors > 20 {
- Exitf("too many errors")
- }
+ format += "\n"
+ fmt.Fprintf(os.Stderr, format, args...)
+ afterErrorAction()
}
func artrim(x []byte) string {
diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go
index 8814bad..55a404c 100644
--- a/src/cmd/link/internal/ld/xcoff.go
+++ b/src/cmd/link/internal/ld/xcoff.go
@@ -1096,8 +1096,8 @@
// Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
// This relocation will be made by the loader.
-func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool {
- if ctxt.LinkMode == LinkExternal {
+func Xcoffadddynrel(target *Target, s *sym.Symbol, r *sym.Reloc) bool {
+ if target.IsExternal() {
return true
}
if s.Type <= sym.SPCLNTAB {
@@ -1186,7 +1186,7 @@
if ctxt.LinkMode == LinkExternal {
// Change rt0_go name to match name in runtime/cgo:main().
rt0 := ctxt.Syms.ROLookup("runtime.rt0_go", 0)
- ctxt.Syms.Rename(rt0.Name, "runtime_rt0_go", 0, ctxt.Reachparent)
+ ctxt.Syms.Rename(rt0.Name, "runtime_rt0_go", 0)
for _, s := range ctxt.Syms.Allsym {
if !s.Attr.CgoExport() {
@@ -1198,7 +1198,7 @@
// On AIX, a exported function must have two symbols:
// - a .text symbol which must start with a ".".
// - a .data symbol which is a function descriptor.
- ctxt.Syms.Rename(s.Name, "."+name, 0, ctxt.Reachparent)
+ ctxt.Syms.Rename(s.Name, "."+name, 0)
desc := ctxt.Syms.Lookup(name, 0)
desc.Type = sym.SNOPTRDATA
diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go
index 1962d76..2eabefd 100644
--- a/src/cmd/link/internal/loadelf/ldelf.go
+++ b/src/cmd/link/internal/loadelf/ldelf.go
@@ -1,4 +1,4 @@
-// Copyright 2017 The Go Authors. All rights reserved.
+// 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.
@@ -270,19 +270,20 @@
}
type ElfSect struct {
- name string
- nameoff uint32
- type_ uint32
- flags uint64
- addr uint64
- off uint64
- size uint64
- link uint32
- info uint32
- align uint64
- entsize uint64
- base []byte
- sym *sym.Symbol
+ name string
+ nameoff uint32
+ type_ uint32
+ flags uint64
+ addr uint64
+ off uint64
+ size uint64
+ link uint32
+ info uint32
+ align uint64
+ entsize uint64
+ base []byte
+ readOnlyMem bool // Is this section in readonly memory?
+ sym loader.Sym
}
type ElfObj struct {
@@ -320,7 +321,7 @@
type_ uint8
other uint8
shndx uint16
- sym *sym.Symbol
+ sym loader.Sym
}
var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
@@ -452,32 +453,22 @@
return found, ehdrFlags, nil
}
-func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
- newSym := func(name string, version int) *sym.Symbol {
- return l.Create(name, syms)
- }
- lookup := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version, syms)
- }
- return load(arch, syms.IncVersion(), newSym, lookup, f, pkg, length, pn, flags)
-}
-
-func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
- return load(arch, syms.IncVersion(), syms.Newsym, syms.Lookup, f, pkg, length, pn, flags)
-}
-
-type lookupFunc func(string, int) *sym.Symbol
-
-// load loads the ELF file pn from f.
-// Symbols are written into syms, and a slice of the text symbols is returned.
+// Load loads the ELF file pn from f.
+// Symbols are installed into the loader, and a slice of the text symbols is returned.
//
// On ARM systems, Load will attempt to determine what ELF header flags to
// emit by scanning the attributes in the ELF file being loaded. The
// parameter initEhdrFlags contains the current header flags for the output
// object, and the returned ehdrFlags contains what this Load function computes.
// TODO: find a better place for this logic.
-func load(arch *sys.Arch, localSymVersion int, newSym, lookup lookupFunc, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
- errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) {
+func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []loader.Sym, ehdrFlags uint32, err error) {
+ newSym := func(name string, version int) loader.Sym {
+ return l.CreateExtSym(name)
+ }
+ lookup := func(name string, version int) loader.Sym {
+ return l.LookupOrCreateSym(name, version)
+ }
+ errorf := func(str string, args ...interface{}) ([]loader.Sym, uint32, error) {
return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
}
@@ -610,7 +601,6 @@
sect := &elfobj.sect[i]
if is64 != 0 {
var b ElfSectBytes64
-
if err := binary.Read(f, e, &b); err != nil {
return errorf("malformed elf file: %v", err)
}
@@ -731,46 +721,47 @@
}
sectsymNames[name] = true
- s := lookup(name, localSymVersion)
+ sb := l.MakeSymbolUpdater(lookup(name, localSymVersion))
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
default:
return errorf("%s: unexpected flags for ELF section %s", pn, sect.name)
case ElfSectFlagAlloc:
- s.Type = sym.SRODATA
+ sb.SetType(sym.SRODATA)
case ElfSectFlagAlloc + ElfSectFlagWrite:
if sect.type_ == ElfSectNobits {
- s.Type = sym.SNOPTRBSS
+ sb.SetType(sym.SNOPTRBSS)
} else {
- s.Type = sym.SNOPTRDATA
+ sb.SetType(sym.SNOPTRDATA)
}
case ElfSectFlagAlloc + ElfSectFlagExec:
- s.Type = sym.STEXT
+ sb.SetType(sym.STEXT)
}
if sect.name == ".got" || sect.name == ".toc" {
- s.Type = sym.SELFGOT
+ sb.SetType(sym.SELFGOT)
}
if sect.type_ == ElfSectProgbits {
- s.P = sect.base
- s.P = s.P[:sect.size]
+ sb.SetData(sect.base[:sect.size])
}
- s.Size = int64(sect.size)
- s.Align = int32(sect.align)
- sect.sym = s
+ sb.SetSize(int64(sect.size))
+ sb.SetAlign(int32(sect.align))
+ sb.SetReadOnly(sect.readOnlyMem)
+
+ sect.sym = sb.Sym()
}
// enter sub-symbols into symbol table.
// symbol 0 is the null symbol.
- symbols := make([]*sym.Symbol, elfobj.nsymtab)
+ symbols := make([]loader.Sym, elfobj.nsymtab)
for i := 1; i < elfobj.nsymtab; i++ {
var elfsym ElfSym
- if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
+ if err := readelfsym(newSym, lookup, l, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
return errorf("%s: malformed elf file: %v", pn, err)
}
symbols[i] = elfsym.sym
@@ -778,12 +769,12 @@
continue
}
if elfsym.shndx == ElfSymShnCommon || elfsym.type_ == ElfSymTypeCommon {
- s := elfsym.sym
- if uint64(s.Size) < elfsym.size {
- s.Size = int64(elfsym.size)
+ sb := l.MakeSymbolUpdater(elfsym.sym)
+ if uint64(sb.Size()) < elfsym.size {
+ sb.SetSize(int64(elfsym.size))
}
- if s.Type == 0 || s.Type == sym.SXREF {
- s.Type = sym.SNOPTRBSS
+ if sb.Type() == 0 || sb.Type() == sym.SXREF {
+ sb.SetType(sym.SNOPTRBSS)
}
continue
}
@@ -793,11 +784,11 @@
}
// even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
- if elfsym.sym == nil {
+ if elfsym.sym == 0 {
continue
}
sect = &elfobj.sect[elfsym.shndx]
- if sect.sym == nil {
+ if sect.sym == 0 {
if strings.HasPrefix(elfsym.name, ".Linfo_string") { // clang does this
continue
}
@@ -822,36 +813,37 @@
}
s := elfsym.sym
- if s.Outer != nil {
- if s.Attr.DuplicateOK() {
+ if l.OuterSym(s) != 0 {
+ if l.AttrDuplicateOK(s) {
continue
}
- return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
+ return errorf("duplicate symbol reference: %s in both %s and %s",
+ l.SymName(s), l.SymName(l.OuterSym(s)), l.SymName(sect.sym))
}
- s.Sub = sect.sym.Sub
- sect.sym.Sub = s
- s.Type = sect.sym.Type
- s.Attr |= sym.AttrSubSymbol
- if !s.Attr.CgoExportDynamic() {
- s.SetDynimplib("") // satisfy dynimport
+ sectsb := l.MakeSymbolUpdater(sect.sym)
+ sb := l.MakeSymbolUpdater(s)
+
+ sb.SetType(sectsb.Type())
+ sectsb.PrependSub(s)
+ if !l.AttrCgoExportDynamic(s) {
+ sb.SetDynimplib("") // satisfy dynimport
}
- s.Value = int64(elfsym.value)
- s.Size = int64(elfsym.size)
- s.Outer = sect.sym
- if sect.sym.Type == sym.STEXT {
- if s.Attr.External() && !s.Attr.DuplicateOK() {
- return errorf("%v: duplicate symbol definition", s)
+ sb.SetValue(int64(elfsym.value))
+ sb.SetSize(int64(elfsym.size))
+ if sectsb.Type() == sym.STEXT {
+ if l.AttrExternal(s) && !l.AttrDuplicateOK(s) {
+ return errorf("%s: duplicate symbol definition", sb.Name())
}
- s.Attr |= sym.AttrExternal
+ l.SetAttrExternal(s, true)
}
if elfobj.machine == ElfMachPower64 {
flag := int(elfsym.other) >> 5
if 2 <= flag && flag <= 6 {
- s.SetLocalentry(1 << uint(flag-2))
+ l.SetSymLocalentry(s, 1<<uint(flag-2))
} else if flag == 7 {
- return errorf("%v: invalid sym.other 0x%x", s, elfsym.other)
+ return errorf("%s: invalid sym.other 0x%x", sb.Name(), elfsym.other)
}
}
}
@@ -860,24 +852,27 @@
// This keeps textp in increasing address order.
for i := uint(0); i < elfobj.nsect; i++ {
s := elfobj.sect[i].sym
- if s == nil {
+ if s == 0 {
continue
}
- if s.Sub != nil {
- s.Sub = sym.SortSub(s.Sub)
+ sb := l.MakeSymbolUpdater(s)
+ if l.SubSym(s) != 0 {
+ sb.SortSub()
}
- if s.Type == sym.STEXT {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
+ if sb.Type() == sym.STEXT {
+ if l.AttrOnList(s) {
+ return errorf("symbol %s listed multiple times",
+ l.SymName(s))
}
- s.Attr |= sym.AttrOnList
+ l.SetAttrOnList(s, true)
textp = append(textp, s)
- for s = s.Sub; s != nil; s = s.Sub {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
+ for ss := l.SubSym(s); ss != 0; ss = l.SubSym(ss) {
+ if l.AttrOnList(ss) {
+ return errorf("symbol %s listed multiple times",
+ l.SymName(ss))
}
- s.Attr |= sym.AttrOnList
- textp = append(textp, s)
+ l.SetAttrOnList(ss, true)
+ textp = append(textp, ss)
}
}
}
@@ -900,7 +895,7 @@
rela = 1
}
n := int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
- r := make([]sym.Reloc, n)
+ r := make([]loader.Reloc, n)
p := rsect.base
for j := 0; j < n; j++ {
var add uint64
@@ -951,22 +946,22 @@
}
if symIdx == 0 { // absolute relocation, don't bother reading the null symbol
- rp.Sym = nil
+ rp.Sym = 0
} else {
var elfsym ElfSym
- if err := readelfsym(newSym, lookup, arch, elfobj, symIdx, &elfsym, 0, 0); err != nil {
+ if err := readelfsym(newSym, lookup, l, arch, elfobj, int(symIdx), &elfsym, 0, 0); err != nil {
return errorf("malformed elf file: %v", err)
}
elfsym.sym = symbols[symIdx]
- if elfsym.sym == nil {
- return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, symIdx, elfsym.name, elfsym.shndx, elfsym.type_)
+ if elfsym.sym == 0 {
+ return errorf("malformed elf file: %s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", l.SymName(sect.sym), j, int(symIdx), elfsym.name, elfsym.shndx, elfsym.type_)
}
rp.Sym = elfsym.sym
}
rp.Type = objabi.ElfRelocOffset + objabi.RelocType(relocType)
- rp.Siz, err = relSize(arch, pn, uint32(relocType))
+ rp.Size, err = relSize(arch, pn, uint32(relocType))
if err != nil {
return nil, 0, err
}
@@ -974,30 +969,30 @@
rp.Add = int64(add)
} else {
// load addend from image
- if rp.Siz == 4 {
+ if rp.Size == 4 {
rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
- } else if rp.Siz == 8 {
+ } else if rp.Size == 8 {
rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
} else {
- return errorf("invalid rela size %d", rp.Siz)
+ return errorf("invalid rela size %d", rp.Size)
}
}
- if rp.Siz == 2 {
+ if rp.Size == 2 {
rp.Add = int64(int16(rp.Add))
}
- if rp.Siz == 4 {
+ if rp.Size == 4 {
rp.Add = int64(int32(rp.Add))
}
}
//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
- sort.Sort(sym.RelocByOff(r[:n]))
+ sort.Sort(loader.RelocByOff(r[:n]))
// just in case
- s := sect.sym
- s.R = r
- s.R = s.R[:n]
+ sb := l.MakeSymbolUpdater(sect.sym)
+ r = r[:n]
+ sb.SetRelocs(r)
}
return textp, ehdrFlags, nil
@@ -1022,16 +1017,16 @@
return err
}
- sect.base = make([]byte, sect.size)
elfobj.f.MustSeek(int64(uint64(elfobj.base)+sect.off), 0)
- if _, err := io.ReadFull(elfobj.f, sect.base); err != nil {
+ sect.base, sect.readOnlyMem, err = elfobj.f.Slice(uint64(sect.size))
+ if err != nil {
return fmt.Errorf("short read: %v", err)
}
return nil
}
-func readelfsym(newSym, lookup lookupFunc, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
+func readelfsym(newSym, lookup func(string, int) loader.Sym, l *loader.Loader, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
if i >= elfobj.nsymtab || i < 0 {
err = fmt.Errorf("invalid elf symbol index")
return err
@@ -1063,7 +1058,8 @@
elfsym.other = b.Other
}
- var s *sym.Symbol
+ var s loader.Sym
+
if elfsym.name == "_GLOBAL_OFFSET_TABLE_" {
elfsym.name = ".got"
}
@@ -1090,8 +1086,12 @@
// TODO(minux): correctly handle __i686.get_pc_thunk.bx without
// set dupok generally. See https://golang.org/cl/5823055
// comment #5 for details.
- if s != nil && elfsym.other == 2 {
- s.Attr |= sym.AttrDuplicateOK | sym.AttrVisibilityHidden
+ if s != 0 && elfsym.other == 2 {
+ if !l.IsExternal(s) {
+ l.MakeSymbolUpdater(s)
+ }
+ l.SetAttrDuplicateOK(s, true)
+ l.SetAttrVisibilityHidden(s, true)
}
}
@@ -1107,9 +1107,8 @@
// so put it in the hash table.
if needSym != 0 {
s = lookup(elfsym.name, localSymVersion)
- s.Attr |= sym.AttrVisibilityHidden
+ l.SetAttrVisibilityHidden(s, true)
}
-
break
}
@@ -1121,20 +1120,19 @@
// reduce mem use, but also (possibly) make it harder
// to debug problems.
s = newSym(elfsym.name, localSymVersion)
-
- s.Attr |= sym.AttrVisibilityHidden
+ l.SetAttrVisibilityHidden(s, true)
}
case ElfSymBindWeak:
if needSym != 0 {
s = lookup(elfsym.name, 0)
if elfsym.other == 2 {
- s.Attr |= sym.AttrVisibilityHidden
+ l.SetAttrVisibilityHidden(s, true)
}
// Allow weak symbols to be duplicated when already defined.
- if s.Outer != nil {
- s.Attr |= sym.AttrDuplicateOK
+ if l.OuterSym(s) != 0 {
+ l.SetAttrDuplicateOK(s, true)
}
}
@@ -1146,8 +1144,9 @@
// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
// sense and should be removed when someone has thought about it properly.
- if s != nil && s.Type == 0 && !s.Attr.VisibilityHidden() && elfsym.type_ != ElfSymTypeSection {
- s.Type = sym.SXREF
+ if s != 0 && l.SymType(s) == 0 && !l.AttrVisibilityHidden(s) && elfsym.type_ != ElfSymTypeSection {
+ sb := l.MakeSymbolUpdater(s)
+ sb.SetType(sym.SXREF)
}
elfsym.sym = s
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 0adc395..8eb12c5 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -7,14 +7,15 @@
import (
"bytes"
"cmd/internal/bio"
- "cmd/internal/dwarf"
"cmd/internal/goobj2"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/sym"
+ "debug/elf"
"fmt"
"log"
+ "math/bits"
"os"
"sort"
"strconv"
@@ -35,8 +36,6 @@
li int // local index of symbol whose relocs we're examining
r *oReader // object reader for containing package
l *Loader // loader
-
- ext *sym.Symbol // external symbol if not nil
}
// Reloc contains the payload for a specific relocation.
@@ -50,6 +49,17 @@
Sym Sym // global index of symbol the reloc addresses
}
+// Reloc2 holds a "handle" to access a relocation record from an
+// object file.
+type Reloc2 struct {
+ *goobj2.Reloc2
+ r *oReader
+ l *Loader
+}
+
+func (rel Reloc2) Type() objabi.RelocType { return objabi.RelocType(rel.Reloc2.Type()) }
+func (rel Reloc2) Sym() Sym { return rel.l.resolve(rel.r, rel.Reloc2.Sym()) }
+
// oReader is a wrapper type of obj.Reader, along with some
// extra information.
// TODO: rename to objReader once the old one is gone?
@@ -59,13 +69,24 @@
version int // version of static symbol
flags uint32 // read from object file
pkgprefix string
- rcache []Sym // cache mapping local PkgNone symbol to resolved Sym
+ syms []Sym // Sym's global index, indexed by local index
+ ndef int // cache goobj2.Reader.NSym()
+ objidx uint32 // index of this reader in the objs slice
}
type objIdx struct {
r *oReader
i Sym // start index
- e Sym // end index
+}
+
+// objSym represents a symbol in an object file. It is a tuple of
+// the object and the symbol's local index.
+// For external symbols, r is l.extReader, s is its index into the
+// payload array.
+// {nil, 0} represents the nil symbol.
+type objSym struct {
+ r *oReader
+ s int // local index
}
type nameVer struct {
@@ -73,47 +94,133 @@
v int
}
-type bitmap []uint32
+type Bitmap []uint32
// set the i-th bit.
-func (bm bitmap) Set(i Sym) {
+func (bm Bitmap) Set(i Sym) {
n, r := uint(i)/32, uint(i)%32
bm[n] |= 1 << r
}
+// unset the i-th bit.
+func (bm Bitmap) Unset(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 {
+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)
+// return current length of bitmap in bits.
+func (bm Bitmap) Len() int {
+ return len(bm) * 32
+}
+func MakeBitmap(n int) Bitmap {
+ return make(Bitmap, (n+31)/32)
+}
+
+// growBitmap insures that the specified bitmap has enough capacity,
+// reallocating (doubling the size) if needed.
+func growBitmap(reqLen int, b Bitmap) Bitmap {
+ curLen := b.Len()
+ if reqLen > curLen {
+ b = append(b, MakeBitmap(reqLen+1-curLen)...)
+ }
+ return b
}
// A Loader loads new object files and resolves indexed symbol references.
+//
+// Notes on the layout of global symbol index space:
+//
+// - Go object files are read before host object files; each Go object
+// read adds its defined package symbols to the global index space.
+// Nonpackage symbols are not yet added.
+//
+// - In loader.LoadNonpkgSyms, add non-package defined symbols and
+// references in all object files to the global index space.
+//
+// - Host object file loading happens; the host object loader does a
+// name/version lookup for each symbol it finds; this can wind up
+// extending the external symbol index space range. The host object
+// loader stores symbol payloads in loader.payloads using SymbolBuilder.
+//
+// - For now, in loader.LoadFull we convert all symbols (Go + external)
+// to sym.Symbols.
+//
+// - At some point (when the wayfront is pushed through all of the
+// linker), all external symbols will be payload-based, and we can
+// get rid of the loader.Syms array.
+//
+// - Each symbol gets a unique global index. For duplicated and
+// overwriting/overwritten symbols, the second (or later) appearance
+// of the symbol gets the same global index as the first appearance.
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
- extSyms []nameVer // externally defined symbols
builtinSyms []Sym // global index of builtin symbols
- ocache int // index (into 'objs') of most recent lookup
+
+ objSyms []objSym // global index mapping to local index
symsByName [2]map[string]Sym // map symbol name to index, two maps are for ABI0 and ABIInternal
extStaticSyms map[nameVer]Sym // externally defined static symbols, keyed by name
- overwrite map[Sym]Sym // overwrite[i]=j if symbol j overwrites symbol i
+
+ extReader *oReader // a dummy oReader, for external symbols
+ payloadBatch []extSymPayload
+ payloads []*extSymPayload // contents of linker-materialized external syms
+ values []int64 // symbol values, indexed by global sym index
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
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.
+ Syms []*sym.Symbol // indexed symbols. XXX we still make sym.Symbol for now.
+ symBatch []sym.Symbol // batch of symbols.
anonVersion int // most recently assigned ext static sym pseudo-version
- Reachable bitmap // bitmap of reachable symbols, indexed by global index
+ // Bitmaps and other side structures used to store data used to store
+ // symbol flags/attributes; these are to be accessed via the
+ // corresponding loader "AttrXXX" and "SetAttrXXX" methods. Please
+ // visit the comments on these methods for more details on the
+ // semantics / interpretation of the specific flags or attribute.
+ attrReachable Bitmap // reachable symbols, indexed by global index
+ attrOnList Bitmap // "on list" symbols, indexed by global index
+ attrLocal Bitmap // "local" symbols, indexed by global index
+ attrNotInSymbolTable Bitmap // "not in symtab" symbols, indexed by glob idx
+ attrVisibilityHidden Bitmap // hidden symbols, indexed by ext sym index
+ attrDuplicateOK Bitmap // dupOK symbols, indexed by ext sym index
+ attrShared Bitmap // shared symbols, indexed by ext sym index
+ attrExternal Bitmap // external symbols, indexed by ext sym index
+
+ attrReadOnly map[Sym]bool // readonly data for this sym
+ attrTopFrame map[Sym]struct{} // top frame symbols
+ attrSpecial map[Sym]struct{} // "special" frame symbols
+ attrCgoExportDynamic map[Sym]struct{} // "cgo_export_dynamic" symbols
+ attrCgoExportStatic map[Sym]struct{} // "cgo_export_static" symbols
+
+ // Outer and Sub relations for symbols.
+ // TODO: figure out whether it's more efficient to just have these
+ // as fields on extSymPayload (note that this won't be a viable
+ // strategy if somewhere in the linker we set sub/outer for a
+ // non-external sym).
+ outer map[Sym]Sym
+ sub map[Sym]Sym
+
+ align map[Sym]int32 // stores alignment for symbols
+
+ dynimplib map[Sym]string // stores Dynimplib symbol attribute
+ dynimpvers map[Sym]string // stores Dynimpvers symbol attribute
+ localentry map[Sym]uint8 // stores Localentry symbol attribute
+ extname map[Sym]string // stores Extname symbol attribute
+ elfType map[Sym]elf.SymType // stores elf type symbol property
+ symFile map[Sym]string // stores file for shlib-derived syms
+ plt map[Sym]int32 // stores dynimport for pe objects
+ got map[Sym]int32 // stores got for pe objects
// Used to implement field tracking; created during deadcode if
// field tracking is enabled. Reachparent[K] contains the index of
@@ -125,6 +232,29 @@
flags uint32
strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled
+
+ elfsetstring elfsetstringFunc
+}
+
+const (
+ pkgDef = iota
+ nonPkgDef
+ nonPkgRef
+)
+
+type elfsetstringFunc func(s *sym.Symbol, str string, off int)
+
+// extSymPayload holds the payload (data + relocations) for linker-synthesized
+// external symbols (note that symbol value is stored in a separate slice).
+type extSymPayload struct {
+ name string // TODO: would this be better as offset into str table?
+ size int64
+ ver int
+ kind sym.SymKind
+ objidx uint32 // index of original object if sym made by cloneToExternal
+ gotype Sym // Gotype (0 if not present)
+ relocs []Reloc
+ data []byte
}
const (
@@ -132,26 +262,39 @@
FlagStrictDups = 1 << iota
)
-func NewLoader(flags uint32) *Loader {
+func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
nbuiltin := goobj2.NBuiltin()
return &Loader{
- start: make(map[*oReader]Sym),
- objs: []objIdx{{nil, 0, 0}},
- symsByName: [2]map[string]Sym{make(map[string]Sym), make(map[string]Sym)},
- objByPkg: make(map[string]*oReader),
- overwrite: make(map[Sym]Sym),
- itablink: make(map[Sym]struct{}),
- extStaticSyms: make(map[nameVer]Sym),
- builtinSyms: make([]Sym, nbuiltin),
- flags: flags,
+ start: make(map[*oReader]Sym),
+ objs: []objIdx{{}}, // reserve index 0 for nil symbol
+ objSyms: []objSym{{}}, // reserve index 0 for nil symbol
+ extReader: &oReader{},
+ symsByName: [2]map[string]Sym{make(map[string]Sym, 100000), make(map[string]Sym, 50000)}, // preallocate ~2MB for ABI0 and ~1MB for ABI1 symbols
+ objByPkg: make(map[string]*oReader),
+ outer: make(map[Sym]Sym),
+ sub: make(map[Sym]Sym),
+ align: make(map[Sym]int32),
+ dynimplib: make(map[Sym]string),
+ dynimpvers: make(map[Sym]string),
+ localentry: make(map[Sym]uint8),
+ extname: make(map[Sym]string),
+ attrReadOnly: make(map[Sym]bool),
+ elfType: make(map[Sym]elf.SymType),
+ symFile: make(map[Sym]string),
+ plt: make(map[Sym]int32),
+ got: make(map[Sym]int32),
+ attrTopFrame: make(map[Sym]struct{}),
+ attrSpecial: make(map[Sym]struct{}),
+ attrCgoExportDynamic: make(map[Sym]struct{}),
+ attrCgoExportStatic: make(map[Sym]struct{}),
+ itablink: make(map[Sym]struct{}),
+ extStaticSyms: make(map[nameVer]Sym),
+ builtinSyms: make([]Sym, nbuiltin),
+ flags: flags,
+ elfsetstring: elfsetstring,
}
}
-// 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 {
@@ -161,89 +304,194 @@
if _, ok := l.objByPkg[pkg]; !ok {
l.objByPkg[pkg] = r
}
- n := r.NSym() + r.NNonpkgdef()
- i := l.max + 1
+ i := Sym(len(l.objSyms))
l.start[r] = i
- l.objs = append(l.objs, objIdx{r, i, i + Sym(n) - 1})
- l.max += Sym(n)
+ l.objs = append(l.objs, objIdx{r, i})
return i
}
-// Add a symbol with a given index, return if it is added.
-func (l *Loader) AddSym(name string, ver int, i Sym, r *oReader, dupok bool, typ sym.SymKind) bool {
+// Add a symbol from an object file, return the global index and whether it is added.
+// If the symbol already exist, it returns the index of that symbol.
+func (l *Loader) AddSym(name string, ver int, r *oReader, li int, kind int, dupok bool, typ sym.SymKind) (Sym, bool) {
if l.extStart != 0 {
panic("AddSym called after AddExtSym is called")
}
+ i := Sym(len(l.objSyms))
+ addToGlobal := func() {
+ l.objSyms = append(l.objSyms, objSym{r, li})
+ }
+ if name == "" {
+ addToGlobal()
+ return i, true // unnamed aux symbol
+ }
if ver == r.version {
// Static symbol. Add its global index but don't
// add to name lookup table, as it cannot be
// referenced by name.
- return true
+ addToGlobal()
+ return i, true
}
- if oldi, ok := l.symsByName[ver][name]; ok {
- if dupok {
- if l.flags&FlagStrictDups != 0 {
- l.checkdup(name, i, r, oldi)
- }
- return false
+ if kind == pkgDef {
+ // Defined package symbols cannot be dup to each other.
+ // We load all the package symbols first, so we don't need
+ // to check dup here.
+ // We still add it to the lookup table, as it may still be
+ // referenced by name (e.g. through linkname).
+ l.symsByName[ver][name] = i
+ addToGlobal()
+ return i, true
+ }
+
+ // Non-package (named) symbol. Check if it already exists.
+ oldi, existed := l.symsByName[ver][name]
+ if !existed {
+ l.symsByName[ver][name] = i
+ addToGlobal()
+ return i, true
+ }
+ // symbol already exists
+ if dupok {
+ if l.flags&FlagStrictDups != 0 {
+ l.checkdup(name, r, li, oldi)
}
- oldr, li := l.toLocal(oldi)
- oldsym := goobj2.Sym{}
- oldsym.Read(oldr.Reader, oldr.SymOff(li))
- if oldsym.Dupok() {
- return false
+ return oldi, false
+ }
+ oldr, oldli := l.toLocal(oldi)
+ oldsym := goobj2.Sym{}
+ oldsym.ReadWithoutName(oldr.Reader, oldr.SymOff(oldli))
+ if oldsym.Dupok() {
+ return oldi, false
+ }
+ overwrite := r.DataSize(li) != 0
+ if overwrite {
+ // new symbol overwrites old symbol.
+ oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type)]
+ if !(oldtyp.IsData() && oldr.DataSize(oldli) == 0) {
+ log.Fatalf("duplicated definition of symbol " + name)
}
- overwrite := r.DataSize(int(i-l.startIndex(r))) != 0
- if overwrite {
- // new symbol overwrites old symbol.
- oldtyp := sym.AbiSymKindToSymKind[objabi.SymKind(oldsym.Type)]
- if !oldtyp.IsData() && r.DataSize(li) == 0 {
- log.Fatalf("duplicated definition of symbol " + name)
- }
- l.overwrite[oldi] = i
- } else {
- // old symbol overwrites new symbol.
- if typ != sym.SDATA && typ != sym.SNOPTRDATA && typ != sym.SBSS && typ != sym.SNOPTRBSS { // only allow overwriting data symbol
- log.Fatalf("duplicated definition of symbol " + name)
- }
- l.overwrite[i] = oldi
- return false
+ l.objSyms[oldi] = objSym{r, li}
+ } else {
+ // old symbol overwrites new symbol.
+ if !typ.IsData() { // only allow overwriting data symbol
+ log.Fatalf("duplicated definition of symbol " + name)
}
}
- l.symsByName[ver][name] = i
- return true
+ return oldi, true
+}
+
+// newExtSym creates a new external sym with the specified
+// name/version.
+func (l *Loader) newExtSym(name string, ver int) Sym {
+ i := Sym(len(l.objSyms))
+ if l.extStart == 0 {
+ l.extStart = i
+ }
+ l.growSyms(int(i))
+ pi := l.newPayload(name, ver)
+ l.objSyms = append(l.objSyms, objSym{l.extReader, int(pi)})
+ l.extReader.syms = append(l.extReader.syms, i)
+ return i
}
// 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 {
- static := ver >= sym.SymVerStatic
- if static {
- if _, ok := l.extStaticSyms[nameVer{name, ver}]; ok {
- return 0
- }
- } else {
- if _, ok := l.symsByName[ver][name]; ok {
- return 0
- }
+ i := l.Lookup(name, ver)
+ if i != 0 {
+ return i
}
- i := l.max + 1
+ i = l.newExtSym(name, ver)
+ static := ver >= sym.SymVerStatic || ver < 0
if static {
l.extStaticSyms[nameVer{name, ver}] = i
} else {
l.symsByName[ver][name] = i
}
- l.max++
- if l.extStart == 0 {
- l.extStart = i
+ return i
+}
+
+// LookupOrCreateSym looks up the symbol with the specified name/version,
+// returning its Sym index if found. If the lookup fails, a new external
+// Sym will be created, entered into the lookup tables, and returned.
+func (l *Loader) LookupOrCreateSym(name string, ver int) Sym {
+ i := l.Lookup(name, ver)
+ if i != 0 {
+ return i
}
- l.extSyms = append(l.extSyms, nameVer{name, ver})
- l.growSyms(int(i))
+ i = l.newExtSym(name, ver)
+ static := ver >= sym.SymVerStatic || ver < 0
+ if static {
+ l.extStaticSyms[nameVer{name, ver}] = i
+ } else {
+ l.symsByName[ver][name] = i
+ }
return i
}
func (l *Loader) IsExternal(i Sym) bool {
- return l.extStart != 0 && i >= l.extStart
+ r, _ := l.toLocal(i)
+ return l.isExtReader(r)
+}
+
+func (l *Loader) isExtReader(r *oReader) bool {
+ return r == l.extReader
+}
+
+// For external symbol, return its index in the payloads array.
+// XXX result is actually not a global index. We (ab)use the Sym type
+// so we don't need conversion for accessing bitmaps.
+func (l *Loader) extIndex(i Sym) Sym {
+ _, li := l.toLocal(i)
+ return Sym(li)
+}
+
+// Get a new payload for external symbol, return its index in
+// the payloads array.
+func (l *Loader) newPayload(name string, ver int) int {
+ pi := len(l.payloads)
+ pp := l.allocPayload()
+ pp.name = name
+ pp.ver = ver
+ l.payloads = append(l.payloads, pp)
+ l.growExtAttrBitmaps()
+ return pi
+}
+
+// getPayload returns a pointer to the extSymPayload struct for an
+// external symbol if the symbol has a payload. Will panic if the
+// symbol in question is bogus (zero or not an external sym).
+func (l *Loader) getPayload(i Sym) *extSymPayload {
+ if !l.IsExternal(i) {
+ panic(fmt.Sprintf("bogus symbol index %d in getPayload", i))
+ }
+ pi := l.extIndex(i)
+ return l.payloads[pi]
+}
+
+// allocPayload allocates a new payload.
+func (l *Loader) allocPayload() *extSymPayload {
+ batch := l.payloadBatch
+ if len(batch) == 0 {
+ batch = make([]extSymPayload, 1000)
+ }
+ p := &batch[0]
+ l.payloadBatch = batch[1:]
+ return p
+}
+
+func (ms *extSymPayload) Grow(siz int64) {
+ if int64(int(siz)) != siz {
+ log.Fatalf("symgrow size %d too long", siz)
+ }
+ if int64(len(ms.data)) >= siz {
+ return
+ }
+ if cap(ms.data) < int(siz) {
+ cl := len(ms.data)
+ ms.data = append(ms.data, make([]byte, int(siz)+1-cl)...)
+ ms.data = ms.data[0:cl]
+ }
+ ms.data = ms.data[:siz]
}
// Ensure Syms slice has enough space.
@@ -253,57 +501,18 @@
return
}
l.Syms = append(l.Syms, make([]*sym.Symbol, i+1-n)...)
+ l.growValues(int(i) + 1)
+ l.growAttrBitmaps(int(i) + 1)
}
// Convert a local index to a global index.
func (l *Loader) toGlobal(r *oReader, i int) Sym {
- g := l.startIndex(r) + Sym(i)
- if ov, ok := l.overwrite[g]; ok {
- return ov
- }
- return g
+ return r.syms[i]
}
// Convert a global index to a local index.
func (l *Loader) toLocal(i Sym) (*oReader, int) {
- if ov, ok := l.overwrite[i]; ok {
- i = ov
- }
- if l.IsExternal(i) {
- return nil, int(i - l.extStart)
- }
- oc := l.ocache
- if oc != 0 && i >= l.objs[oc].i && i <= l.objs[oc].e {
- return l.objs[oc].r, int(i - l.objs[oc].i)
- }
- // 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
- })
- l.ocache = k - 1
- return l.objs[k-1].r, int(i - l.objs[k-1].i)
-}
-
-// rcacheGet checks for a valid entry for 's' in the readers cache,
-// where 's' is a local PkgIdxNone ref or def, or zero if
-// the cache is empty or doesn't contain a value for 's'.
-func (or *oReader) rcacheGet(symIdx uint32) Sym {
- if len(or.rcache) > 0 {
- return or.rcache[symIdx]
- }
- return 0
-}
-
-// rcacheSet installs a new entry in the oReader's PkgNone
-// resolver cache for the specified PkgIdxNone ref or def,
-// allocating a new cache if needed.
-func (or *oReader) rcacheSet(symIdx uint32, gsym Sym) {
- if len(or.rcache) == 0 {
- or.rcache = make([]Sym, or.NNonpkgdef()+or.NNonpkgref())
- }
- or.rcache[symIdx] = gsym
+ return l.objSyms[i].r, int(l.objSyms[i].s)
}
// Resolve a local symbol reference. Return global index.
@@ -311,25 +520,19 @@
var rr *oReader
switch p := s.PkgIdx; p {
case goobj2.PkgIdxInvalid:
+ // {0, X} with non-zero X is never a valid sym reference from a Go object.
+ // We steal this space for symbol references from external objects.
+ // In this case, X is just the global index.
+ if l.isExtReader(r) {
+ return Sym(s.SymIdx)
+ }
if s.SymIdx != 0 {
panic("bad sym ref")
}
return 0
case goobj2.PkgIdxNone:
- // Check for cached version first
- if cached := r.rcacheGet(s.SymIdx); cached != 0 {
- return cached
- }
- // 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)
- gsym := l.Lookup(name, v)
- // Add to cache, then return.
- r.rcacheSet(s.SymIdx, gsym)
- return gsym
+ i := int(s.SymIdx) + r.ndef
+ return r.syms[i]
case goobj2.PkgIdxBuiltin:
return l.builtinSyms[s.SymIdx]
case goobj2.PkgIdxSelf:
@@ -355,44 +558,11 @@
return l.symsByName[ver][name]
}
-// Returns whether i is a dup of another symbol, and i is not
-// "primary", i.e. Lookup i by name will not return i.
-func (l *Loader) IsDup(i Sym) bool {
- if _, ok := l.overwrite[i]; ok {
- return true
- }
- if l.IsExternal(i) {
- return false
- }
- r, li := l.toLocal(i)
- osym := goobj2.Sym{}
- osym.Read(r.Reader, r.SymOff(li))
- if !osym.Dupok() {
- return false
- }
- if osym.Name == "" {
- return false // Unnamed aux symbol cannot be dup.
- }
- if osym.ABI == goobj2.SymABIstatic {
- return false // Static symbol cannot be dup.
- }
- name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
- ver := abiToVer(osym.ABI, r.version)
- return l.symsByName[ver][name] != i
-}
-
// Check that duplicate symbols have same contents.
-func (l *Loader) checkdup(name string, i Sym, r *oReader, dup Sym) {
- li := int(i - l.startIndex(r))
+func (l *Loader) checkdup(name string, r *oReader, li int, dup Sym) {
p := r.Data(li)
- if strings.HasPrefix(name, "go.info.") {
- p, _ = patchDWARFName1(p, r)
- }
rdup, ldup := l.toLocal(dup)
pdup := rdup.Data(ldup)
- if strings.HasPrefix(name, "go.info.") {
- pdup, _ = patchDWARFName1(pdup, rdup)
- }
if bytes.Equal(p, pdup) {
return
}
@@ -419,7 +589,7 @@
// Number of total symbols.
func (l *Loader) NSym() int {
- return int(l.max + 1)
+ return len(l.objSyms)
}
// Number of defined Go symbols.
@@ -430,10 +600,8 @@
// Returns the raw (unpatched) name of the i-th symbol.
func (l *Loader) RawSymName(i Sym) string {
if l.IsExternal(i) {
- if s := l.Syms[i]; s != nil {
- return s.Name
- }
- return ""
+ pp := l.getPayload(i)
+ return pp.name
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
@@ -444,10 +612,8 @@
// Returns the (patched) name of the i-th symbol.
func (l *Loader) SymName(i Sym) string {
if l.IsExternal(i) {
- if s := l.Syms[i]; s != nil {
- return s.Name // external name should already be patched?
- }
- return ""
+ pp := l.getPayload(i)
+ return pp.name
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
@@ -455,17 +621,30 @@
return strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
}
+// Returns the version of the i-th symbol.
+func (l *Loader) SymVersion(i Sym) int {
+ if l.IsExternal(i) {
+ pp := l.getPayload(i)
+ return pp.ver
+ }
+ r, li := l.toLocal(i)
+ osym := goobj2.Sym{}
+ osym.ReadWithoutName(r.Reader, r.SymOff(li))
+ return int(abiToVer(osym.ABI, r.version))
+}
+
// Returns the type of the i-th symbol.
func (l *Loader) SymType(i Sym) sym.SymKind {
if l.IsExternal(i) {
- if s := l.Syms[i]; s != nil {
- return s.Type
+ pp := l.getPayload(i)
+ if pp != nil {
+ return pp.kind
}
return 0
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
- osym.Read(r.Reader, r.SymOff(li))
+ osym.ReadWithoutName(r.Reader, r.SymOff(li))
return sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
}
@@ -477,15 +656,305 @@
}
r, li := l.toLocal(i)
osym := goobj2.Sym{}
- osym.Read(r.Reader, r.SymOff(li))
+ osym.ReadFlag(r.Reader, r.SymOff(li))
return osym.Flag
}
+// AttrReachable returns true for symbols that are transitively
+// referenced from the entry points. Unreachable symbols are not
+// written to the output.
+func (l *Loader) AttrReachable(i Sym) bool {
+ return l.attrReachable.Has(i)
+}
+
+// SetAttrReachable sets the reachability property for a symbol (see
+// AttrReachable).
+func (l *Loader) SetAttrReachable(i Sym, v bool) {
+ if v {
+ l.attrReachable.Set(i)
+ } else {
+ l.attrReachable.Unset(i)
+ }
+}
+
+// AttrOnList returns true for symbols that are on some list (such as
+// the list of all text symbols, or one of the lists of data symbols)
+// and is consulted to avoid bugs where a symbol is put on a list
+// twice.
+func (l *Loader) AttrOnList(i Sym) bool {
+ return l.attrOnList.Has(i)
+}
+
+// SetAttrOnList sets the "on list" property for a symbol (see
+// AttrOnList).
+func (l *Loader) SetAttrOnList(i Sym, v bool) {
+ if v {
+ l.attrOnList.Set(i)
+ } else {
+ l.attrOnList.Unset(i)
+ }
+}
+
+// AttrLocal returns true for symbols that are only visible within the
+// module (executable or shared library) being linked. This attribute
+// is applied to thunks and certain other linker-generated symbols.
+func (l *Loader) AttrLocal(i Sym) bool {
+ return l.attrLocal.Has(i)
+}
+
+// SetAttrLocal the "local" property for a symbol (see AttrLocal above).
+func (l *Loader) SetAttrLocal(i Sym, v bool) {
+ if v {
+ l.attrLocal.Set(i)
+ } else {
+ l.attrLocal.Unset(i)
+ }
+}
+
+// AttrNotInSymbolTable returns true for symbols that should not be
+// added to the symbol table of the final generated load module.
+func (l *Loader) AttrNotInSymbolTable(i Sym) bool {
+ return l.attrNotInSymbolTable.Has(i)
+}
+
+// SetAttrNotInSymbolTable the "not in symtab" property for a symbol
+// (see AttrNotInSymbolTable above).
+func (l *Loader) SetAttrNotInSymbolTable(i Sym, v bool) {
+ if v {
+ l.attrNotInSymbolTable.Set(i)
+ } else {
+ l.attrNotInSymbolTable.Unset(i)
+ }
+}
+
+// AttrVisibilityHidden symbols returns true for ELF symbols with
+// visibility set to STV_HIDDEN. They become local symbols in
+// the final executable. Only relevant when internally linking
+// on an ELF platform.
+func (l *Loader) AttrVisibilityHidden(i Sym) bool {
+ if !l.IsExternal(i) {
+ return false
+ }
+ return l.attrVisibilityHidden.Has(l.extIndex(i))
+}
+
+// SetAttrVisibilityHidden sets the "hidden visibility" property for a
+// symbol (see AttrVisibilityHidden).
+func (l *Loader) SetAttrVisibilityHidden(i Sym, v bool) {
+ if !l.IsExternal(i) {
+ panic("tried to set visibility attr on non-external symbol")
+ }
+ if v {
+ l.attrVisibilityHidden.Set(l.extIndex(i))
+ } else {
+ l.attrVisibilityHidden.Unset(l.extIndex(i))
+ }
+}
+
+// AttrDuplicateOK returns true for a symbol that can be present in
+// multiple object files.
+func (l *Loader) AttrDuplicateOK(i Sym) bool {
+ if !l.IsExternal(i) {
+ // TODO: if this path winds up being taken frequently, it
+ // might make more sense to copy the flag value out of the object
+ // into a larger bitmap during preload.
+ r, li := l.toLocal(i)
+ osym := goobj2.Sym{}
+ osym.ReadFlag(r.Reader, r.SymOff(li))
+ return osym.Dupok()
+ }
+ return l.attrDuplicateOK.Has(l.extIndex(i))
+}
+
+// SetAttrDuplicateOK sets the "duplicate OK" property for an external
+// symbol (see AttrDuplicateOK).
+func (l *Loader) SetAttrDuplicateOK(i Sym, v bool) {
+ if !l.IsExternal(i) {
+ panic("tried to set dupok attr on non-external symbol")
+ }
+ if v {
+ l.attrDuplicateOK.Set(l.extIndex(i))
+ } else {
+ l.attrDuplicateOK.Unset(l.extIndex(i))
+ }
+}
+
+// AttrShared returns true for symbols compiled with the -shared option.
+func (l *Loader) AttrShared(i Sym) bool {
+ if !l.IsExternal(i) {
+ // TODO: if this path winds up being taken frequently, it
+ // might make more sense to copy the flag value out of the
+ // object into a larger bitmap during preload.
+ r, _ := l.toLocal(i)
+ return (r.Flags() & goobj2.ObjFlagShared) != 0
+ }
+ return l.attrShared.Has(l.extIndex(i))
+}
+
+// SetAttrShared sets the "shared" property for an external
+// symbol (see AttrShared).
+func (l *Loader) SetAttrShared(i Sym, v bool) {
+ if !l.IsExternal(i) {
+ panic(fmt.Sprintf("tried to set shared attr on non-external symbol %d %s", i, l.SymName(i)))
+ }
+ if v {
+ l.attrShared.Set(l.extIndex(i))
+ } else {
+ l.attrShared.Unset(l.extIndex(i))
+ }
+}
+
+// AttrExternal returns true for function symbols loaded from host
+// object files.
+func (l *Loader) AttrExternal(i Sym) bool {
+ if !l.IsExternal(i) {
+ return false
+ }
+ return l.attrExternal.Has(l.extIndex(i))
+}
+
+// SetAttrExternal sets the "external" property for an host object
+// symbol (see AttrExternal).
+func (l *Loader) SetAttrExternal(i Sym, v bool) {
+ if !l.IsExternal(i) {
+ panic(fmt.Sprintf("tried to set external attr on non-external symbol %q", l.RawSymName(i)))
+ }
+ if v {
+ l.attrExternal.Set(l.extIndex(i))
+ } else {
+ l.attrExternal.Unset(l.extIndex(i))
+ }
+}
+
+// AttrTopFrame returns true for a function symbol that is an entry
+// point, meaning that unwinders should stop when they hit this
+// function.
+func (l *Loader) AttrTopFrame(i Sym) bool {
+ _, ok := l.attrTopFrame[i]
+ return ok
+}
+
+// SetAttrTopFrame sets the "top frame" property for a symbol (see
+// AttrTopFrame).
+func (l *Loader) SetAttrTopFrame(i Sym, v bool) {
+ if v {
+ l.attrTopFrame[i] = struct{}{}
+ } else {
+ delete(l.attrTopFrame, i)
+ }
+}
+
+// AttrSpecial returns true for a symbols that do not have their
+// address (i.e. Value) computed by the usual mechanism of
+// data.go:dodata() & data.go:address().
+func (l *Loader) AttrSpecial(i Sym) bool {
+ _, ok := l.attrSpecial[i]
+ return ok
+}
+
+// SetAttrSpecial sets the "special" property for a symbol (see
+// AttrSpecial).
+func (l *Loader) SetAttrSpecial(i Sym, v bool) {
+ if v {
+ l.attrSpecial[i] = struct{}{}
+ } else {
+ delete(l.attrSpecial, i)
+ }
+}
+
+// AttrCgoExportDynamic returns true for a symbol that has been
+// specially marked via the "cgo_export_dynamic" compiler directive
+// written by cgo (in response to //export directives in the source).
+func (l *Loader) AttrCgoExportDynamic(i Sym) bool {
+ _, ok := l.attrCgoExportDynamic[i]
+ return ok
+}
+
+// SetAttrCgoExportDynamic sets the "cgo_export_dynamic" for a symbol
+// (see AttrCgoExportDynamic).
+func (l *Loader) SetAttrCgoExportDynamic(i Sym, v bool) {
+ if v {
+ l.attrCgoExportDynamic[i] = struct{}{}
+ } else {
+ delete(l.attrCgoExportDynamic, i)
+ }
+}
+
+// AttrCgoExportStatic returns true for a symbol that has been
+// specially marked via the "cgo_export_static" directive
+// written by cgo.
+func (l *Loader) AttrCgoExportStatic(i Sym) bool {
+ _, ok := l.attrCgoExportStatic[i]
+ return ok
+}
+
+// SetAttrCgoExportStatic sets the "cgo_export_dynamic" for a symbol
+// (see AttrCgoExportStatic).
+func (l *Loader) SetAttrCgoExportStatic(i Sym, v bool) {
+ if v {
+ l.attrCgoExportStatic[i] = struct{}{}
+ } else {
+ delete(l.attrCgoExportStatic, i)
+ }
+}
+
+// AttrReadOnly returns true for a symbol whose underlying data
+// is stored via a read-only mmap.
+func (l *Loader) AttrReadOnly(i Sym) bool {
+ if v, ok := l.attrReadOnly[i]; ok {
+ return v
+ }
+ if l.IsExternal(i) {
+ return false
+ }
+ r, _ := l.toLocal(i)
+ return r.ReadOnly()
+}
+
+// SetAttrReadOnly sets the "cgo_export_dynamic" for a symbol
+// (see AttrReadOnly).
+func (l *Loader) SetAttrReadOnly(i Sym, v bool) {
+ l.attrReadOnly[i] = v
+}
+
+// AttrSubSymbol returns true for symbols that are listed as a
+// sub-symbol of some other outer symbol. The sub/outer mechanism is
+// used when loading host objects (sections from the host object
+// become regular linker symbols and symbols go on the Sub list of
+// their section) and for constructing the global offset table when
+// internally linking a dynamic executable.
+func (l *Loader) AttrSubSymbol(i Sym) bool {
+ // we don't explicitly store this attribute any more -- return
+ // a value based on the sub-symbol setting.
+ return l.OuterSym(i) != 0
+}
+
+// AttrContainer returns true for symbols that are listed as a
+// sub-symbol of some other outer symbol. The sub/outer mechanism is
+// used when loading host objects (sections from the host object
+// become regular linker symbols and symbols go on the Sub list of
+// their section) and for constructing the global offset table when
+// internally linking a dynamic executable.
+func (l *Loader) AttrContainer(i Sym) bool {
+ // we don't explicitly store this attribute any more -- return
+ // a value based on the sub-symbol setting.
+ return l.SubSym(i) != 0
+}
+
+// Note that we don't have SetAttrSubSymbol' or 'SetAttrContainer' methods
+// in the loader; clients should just use methods like PrependSub
+// to establish these relationships
+
// Returns whether the i-th symbol has ReflectMethod attribute set.
func (l *Loader) IsReflectMethod(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagReflectMethod != 0
}
+// Returns whether the i-th symbol is nosplit.
+func (l *Loader) IsNoSplit(i Sym) bool {
+ return l.SymAttr(i)&goobj2.SymFlagNoSplit != 0
+}
+
// Returns whether this is a Go type symbol.
func (l *Loader) IsGoType(i Sym) bool {
return l.SymAttr(i)&goobj2.SymFlagGoType != 0
@@ -499,11 +968,30 @@
return false
}
+// growValues grows the slice used to store symbol values.
+func (l *Loader) growValues(reqLen int) {
+ curLen := len(l.values)
+ if reqLen > curLen {
+ l.values = append(l.values, make([]int64, reqLen+1-curLen)...)
+ }
+}
+
+// SymValue returns the value of the i-th symbol. i is global index.
+func (l *Loader) SymValue(i Sym) int64 {
+ return l.values[i]
+}
+
+// SetSymValue sets the value of the i-th symbol. i is global index.
+func (l *Loader) SetSymValue(i Sym, val int64) {
+ l.values[i] = val
+}
+
// Returns the symbol content of the i-th symbol. i is global index.
func (l *Loader) Data(i Sym) []byte {
if l.IsExternal(i) {
- if s := l.Syms[i]; s != nil {
- return s.P
+ pp := l.getPayload(i)
+ if pp != nil {
+ return pp.data
}
return nil
}
@@ -511,6 +999,243 @@
return r.Data(li)
}
+// SymAlign returns the alignment for a symbol.
+func (l *Loader) SymAlign(i Sym) int32 {
+ // If an alignment has been recorded, return that.
+ if align, ok := l.align[i]; ok {
+ return align
+ }
+ // TODO: would it make sense to return an arch-specific
+ // alignment depending on section type? E.g. STEXT => 32,
+ // SDATA => 1, etc?
+ return 0
+}
+
+// SetSymAlign sets the alignment for a symbol.
+func (l *Loader) SetSymAlign(i Sym, align int32) {
+ // reject bad synbols
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol index in SetSymAlign")
+ }
+ // Reject nonsense alignments.
+ // TODO: do we need this?
+ if align < 0 {
+ panic("bad alignment value")
+ }
+ if align == 0 {
+ delete(l.align, i)
+ } else {
+ // Alignment should be a power of 2.
+ if bits.OnesCount32(uint32(align)) != 1 {
+ panic("bad alignment value")
+ }
+ l.align[i] = align
+ }
+}
+
+// SymDynImplib returns the "dynimplib" attribute for the specified
+// symbol, making up a portion of the info for a symbol specified
+// on a "cgo_import_dynamic" compiler directive.
+func (l *Loader) SymDynimplib(i Sym) string {
+ return l.dynimplib[i]
+}
+
+// SetSymDynimplib sets the "dynimplib" attribute for a symbol.
+func (l *Loader) SetSymDynimplib(i Sym, value string) {
+ // reject bad symbols
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol index in SetDynimplib")
+ }
+ if value == "" {
+ delete(l.dynimplib, i)
+ } else {
+ l.dynimplib[i] = value
+ }
+}
+
+// SymDynimpvers returns the "dynimpvers" attribute for the specified
+// symbol, making up a portion of the info for a symbol specified
+// on a "cgo_import_dynamic" compiler directive.
+func (l *Loader) SymDynimpvers(i Sym) string {
+ return l.dynimpvers[i]
+}
+
+// SetSymDynimpvers sets the "dynimpvers" attribute for a symbol.
+func (l *Loader) SetSymDynimpvers(i Sym, value string) {
+ // reject bad symbols
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol index in SetDynimpvers")
+ }
+ if value == "" {
+ delete(l.dynimpvers, i)
+ } else {
+ l.dynimpvers[i] = value
+ }
+}
+
+// SymExtname returns the "extname" value for the specified
+// symbol.
+func (l *Loader) SymExtname(i Sym) string {
+ if s, ok := l.extname[i]; ok {
+ return s
+ }
+ return l.SymName(i)
+}
+
+// SetSymExtname sets the "extname" attribute for a symbol.
+func (l *Loader) SetSymExtname(i Sym, value string) {
+ // reject bad symbols
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol index in SetExtname")
+ }
+ if value == "" {
+ delete(l.extname, i)
+ } else {
+ l.extname[i] = value
+ }
+}
+
+// SymElfType returns the previously recorded ELF type for a symbol
+// (used only for symbols read from shared libraries by ldshlibsyms).
+// It is not set for symbols defined by the packages being linked or
+// by symbols read by ldelf (and so is left as elf.STT_NOTYPE).
+func (l *Loader) SymElfType(i Sym) elf.SymType {
+ if et, ok := l.elfType[i]; ok {
+ return et
+ }
+ return elf.STT_NOTYPE
+}
+
+// SetSymElfType sets the elf type attribute for a symbol.
+func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
+ // reject bad symbols
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol index in SetSymElfType")
+ }
+ if et == elf.STT_NOTYPE {
+ delete(l.elfType, i)
+ } else {
+ l.elfType[i] = et
+ }
+}
+
+// SetPlt sets the plt value for pe symbols.
+func (l *Loader) SetPlt(i Sym, v int32) {
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol for SetPlt")
+ }
+ if v == 0 {
+ delete(l.plt, i)
+ } else {
+ l.plt[i] = v
+ }
+}
+
+// SetGot sets the got value for pe symbols.
+func (l *Loader) SetGot(i Sym, v int32) {
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol for SetPlt")
+ }
+ if v == 0 {
+ delete(l.got, i)
+ } else {
+ l.got[i] = v
+ }
+}
+
+// SymGoType returns the 'Gotype' property for a given symbol (set by
+// the Go compiler for variable symbols). This version relies on
+// reading aux symbols for the target sym -- it could be that a faster
+// approach would be to check for gotype during preload and copy the
+// results in to a map (might want to try this at some point and see
+// if it helps speed things up).
+func (l *Loader) SymGoType(i Sym) Sym {
+ if l.IsExternal(i) {
+ pp := l.getPayload(i)
+ return pp.gotype
+ }
+ r, li := l.toLocal(i)
+ naux := r.NAux(li)
+ for j := 0; j < naux; j++ {
+ a := goobj2.Aux{}
+ a.Read(r.Reader, r.AuxOff(li, j))
+ switch a.Type {
+ case goobj2.AuxGotype:
+ return l.resolve(r, a.Sym)
+ }
+ }
+ return 0
+}
+
+// SymUnit returns the compilation unit for a given symbol (which will
+// typically be nil for external or linker-manufactured symbols).
+func (l *Loader) SymUnit(i Sym) *sym.CompilationUnit {
+ if l.IsExternal(i) {
+ pp := l.getPayload(i)
+ if pp.objidx != 0 {
+ r := l.objs[pp.objidx].r
+ return r.unit
+ }
+ return nil
+ }
+ r, _ := l.toLocal(i)
+ return r.unit
+}
+
+// SymFile returns the file for a symbol, which is normally the
+// package the symbol came from (for regular compiler-generated Go
+// symbols), but in the case of building with "-linkshared" (when a
+// symbol is read from a a shared library), will hold the library
+// name.
+func (l *Loader) SymFile(i Sym) string {
+ if l.IsExternal(i) {
+ if f, ok := l.symFile[i]; ok {
+ return f
+ }
+ pp := l.getPayload(i)
+ if pp.objidx != 0 {
+ r := l.objs[pp.objidx].r
+ return r.unit.Lib.File
+ }
+ return ""
+ }
+ r, _ := l.toLocal(i)
+ return r.unit.Lib.File
+}
+
+// SetSymFile sets the file attribute for a symbol. This is
+// needed mainly for external symbols, specifically those imported
+// from shared libraries.
+func (l *Loader) SetSymFile(i Sym, file string) {
+ // reject bad symbols
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol index in SetSymFile")
+ }
+ if !l.IsExternal(i) {
+ panic("can't set file for non-external sym")
+ }
+ l.symFile[i] = file
+}
+
+// SymLocalentry returns the "local entry" value for the specified
+// symbol.
+func (l *Loader) SymLocalentry(i Sym) uint8 {
+ return l.localentry[i]
+}
+
+// SetSymExtname sets the "extname" attribute for a symbol.
+func (l *Loader) SetSymLocalentry(i Sym, value uint8) {
+ // reject bad symbols
+ if i >= Sym(len(l.objSyms)) || i == 0 {
+ panic("bad symbol index in SetExtname")
+ }
+ if value == 0 {
+ delete(l.localentry, i)
+ } else {
+ l.localentry[i] = value
+ }
+}
+
// Returns the number of aux symbols given a global index.
func (l *Loader) NAux(i Sym) int {
if l.IsExternal(i) {
@@ -532,6 +1257,56 @@
return l.resolve(r, a.Sym)
}
+// GetFuncDwarfAuxSyms collects and returns the auxiliary DWARF
+// symbols associated with a given function symbol. Prior to the
+// introduction of the loader, this was done purely using name
+// lookups, e.f. for function with name XYZ we would then look up
+// go.info.XYZ, etc.
+// FIXME: once all of dwarfgen is converted over to the loader,
+// it would save some space to make these aux symbols nameless.
+func (l *Loader) GetFuncDwarfAuxSyms(fnSymIdx Sym) (auxDwarfInfo, auxDwarfLoc, auxDwarfRanges, auxDwarfLines Sym) {
+ if l.SymType(fnSymIdx) != sym.STEXT {
+ log.Fatalf("error: non-function sym %d/%s t=%s passed to GetFuncDwarfAuxSyms", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
+ }
+ if l.IsExternal(fnSymIdx) {
+ // Current expectation is that any external function will
+ // not have auxsyms.
+ return
+ }
+ naux := l.NAux(fnSymIdx)
+ if naux == 0 {
+ return
+ }
+ r, li := l.toLocal(fnSymIdx)
+ for i := 0; i < naux; i++ {
+ a := goobj2.Aux{}
+ a.Read(r.Reader, r.AuxOff(li, i))
+ switch a.Type {
+ case goobj2.AuxDwarfInfo:
+ auxDwarfInfo = l.resolve(r, a.Sym)
+ if l.SymType(auxDwarfInfo) != sym.SDWARFINFO {
+ panic("aux dwarf info sym with wrong type")
+ }
+ case goobj2.AuxDwarfLoc:
+ auxDwarfLoc = l.resolve(r, a.Sym)
+ if l.SymType(auxDwarfLoc) != sym.SDWARFLOC {
+ panic("aux dwarf loc sym with wrong type")
+ }
+ case goobj2.AuxDwarfRanges:
+ auxDwarfRanges = l.resolve(r, a.Sym)
+ if l.SymType(auxDwarfRanges) != sym.SDWARFRANGE {
+ panic("aux dwarf ranges sym with wrong type")
+ }
+ case goobj2.AuxDwarfLines:
+ auxDwarfLines = l.resolve(r, a.Sym)
+ if l.SymType(auxDwarfLines) != sym.SDWARFLINES {
+ panic("aux dwarf lines sym with wrong type")
+ }
+ }
+ }
+ return
+}
+
// ReadAuxSyms reads the aux symbol ids for the specified symbol into the
// slice passed as a parameter. If the slice capacity is not large enough, a new
// larger slice will be allocated. Final slice is returned.
@@ -550,51 +1325,123 @@
dst = dst[:0]
r, li := l.toLocal(symIdx)
+ a := goobj2.Aux{}
for i := 0; i < naux; i++ {
- a := goobj2.Aux{}
- a.Read(r.Reader, r.AuxOff(li, i))
+ a.ReadSym(r.Reader, r.AuxOff(li, i))
dst = append(dst, l.resolve(r, a.Sym))
}
return dst
}
+// PrependSub prepends 'sub' onto the sub list for outer symbol 'outer'.
+// Will panic if 'sub' already has an outer sym or sub sym.
+// FIXME: should this be instead a method on SymbolBuilder?
+func (l *Loader) PrependSub(outer Sym, sub Sym) {
+ // NB: this presupposes that an outer sym can't be a sub symbol of
+ // some other outer-outer sym (I'm assuming this is true, but I
+ // haven't tested exhaustively).
+ if l.OuterSym(outer) != 0 {
+ panic("outer has outer itself")
+ }
+ if l.SubSym(sub) != 0 {
+ panic("sub set for subsym")
+ }
+ if l.OuterSym(sub) != 0 {
+ panic("outer already set for subsym")
+ }
+ l.sub[sub] = l.sub[outer]
+ l.sub[outer] = sub
+ l.outer[sub] = outer
+}
+
// OuterSym gets the outer symbol for host object loaded symbols.
func (l *Loader) OuterSym(i Sym) Sym {
- sym := l.Syms[i]
- if sym != nil && sym.Outer != nil {
- outer := sym.Outer
- return l.Lookup(outer.Name, int(outer.Version))
- }
- return 0
+ // FIXME: add check for isExternal?
+ return l.outer[i]
}
// SubSym gets the subsymbol for host object loaded symbols.
func (l *Loader) SubSym(i Sym) Sym {
- sym := l.Syms[i]
- if sym != nil && sym.Sub != nil {
- sub := sym.Sub
- return l.Lookup(sub.Name, int(sub.Version))
- }
- return 0
+ // NB: note -- no check for l.isExternal(), since I am pretty sure
+ // that later phases in the linker set subsym for "type." syms
+ return l.sub[i]
}
-// Initialize Reachable bitmap for running deadcode pass.
+// Initialize Reachable bitmap and its siblings for running deadcode pass.
func (l *Loader) InitReachable() {
- l.Reachable = makeBitmap(l.NSym())
+ l.growAttrBitmaps(l.NSym() + 1)
+}
+
+type symWithVal struct {
+ s Sym
+ v int64
+}
+type bySymValue []symWithVal
+
+func (s bySymValue) Len() int { return len(s) }
+func (s bySymValue) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s bySymValue) Less(i, j int) bool { return s[i].v < s[j].v }
+
+// SortSub walks through the sub-symbols for 's' and sorts them
+// in place by increasing value. Return value is the new
+// sub symbol for the specified outer symbol.
+func (l *Loader) SortSub(s Sym) Sym {
+
+ if s == 0 || l.sub[s] == 0 {
+ return s
+ }
+
+ // Sort symbols using a slice first. Use a stable sort on the off
+ // chance that there's more than once symbol with the same value,
+ // so as to preserve reproducible builds.
+ sl := []symWithVal{}
+ for ss := l.sub[s]; ss != 0; ss = l.sub[ss] {
+ sl = append(sl, symWithVal{s: ss, v: l.SymValue(ss)})
+ }
+ sort.Stable(bySymValue(sl))
+
+ // Then apply any changes needed to the sub map.
+ ns := Sym(0)
+ for i := len(sl) - 1; i >= 0; i-- {
+ s := sl[i].s
+ l.sub[s] = ns
+ ns = s
+ }
+
+ // Update sub for outer symbol, then return
+ l.sub[s] = sl[0].s
+ return sl[0].s
+}
+
+// Insure that reachable bitmap and its siblings have enough size.
+func (l *Loader) growAttrBitmaps(reqLen int) {
+ if reqLen > l.attrReachable.Len() {
+ // These are indexed by global symbol
+ l.attrReachable = growBitmap(reqLen, l.attrReachable)
+ l.attrOnList = growBitmap(reqLen, l.attrOnList)
+ l.attrLocal = growBitmap(reqLen, l.attrLocal)
+ l.attrNotInSymbolTable = growBitmap(reqLen, l.attrNotInSymbolTable)
+ }
+ l.growExtAttrBitmaps()
+}
+
+func (l *Loader) growExtAttrBitmaps() {
+ // These are indexed by external symbol index (e.g. l.extIndex(i))
+ extReqLen := len(l.payloads)
+ if extReqLen > l.attrVisibilityHidden.Len() {
+ l.attrVisibilityHidden = growBitmap(extReqLen, l.attrVisibilityHidden)
+ l.attrDuplicateOK = growBitmap(extReqLen, l.attrDuplicateOK)
+ l.attrShared = growBitmap(extReqLen, l.attrShared)
+ l.attrExternal = growBitmap(extReqLen, l.attrExternal)
+ }
}
// At method returns the j-th reloc for a global symbol.
func (relocs *Relocs) At(j int) Reloc {
- if relocs.ext != nil {
- rel := &relocs.ext.R[j]
- return Reloc{
- Off: rel.Off,
- Size: rel.Siz,
- Type: rel.Type,
- Add: rel.Add,
- Sym: relocs.l.Lookup(rel.Sym.Name, int(rel.Sym.Version)),
- }
+ if relocs.l.isExtReader(relocs.r) {
+ pp := relocs.l.payloads[relocs.li]
+ return pp.relocs[j]
}
rel := goobj2.Reloc{}
rel.Read(relocs.r.Reader, relocs.r.RelocOff(relocs.li, j))
@@ -608,10 +1455,35 @@
}
}
+func (relocs *Relocs) At2(j int) Reloc2 {
+ if relocs.l.isExtReader(relocs.r) {
+ pp := relocs.l.payloads[relocs.li]
+ r := pp.relocs[j]
+ // XXX populate a goobj2.Reloc from external reloc record.
+ // Ugly. Maybe we just want to use this format to store the
+ // reloc record in the first place?
+ var b goobj2.Reloc2
+ b.Set(r.Off, r.Size, uint8(r.Type), r.Add, goobj2.SymRef{PkgIdx: 0, SymIdx: uint32(r.Sym)})
+ return Reloc2{&b, relocs.r, relocs.l}
+ }
+ return Reloc2{relocs.r.Reloc2(relocs.li, j), relocs.r, relocs.l}
+}
+
// ReadAll method reads all relocations for a symbol into the
// specified slice. If the slice capacity is not large enough, a new
// larger slice will be allocated. Final slice is returned.
func (relocs *Relocs) ReadAll(dst []Reloc) []Reloc {
+ return relocs.readAll(dst, false)
+}
+
+// ReadSyms method reads all relocation target symbols and reloc types
+// for a symbol into the specified slice. It is like ReadAll but only
+// fill in the Sym and Type fields.
+func (relocs *Relocs) ReadSyms(dst []Reloc) []Reloc {
+ return relocs.readAll(dst, true)
+}
+
+func (relocs *Relocs) readAll(dst []Reloc, onlySymType bool) []Reloc {
if relocs.Count == 0 {
return dst[:0]
}
@@ -621,25 +1493,20 @@
}
dst = dst[:0]
- if relocs.ext != nil {
- for i := 0; i < relocs.Count; i++ {
- erel := &relocs.ext.R[i]
- rel := Reloc{
- Off: erel.Off,
- Size: erel.Siz,
- Type: erel.Type,
- Add: erel.Add,
- Sym: relocs.l.Lookup(erel.Sym.Name, int(erel.Sym.Version)),
- }
- dst = append(dst, rel)
- }
+ if relocs.l.isExtReader(relocs.r) {
+ pp := relocs.l.payloads[relocs.li]
+ dst = append(dst, pp.relocs...)
return dst
}
off := relocs.r.RelocOff(relocs.li, 0)
+ rel := goobj2.Reloc{}
for i := 0; i < relocs.Count; i++ {
- rel := goobj2.Reloc{}
- rel.Read(relocs.r.Reader, off)
+ if onlySymType {
+ rel.ReadSymType(relocs.r.Reader, off)
+ } else {
+ rel.Read(relocs.r.Reader, off)
+ }
off += uint32(rel.Size())
target := relocs.l.resolve(relocs.r, rel.Sym)
dst = append(dst, Reloc{
@@ -655,29 +1522,79 @@
// Relocs returns a Relocs object for the given global sym.
func (l *Loader) Relocs(i Sym) Relocs {
- if l.IsExternal(i) {
- if s := l.Syms[i]; s != nil {
- return Relocs{Count: len(s.R), l: l, ext: s}
- }
- return Relocs{}
- }
r, li := l.toLocal(i)
+ if r == nil {
+ panic(fmt.Sprintf("trying to get oreader for invalid sym %d\n\n", i))
+ }
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 {
+ var n int
+ if l.isExtReader(r) {
+ pp := l.payloads[li]
+ n = len(pp.relocs)
+ } else {
+ n = r.NReloc(li)
+ }
return Relocs{
- Count: r.NReloc(li),
+ Count: n,
li: li,
r: r,
l: l,
}
}
-// Preload a package: add autolibs, add symbols to the symbol table.
-// Does not read symbol data yet.
-func (l *Loader) Preload(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) {
+// RelocByOff implements sort.Interface for sorting relocations by offset.
+
+type RelocByOff []Reloc
+
+func (x RelocByOff) Len() int { return len(x) }
+func (x RelocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x RelocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
+
+// FuncInfo provides hooks to access goobj2.FuncInfo in the objects.
+type FuncInfo struct {
+ l *Loader
+ r *oReader
+ data []byte
+}
+
+func (fi *FuncInfo) Valid() bool { return fi.r != nil }
+
+func (fi *FuncInfo) Locals() int {
+ return int((*goobj2.FuncInfo)(nil).ReadLocals(fi.data))
+}
+
+func (fi *FuncInfo) Pcsp() []byte {
+ pcsp, end := (*goobj2.FuncInfo)(nil).ReadPcsp(fi.data)
+ return fi.r.BytesAt(fi.r.PcdataBase()+pcsp, int(end-pcsp))
+}
+
+// TODO: more accessors.
+
+func (l *Loader) FuncInfo(i Sym) FuncInfo {
+ if l.IsExternal(i) {
+ return FuncInfo{}
+ }
+ r, li := l.toLocal(i)
+ n := r.NAux(li)
+ for j := 0; j < n; j++ {
+ a := goobj2.Aux{}
+ a.Read(r.Reader, r.AuxOff(li, j))
+ if a.Type == goobj2.AuxFuncInfo {
+ b := r.Data(int(a.Sym.SymIdx))
+ return FuncInfo{l, r, b}
+ }
+ }
+ return FuncInfo{}
+}
+
+// Preload a package: add autolibs, add defined package symbols to the symbol table.
+// Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
+// Does not read symbol data.
+func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, flags int) {
roObject, readonly, err := f.Slice(uint64(length))
if err != nil {
log.Fatal("cannot read object file:", err)
@@ -688,7 +1605,9 @@
}
localSymVersion := syms.IncVersion()
pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
- or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, nil}
+ ndef := r.NSym()
+ nnonpkgdef := r.NNonpkgdef()
+ or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, make([]Sym, ndef+nnonpkgdef+r.NNonpkgref()), ndef, uint32(len(l.objs))}
// Autolib
lib.ImportStrings = append(lib.ImportStrings, r.Autolib()...)
@@ -700,51 +1619,80 @@
unit.DWARFFileTable[i] = r.DwarfFile(i)
}
- istart := l.addObj(lib.Pkg, or)
-
- ndef := r.NSym()
- nnonpkgdef := r.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.Dupok()
- added := l.AddSym(name, v, istart+Sym(i), or, dupok, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)])
- if added && strings.HasPrefix(name, "go.itablink.") {
- l.itablink[istart+Sym(i)] = struct{}{}
- }
- if added && strings.HasPrefix(name, "runtime.") {
- if bi := goobj2.BuiltinIdx(name, v); bi != -1 {
- // This is a definition of a builtin symbol. Record where it is.
- l.builtinSyms[bi] = istart + Sym(i)
- }
- }
- }
+ l.addObj(lib.Pkg, or)
+ l.preloadSyms(or, pkgDef)
// 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 (l *Loader) LoadRefs(arch *sys.Arch, syms *sym.Symbols) {
- for _, o := range l.objs[1:] {
- loadObjRefs(l, o.r, arch, syms)
+// Preload symbols of given kind from an object.
+func (l *Loader) preloadSyms(r *oReader, kind int) {
+ ndef := r.NSym()
+ nnonpkgdef := r.NNonpkgdef()
+ var start, end int
+ switch kind {
+ case pkgDef:
+ start = 0
+ end = ndef
+ case nonPkgDef:
+ start = ndef
+ end = ndef + nnonpkgdef
+ default:
+ panic("preloadSyms: bad kind")
+ }
+ l.growSyms(len(l.objSyms) + end - start)
+ l.growAttrBitmaps(len(l.objSyms) + end - start)
+ for i := start; i < end; i++ {
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(i))
+ name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
+ v := abiToVer(osym.ABI, r.version)
+ dupok := osym.Dupok()
+ gi, added := l.AddSym(name, v, r, i, kind, dupok, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)])
+ r.syms[i] = gi
+ if !added {
+ continue
+ }
+ if osym.TopFrame() {
+ l.SetAttrTopFrame(gi, true)
+ }
+ if strings.HasPrefix(name, "go.itablink.") {
+ l.itablink[gi] = struct{}{}
+ }
+ if strings.HasPrefix(name, "runtime.") {
+ if bi := goobj2.BuiltinIdx(name, v); bi != -1 {
+ // This is a definition of a builtin symbol. Record where it is.
+ l.builtinSyms[bi] = gi
+ }
+ }
+ if strings.HasPrefix(name, "go.string.") ||
+ strings.HasPrefix(name, "gclocals·") ||
+ strings.HasPrefix(name, "runtime.gcbits.") {
+ l.SetAttrNotInSymbolTable(gi, true)
+ }
}
}
-func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch, syms *sym.Symbols) {
+// Add non-package symbols and references to external symbols (which are always
+// named).
+func (l *Loader) LoadNonpkgSyms(syms *sym.Symbols) {
+ for _, o := range l.objs[1:] {
+ l.preloadSyms(o.r, nonPkgDef)
+ }
+ for _, o := range l.objs[1:] {
+ loadObjRefs(l, o.r, syms)
+ }
+}
+
+func loadObjRefs(l *Loader, r *oReader, syms *sym.Symbols) {
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, "\"\".", r.pkgprefix, -1)
v := abiToVer(osym.ABI, r.version)
- l.AddExtSym(name, v)
+ r.syms[ndef+i] = l.AddExtSym(name, v)
}
}
@@ -794,22 +1742,65 @@
nr += loadObjSyms(l, syms, o.r)
}
+ // Make a first pass through the external symbols, making
+ // sure that each external symbol has a non-nil entry in
+ // l.Syms (note that relocations and symbol content will
+ // be copied in a later loop).
+ toConvert := make([]Sym, 0, len(l.payloads))
+ for _, i := range l.extReader.syms {
+ sname := l.RawSymName(i)
+ if !l.attrReachable.Has(i) && !strings.HasPrefix(sname, "gofile..") { // XXX file symbols are used but not marked
+ continue
+ }
+ pp := l.getPayload(i)
+ nr += len(pp.relocs)
+ // create and install the sym.Symbol here so that l.Syms will
+ // be fully populated when we do relocation processing and
+ // outer/sub processing below. Note that once we do this,
+ // we'll need to get at the payload for a symbol with direct
+ // reference to l.payloads[] as opposed to calling l.getPayload().
+ s := l.allocSym(sname, 0)
+ l.installSym(i, s)
+ toConvert = append(toConvert, i)
+ }
+
// allocate a single large slab of relocations for all live symbols
l.relocBatch = make([]sym.Reloc, nr)
- // external symbols
- for i := l.extStart; i <= l.max; i++ {
- if s := l.Syms[i]; s != nil {
- s.Attr.Set(sym.AttrReachable, l.Reachable.Has(i))
- continue // already loaded from external object
+ // convert payload-based external symbols into sym.Symbol-based
+ for _, i := range toConvert {
+
+ // Copy kind/size/value etc.
+ pp := l.payloads[l.extIndex(i)]
+ s := l.Syms[i]
+ s.Version = int16(pp.ver)
+ s.Type = pp.kind
+ s.Size = pp.size
+ s.Value = l.SymValue(i)
+ if pp.gotype != 0 {
+ s.Gotype = l.Syms[pp.gotype]
}
- nv := l.extSyms[i-l.extStart]
- if l.Reachable.Has(i) || strings.HasPrefix(nv.name, "gofile..") { // XXX file symbols are used but not marked
- s := syms.Newsym(nv.name, nv.v)
- preprocess(arch, s)
- s.Attr.Set(sym.AttrReachable, l.Reachable.Has(i))
- l.Syms[i] = s
+ s.Value = l.values[i]
+ if f, ok := l.symFile[i]; ok {
+ s.File = f
+ } else if pp.objidx != 0 {
+ s.File = l.objs[pp.objidx].r.unit.Lib.File
}
+
+ // Copy relocations
+ batch := l.relocBatch
+ s.R = batch[:len(pp.relocs):len(pp.relocs)]
+ l.relocBatch = batch[len(pp.relocs):]
+ l.convertRelocations(pp.relocs, s, false)
+
+ // Copy data
+ s.P = pp.data
+
+ // Transfer over attributes.
+ l.migrateAttributes(i, s)
+
+ // Preprocess symbol. May set 'AttrLocal'.
+ preprocess(arch, s)
}
// load contents of defined symbols
@@ -817,11 +1808,15 @@
loadObjFull(l, o.r)
}
+ // Note: resolution of ABI aliases is now also handled in
+ // loader.convertRelocations, so once the host object loaders move
+ // completely to loader.Sym, we can remove the code below.
+
// Resolve ABI aliases for external symbols. This is only
// needed for internal cgo linking.
// (The old code does this in deadcode, but deadcode2 doesn't
// do this.)
- for i := l.extStart; i <= l.max; i++ {
+ for _, i := range l.extReader.syms {
if s := l.Syms[i]; s != nil && s.Attr.Reachable() {
for ri := range s.R {
r := &s.R[ri]
@@ -833,40 +1828,283 @@
}
}
-// ExtractSymbols grabs the symbols out of the loader for work that hasn't been
-// ported to the new symbol type.
-func (l *Loader) ExtractSymbols(syms *sym.Symbols) {
- // Nil out overwritten symbols.
- // Overwritten Go symbols aren't a problem (as they're lazy loaded), but
- // symbols loaded from host object loaders are fully loaded, and we might
- // have multiple symbols with the same name. This loop nils them out.
- for oldI := range l.overwrite {
- l.Syms[oldI] = nil
+// PropagateSymbolChangesBackToLoader is a temporary shim function
+// that copies over a given sym.Symbol into the equivalent representation
+// in the loader world. The intent is to enable converting a given
+// linker phase/pass from dealing with sym.Symbol's to a modernized
+// pass that works with loader.Sym, in cases where the "loader.Sym
+// wavefront" has not yet reached the pass in question. For such work
+// the recipe is to first call PropagateSymbolChangesBackToLoader(),
+// then exexute the pass working with the loader, then call
+// PropagateLoaderChangesToSymbols to copy the changes made by the
+// pass back to the sym.Symbol world.
+func (l *Loader) PropagateSymbolChangesBackToLoader() {
+
+ // For the moment we only copy symbol values, and we don't touch
+ // any new sym.Symbols created since loadlibfull() was run. This
+ // seems to be what's needed for DWARF gen.
+ for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
+ s := l.Syms[i]
+ if s != nil {
+ if s.Value != l.SymValue(i) {
+ l.SetSymValue(i, s.Value)
+ }
+ }
+ }
+}
+
+// PropagateLoaderChangesToSymbols is a temporary shim function that
+// takes a list of loader.Sym symbols and works to copy their contents
+// and attributes over to a corresponding sym.Symbol. See the
+// PropagateSymbolChangesBackToLoader header comment for more info.
+//
+// WARNING: this function is brittle and depends heavily on loader
+// implementation. A key problem with doing this is that as things
+// stand at the moment, some sym.Symbol contents/attributes are
+// populated only when converting from loader.Sym to sym.Symbol
+// in loadlibfull, meaning if we may wipe out some information
+// when copying back.
+
+func (l *Loader) PropagateLoaderChangesToSymbols(toconvert []Sym, syms *sym.Symbols) []*sym.Symbol {
+
+ result := []*sym.Symbol{}
+ relocfixup := []Sym{}
+
+ // Note: this loop needs to allow for the possibility that we may
+ // see "new" symbols on the 'toconvert' list that come from object
+ // files (for example, DWARF location lists), as opposed to just
+ // newly manufactured symbols (ex: DWARF section symbols such as
+ // ".debug_info"). This means that we have to be careful not to
+ // stomp on sym.Symbol attributes/content that was set up in
+ // in loadlibfull().
+
+ // Also note that in order for the relocation fixup to work, we
+ // have to do this in two passes -- one pass to create the symbols,
+ // and then a second fix up the relocations once all necessary
+ // sym.Symbols are created.
+
+ // First pass, symbol creation and symbol data fixup.
+ anonVerReplacement := syms.IncVersion()
+ rslice := []Reloc{}
+ for _, cand := range toconvert {
+
+ sn := l.SymName(cand)
+ sv := l.SymVersion(cand)
+ st := l.SymType(cand)
+ if sv < 0 {
+ sv = anonVerReplacement
+ }
+
+ s := l.Syms[cand]
+
+ isnew := false
+ if sn == "" {
+ // Don't install anonymous symbols in the lookup tab.
+ if s == nil {
+ s = l.allocSym(sn, sv)
+ l.installSym(cand, s)
+ }
+ isnew = true
+ } else {
+ if s != nil {
+ // Already have a symbol for this -- it must be
+ // something that was previously processed by
+ // loadObjFull. Note that the symbol in question may
+ // or may not be in the name lookup map.
+ } else {
+ isnew = true
+ s = syms.Lookup(sn, sv)
+ }
+ }
+ result = append(result, s)
+
+ // Always copy these from new to old.
+ s.Value = l.SymValue(cand)
+ s.Type = st
+
+ // If the data for a symbol has increased in size, make sure
+ // we bring the new content across.
+ relfix := isnew
+ if isnew || len(l.Data(cand)) > len(s.P) {
+ s.P = l.Data(cand)
+ s.Size = int64(len(s.P))
+ relfix = true
+ }
+
+ // For 'new' symbols, copy other content (such as Gotype,
+ // sym file, relocations, etc).
+ if isnew {
+ if gt := l.SymGoType(cand); gt != 0 {
+ s.Gotype = l.Syms[gt]
+ }
+ if f, ok := l.symFile[cand]; ok {
+ s.File = f
+ } else {
+ r, _ := l.toLocal(cand)
+ if r != nil && r != l.extReader {
+ s.File = l.SymFile(cand)
+ }
+ }
+ }
+
+ // If this symbol has any DWARF file relocations, we need to
+ // make sure that the relocations are copied back over, since
+ // DWARF-gen alters the offset values for these relocs. Also:
+ // if this is an info symbol and it refers to a previously
+ // unseen range/loc symbol, we'll need to fix up relocations
+ // for it as well.
+ relocs := l.Relocs(cand)
+ rslice = relocs.ReadSyms(rslice)
+ for ri := range rslice {
+ if rslice[ri].Type == objabi.R_DWARFFILEREF {
+ relfix = true
+ break
+ }
+ if st != sym.SDWARFINFO {
+ continue
+ }
+ rst := l.SymType(rslice[ri].Sym)
+ if rst == sym.SDWARFRANGE || rst == sym.SDWARFLOC {
+ relfix = true
+ break
+ }
+ }
+
+ if relfix {
+ relocfixup = append(relocfixup, cand)
+ }
+
+ // If new symbol, call a helper to migrate attributes.
+ // Otherwise touch only not-in-symbol-table, since there are
+ // some attrs that are only set up at the point where we
+ // convert loader.Sym to sym.Symbol.
+ if isnew {
+ l.migrateAttributes(cand, s)
+ } else {
+ if l.AttrNotInSymbolTable(cand) {
+ s.Attr.Set(sym.AttrNotInSymbolTable, true)
+ }
+ }
}
- // Add symbols to the ctxt.Syms lookup table. This explicitly
- // skips things created via loader.Create (marked with versions
- // less than zero), since if we tried to add these we'd wind up
- // with collisions. Along the way, update the version from the
- // negative anon version to something larger than sym.SymVerStatic
- // (needed so that sym.symbol.IsFileLocal() works properly).
+ // Second pass to fix up relocations.
+ for _, cand := range relocfixup {
+ s := l.Syms[cand]
+ relocs := l.Relocs(cand)
+ rslice = relocs.ReadAll(rslice)
+ s.R = make([]sym.Reloc, len(rslice))
+ l.convertRelocations(rslice, s, true)
+ }
+
+ return result
+}
+
+// ExtractSymbols grabs the symbols out of the loader for work that hasn't been
+// ported to the new symbol type.
+func (l *Loader) ExtractSymbols(syms *sym.Symbols, rp map[*sym.Symbol]*sym.Symbol) {
+ // Add symbols to the ctxt.Syms lookup table. This explicitly skips things
+ // created via loader.Create (marked with versions less than zero), since
+ // if we tried to add these we'd wind up with collisions. We do, however,
+ // add these symbols to the list of global symbols so that other future
+ // steps (like pclntab generation) can find these symbols if neceassary.
+ // Along the way, update the version from the negative anon version to
+ // something larger than sym.SymVerStatic (needed so that
+ // sym.symbol.IsFileLocal() works properly).
anonVerReplacement := syms.IncVersion()
for _, s := range l.Syms {
if s == nil {
continue
}
- if s.Name != "" && s.Version >= 0 {
- syms.Add(s)
- }
+ syms.Allsym = append(syms.Allsym, s) // XXX still add to Allsym for now, as there are code looping through Allsym
if s.Version < 0 {
s.Version = int16(anonVerReplacement)
}
}
+
+ for i, s := range l.Reachparent {
+ if i == 0 {
+ continue
+ }
+ rp[l.Syms[i]] = l.Syms[s]
+ }
+
+ // Provide lookup functions for sym.Symbols.
+ syms.Lookup = func(name string, ver int) *sym.Symbol {
+ i := l.LookupOrCreateSym(name, ver)
+ if s := l.Syms[i]; s != nil {
+ return s
+ }
+ s := l.allocSym(name, ver)
+ l.installSym(i, s)
+ syms.Allsym = append(syms.Allsym, s) // XXX see above
+ return s
+ }
+ syms.ROLookup = func(name string, ver int) *sym.Symbol {
+ i := l.Lookup(name, ver)
+ return l.Syms[i]
+ }
+ syms.Rename = func(old, new string, ver int) {
+ // annoying... maybe there is a better way to do this
+ if ver >= 2 {
+ panic("cannot rename static symbol")
+ }
+ i := l.Lookup(old, ver)
+ s := l.Syms[i]
+ s.Name = new
+ if s.Extname() == old {
+ s.SetExtname(new)
+ }
+ delete(l.symsByName[ver], old)
+
+ // This mirrors the old code. But I'm not sure if the logic of
+ // handling dup in the old code actually works, or necessary.
+ dupi := l.symsByName[ver][new]
+ dup := l.Syms[dupi]
+ if dup == nil {
+ l.symsByName[ver][new] = i
+ } else {
+ if s.Type == 0 {
+ dup.Attr |= s.Attr
+ *s = *dup
+ } else if dup.Type == 0 {
+ s.Attr |= dup.Attr
+ *dup = *s
+ l.symsByName[ver][new] = i
+ }
+ }
+ }
+}
+
+// allocSym allocates a new symbol backing.
+func (l *Loader) allocSym(name string, version int) *sym.Symbol {
+ batch := l.symBatch
+ if len(batch) == 0 {
+ batch = make([]sym.Symbol, 1000)
+ }
+ s := &batch[0]
+ l.symBatch = batch[1:]
+
+ s.Dynid = -1
+ s.Name = name
+ s.Version = int16(version)
+
+ return s
+}
+
+// installSym sets the underlying sym.Symbol for the specified sym index.
+func (l *Loader) installSym(i Sym, s *sym.Symbol) {
+ if s == nil {
+ panic("installSym nil symbol")
+ }
+ if l.Syms[i] != nil {
+ panic("sym already present in installSym")
+ }
+ l.Syms[i] = s
}
// addNewSym adds a new sym.Symbol to the i-th index in the list of symbols.
-func (l *Loader) addNewSym(i Sym, syms *sym.Symbols, name string, ver int, unit *sym.CompilationUnit, t sym.SymKind) *sym.Symbol {
- s := syms.Newsym(name, ver)
+func (l *Loader) addNewSym(i Sym, name string, ver int, unit *sym.CompilationUnit, t sym.SymKind) *sym.Symbol {
+ s := l.allocSym(name, ver)
if s.Type != 0 && s.Type != sym.SXREF {
fmt.Println("symbol already processed:", unit.Lib, i, s)
panic("symbol already processed")
@@ -877,7 +2115,7 @@
s.Type = t
s.Unit = unit
l.growSyms(int(i))
- l.Syms[i] = s
+ l.installSym(i, s)
return s
}
@@ -885,16 +2123,11 @@
// object corresponding to object reader "r". Return value is the
// number of sym.Reloc entries required for all the new symbols.
func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader) int {
- istart := l.startIndex(r)
nr := 0
-
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
- // If it's been previously loaded in host object loading, we don't need to do it again.
- if s := l.Syms[istart+Sym(i)]; s != nil {
- // Mark symbol as reachable as it wasn't marked as such before.
- s.Attr.Set(sym.AttrReachable, l.Reachable.Has(istart+Sym(i)))
- nr += r.NReloc(i)
- continue
+ gi := r.syms[i]
+ if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
+ continue // come from a different object
}
osym := goobj2.Sym{}
osym.Read(r.Reader, r.SymOff(i))
@@ -903,10 +2136,6 @@
continue
}
ver := abiToVer(osym.ABI, r.version)
- if osym.ABI != goobj2.SymABIstatic && l.symsByName[ver][name] != istart+Sym(i) {
- continue
- }
-
t := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
if t == sym.SXREF {
log.Fatalf("bad sxref")
@@ -914,15 +2143,14 @@
if t == 0 {
log.Fatalf("missing type for %s in %s", name, r.unit.Lib)
}
- if !l.Reachable.Has(istart+Sym(i)) && !(t == sym.SRODATA && strings.HasPrefix(name, "type.")) && name != "runtime.addmoduledata" && name != "runtime.lastmoduledatap" {
+ if !l.attrReachable.Has(gi) && name != "runtime.addmoduledata" && name != "runtime.lastmoduledatap" {
// No need to load unreachable symbols.
- // XXX some type symbol's content may be needed in DWARF code, but they are not marked.
// XXX reference to runtime.addmoduledata may be generated later by the linker in plugin mode.
continue
}
- s := l.addNewSym(istart+Sym(i), syms, name, ver, r.unit, t)
- s.Attr.Set(sym.AttrReachable, l.Reachable.Has(istart+Sym(i)))
+ s := l.addNewSym(gi, name, ver, r.unit, t)
+ l.migrateAttributes(gi, s)
nr += r.NReloc(i)
}
return nr
@@ -947,85 +2175,155 @@
fdOff uint32 // number of int64's needed in all Funcdataoff slices
}
-// LoadSymbol loads a single symbol by name.
-// This function should only be used by the host object loaders.
-// NB: This function does NOT set the symbol as reachable.
-func (l *Loader) LoadSymbol(name string, version int, syms *sym.Symbols) *sym.Symbol {
- global := l.Lookup(name, version)
-
- // If we're already loaded, bail.
- if global != 0 && int(global) < len(l.Syms) && l.Syms[global] != nil {
- return l.Syms[global]
+// cloneToExternal takes the existing object file symbol (symIdx)
+// and creates a new external symbol payload that is a clone with
+// respect to name, version, type, relocations, etc. The idea here
+// is that if the linker decides it wants to update the contents of
+// a symbol originally discovered as part of an object file, it's
+// easier to do this if we make the updates to an external symbol
+// payload.
+// XXX maybe rename? makeExtPayload?
+func (l *Loader) cloneToExternal(symIdx Sym) {
+ if l.IsExternal(symIdx) {
+ panic("sym is already external, no need for clone")
}
+ l.growSyms(int(symIdx))
- // Read the symbol.
- r, i := l.toLocal(global)
- istart := l.startIndex(r)
-
+ // Read the particulars from object.
osym := goobj2.Sym{}
- osym.Read(r.Reader, r.SymOff(int(i)))
- if l.symsByName[version][name] != istart+Sym(i) {
- return nil
+ r, li := l.toLocal(symIdx)
+ osym.Read(r.Reader, r.SymOff(li))
+ sname := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
+ sver := abiToVer(osym.ABI, r.version)
+ skind := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
+
+ // Create new symbol, update version and kind.
+ pi := l.newPayload(sname, sver)
+ pp := l.payloads[pi]
+ pp.kind = skind
+ pp.ver = sver
+ pp.size = int64(osym.Siz)
+ pp.objidx = r.objidx
+
+ // If this is a def, then copy the guts. We expect this case
+ // to be very rare (one case it may come up is with -X).
+ if li < (r.NSym() + r.NNonpkgdef()) {
+
+ // Copy relocations
+ relocs := l.Relocs(symIdx)
+ pp.relocs = relocs.ReadAll(nil)
+
+ // Copy data
+ pp.data = r.Data(li)
}
- return l.addNewSym(istart+Sym(i), syms, name, version, r.unit, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)])
+ // If we're overriding a data symbol, collect the associated
+ // Gotype, so as to propagate it to the new symbol.
+ naux := r.NAux(li)
+ for j := 0; j < naux; j++ {
+ a := goobj2.Aux{}
+ a.Read(r.Reader, r.AuxOff(li, j))
+ switch a.Type {
+ case goobj2.AuxGotype:
+ pp.gotype = l.resolve(r, a.Sym)
+ default:
+ log.Fatalf("internal error: cloneToExternal applied to %s symbol %s with non-gotype aux data %d", skind.String(), sname, a.Type)
+ }
+ }
+
+ // Install new payload to global index space.
+ // (This needs to happen at the end, as the accessors above
+ // need to access the old symbol content.)
+ l.objSyms[symIdx] = objSym{l.extReader, pi}
+ l.extReader.syms = append(l.extReader.syms, symIdx)
}
-// LookupOrCreate looks up a symbol by name, and creates one if not found.
-// Either way, it will also create a sym.Symbol for it, if not already.
-// This should only be called when interacting with parts of the linker
-// that still works on sym.Symbols (i.e. internal cgo linking, for now).
-func (l *Loader) LookupOrCreate(name string, version int, syms *sym.Symbols) *sym.Symbol {
- i := l.Lookup(name, version)
- if i != 0 {
- // symbol exists
- if int(i) < len(l.Syms) && l.Syms[i] != nil {
- return l.Syms[i] // already loaded
- }
- if l.IsExternal(i) {
- panic("Can't load an external symbol.")
- }
- return l.LoadSymbol(name, version, syms)
- }
- i = l.AddExtSym(name, version)
- s := syms.Newsym(name, version)
- l.Syms[i] = s
- return s
+// copyAttributes copies over all of the attributes of symbol 'src' to
+// symbol 'dst'. The assumption is that 'dst' is an external symbol.
+func (l *Loader) copyAttributes(src Sym, dst Sym) {
+ l.SetAttrReachable(dst, l.AttrReachable(src))
+ l.SetAttrOnList(dst, l.AttrOnList(src))
+ l.SetAttrLocal(dst, l.AttrLocal(src))
+ l.SetAttrNotInSymbolTable(dst, l.AttrNotInSymbolTable(src))
+ l.SetAttrVisibilityHidden(dst, l.AttrVisibilityHidden(src))
+ l.SetAttrDuplicateOK(dst, l.AttrDuplicateOK(src))
+ l.SetAttrShared(dst, l.AttrShared(src))
+ l.SetAttrExternal(dst, l.AttrExternal(src))
+ l.SetAttrTopFrame(dst, l.AttrTopFrame(src))
+ l.SetAttrSpecial(dst, l.AttrSpecial(src))
+ l.SetAttrCgoExportDynamic(dst, l.AttrCgoExportDynamic(src))
+ l.SetAttrCgoExportStatic(dst, l.AttrCgoExportStatic(src))
+ l.SetAttrReadOnly(dst, l.AttrReadOnly(src))
}
-// Create creates a symbol with the specified name, returning a
-// sym.Symbol object for it. This method is intended for static/hidden
-// symbols discovered while loading host objects. We can see more than
-// one instance of a given static symbol with the same name/version,
-// so we can't add them to the lookup tables "as is". Instead assign
-// them fictitious (unique) versions, starting at -1 and decreasing by
-// one for each newly created symbol, and record them in the
-// extStaticSyms hash.
-func (l *Loader) Create(name string, syms *sym.Symbols) *sym.Symbol {
- i := l.max + 1
- l.max++
- if l.extStart == 0 {
- l.extStart = i
+// migrateAttributes copies over all of the attributes of symbol 'src' to
+// sym.Symbol 'dst'.
+func (l *Loader) migrateAttributes(src Sym, dst *sym.Symbol) {
+ dst.Attr.Set(sym.AttrReachable, l.AttrReachable(src))
+ dst.Attr.Set(sym.AttrOnList, l.AttrOnList(src))
+ dst.Attr.Set(sym.AttrLocal, l.AttrLocal(src))
+ dst.Attr.Set(sym.AttrNotInSymbolTable, l.AttrNotInSymbolTable(src))
+ dst.Attr.Set(sym.AttrNoSplit, l.IsNoSplit(src))
+ dst.Attr.Set(sym.AttrVisibilityHidden, l.AttrVisibilityHidden(src))
+ dst.Attr.Set(sym.AttrDuplicateOK, l.AttrDuplicateOK(src))
+ dst.Attr.Set(sym.AttrShared, l.AttrShared(src))
+ dst.Attr.Set(sym.AttrExternal, l.AttrExternal(src))
+ dst.Attr.Set(sym.AttrTopFrame, l.AttrTopFrame(src))
+ dst.Attr.Set(sym.AttrSpecial, l.AttrSpecial(src))
+ dst.Attr.Set(sym.AttrCgoExportDynamic, l.AttrCgoExportDynamic(src))
+ dst.Attr.Set(sym.AttrCgoExportStatic, l.AttrCgoExportStatic(src))
+ dst.Attr.Set(sym.AttrReadOnly, l.AttrReadOnly(src))
+
+ // Convert outer/sub relationships
+ if outer, ok := l.outer[src]; ok {
+ dst.Outer = l.Syms[outer]
+ }
+ if sub, ok := l.sub[src]; ok {
+ dst.Sub = l.Syms[sub]
}
+ // Set sub-symbol attribute. FIXME: would be better to do away
+ // with this and just use l.OuterSymbol() != 0 elsewhere within
+ // the linker.
+ dst.Attr.Set(sym.AttrSubSymbol, dst.Outer != nil)
+
+ // Copy over dynimplib, dynimpvers, extname.
+ if l.SymExtname(src) != "" {
+ dst.SetExtname(l.SymExtname(src))
+ }
+ if l.SymDynimplib(src) != "" {
+ dst.SetDynimplib(l.SymDynimplib(src))
+ }
+ if l.SymDynimpvers(src) != "" {
+ dst.SetDynimpvers(l.SymDynimpvers(src))
+ }
+
+ // Copy ELF type if set.
+ if et, ok := l.elfType[src]; ok {
+ dst.SetElfType(et)
+ }
+
+ // Copy pe objects values if set.
+ if plt, ok := l.plt[src]; ok {
+ dst.SetPlt(plt)
+ }
+ if got, ok := l.got[src]; ok {
+ dst.SetGot(got)
+ }
+}
+
+// CreateExtSym creates a new external symbol with the specified name
+// without adding it to any lookup tables, returning a Sym index for it.
+func (l *Loader) CreateExtSym(name string) Sym {
// Assign a new unique negative version -- this is to mark the
// symbol so that it can be skipped when ExtractSymbols is adding
// ext syms to the sym.Symbols hash.
l.anonVersion--
- ver := l.anonVersion
- l.extSyms = append(l.extSyms, nameVer{name, ver})
- l.growSyms(int(i))
- s := syms.Newsym(name, ver)
- l.Syms[i] = s
- l.extStaticSyms[nameVer{name, ver}] = i
-
- return s
+ return l.newExtSym(name, l.anonVersion)
}
func loadObjFull(l *Loader, r *oReader) {
lib := r.unit.Lib
- istart := l.startIndex(r)
-
resolveSymRef := func(s goobj2.SymRef) *sym.Symbol {
i := l.resolve(r, s)
return l.Syms[i]
@@ -1037,36 +2335,37 @@
pcdataBase := r.PcdataBase()
rslice := []Reloc{}
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
- osym := goobj2.Sym{}
- osym.Read(r.Reader, r.SymOff(i))
- name := strings.Replace(osym.Name, "\"\".", r.pkgprefix, -1)
- if name == "" {
- continue
- }
- ver := abiToVer(osym.ABI, r.version)
- dupok := osym.Dupok()
- if dupok {
- if dupsym := l.symsByName[ver][name]; dupsym != istart+Sym(i) {
- if l.Reachable.Has(dupsym) {
- // A dupok symbol is resolved to another package. We still need
- // to record its presence in the current package, as the trampoline
- // pass expects packages are laid out in dependency order.
- s := l.Syms[dupsym]
- if s.Type == sym.STEXT {
- lib.DupTextSyms = append(lib.DupTextSyms, s)
- }
- }
- continue
- }
+ // A symbol may be a dup or overwritten. In this case, its
+ // content will actually be provided by a different object
+ // (to which its global index points). Skip those symbols.
+ gi := l.toGlobal(r, i)
+ var isdup bool
+ if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
+ isdup = true
}
- s := l.Syms[istart+Sym(i)]
- if s == nil {
+ osym := goobj2.Sym{}
+ osym.ReadWithoutName(r.Reader, r.SymOff(i))
+ dupok := osym.Dupok()
+ if dupok && isdup {
+ if l.attrReachable.Has(gi) {
+ // A dupok symbol is resolved to another package. We still need
+ // to record its presence in the current package, as the trampoline
+ // pass expects packages are laid out in dependency order.
+ s := l.Syms[gi]
+ if s.Type == sym.STEXT {
+ lib.DupTextSyms = append(lib.DupTextSyms, s)
+ }
+ }
continue
}
- 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 isdup {
+ continue // come from a different object
+ }
+ s := l.Syms[gi]
+ if s == nil {
+ continue
}
local := osym.Local()
@@ -1083,35 +2382,7 @@
batch := l.relocBatch
s.R = batch[:relocs.Count:relocs.Count]
l.relocBatch = batch[relocs.Count:]
- for j := range s.R {
- r := rslice[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],
- }
- }
+ l.convertRelocations(rslice, s, false)
// Aux symbol info
isym := -1
@@ -1149,14 +2420,6 @@
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
}
@@ -1203,7 +2466,7 @@
info := goobj2.FuncInfo{}
info.Read(b)
- if info.NoSplit != 0 {
+ if osym.NoSplit() {
s.Attr |= sym.AttrNoSplit
}
if osym.ReflectMethod() {
@@ -1283,43 +2546,168 @@
}
}
-var emptyPkg = []byte(`"".`)
-
-func patchDWARFName1(p []byte, r *oReader) ([]byte, int) {
- // This is kind of ugly. Really the package name should not
- // even be included here.
- if len(p) < 1 || p[0] != dwarf.DW_ABRV_FUNCTION {
- return p, -1
- }
- e := bytes.IndexByte(p, 0)
- if e == -1 {
- return p, -1
- }
- if !bytes.Contains(p[:e], emptyPkg) {
- return p, -1
- }
- pkgprefix := []byte(r.pkgprefix)
- patched := bytes.Replace(p[:e], emptyPkg, pkgprefix, -1)
- return append(patched, p[e:]...), e
-}
-
-func patchDWARFName(s *sym.Symbol, r *oReader) {
- patched, e := patchDWARFName1(s.P, r)
- if e == -1 {
- return
- }
- s.P = patched
- 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)
+// convertRelocations takes a vector of loader.Reloc relocations and
+// translates them into an equivalent set of sym.Reloc relocations on
+// the symbol "dst", performing fixups along the way for ABI aliases,
+// etc. It is assumed that the caller has pre-allocated the dst symbol
+// relocations slice. If 'strict' is set, then this method will
+// panic if it finds a relocation targeting a nil symbol.
+func (l *Loader) convertRelocations(src []Reloc, dst *sym.Symbol, strict bool) {
+ for j := range dst.R {
+ r := src[j]
+ rs := r.Sym
+ sz := r.Size
+ rt := r.Type
+ if rt == objabi.R_METHODOFF {
+ if l.attrReachable.Has(rs) {
+ rt = objabi.R_ADDROFF
+ } else {
+ sz = 0
+ rs = 0
+ }
+ }
+ if rt == objabi.R_WEAKADDROFF && !l.attrReachable.Has(rs) {
+ rs = 0
+ sz = 0
+ }
+ if rs != 0 && l.Syms[rs] != nil && l.Syms[rs].Type == sym.SABIALIAS {
+ rsrelocs := l.Relocs(rs)
+ rs = rsrelocs.At(0).Sym
+ }
+ if strict && rs != 0 && l.Syms[rs] == nil && rt != objabi.R_USETYPE {
+ panic("nil reloc target in convertRelocations")
+ }
+ dst.R[j] = sym.Reloc{
+ Off: r.Off,
+ Siz: sz,
+ Type: rt,
+ Add: r.Add,
+ Sym: l.Syms[rs],
}
}
}
+// UndefinedRelocTargets iterates through the global symbol index
+// space, looking for symbols with relocations targeting undefined
+// references. The linker's loadlib method uses this to determine if
+// there are unresolved references to functions in system libraries
+// (for example, libgcc.a), presumably due to CGO code. Return
+// value is a list of loader.Sym's corresponding to the undefined
+// cross-refs. The "limit" param controls the maximum number of
+// results returned; if "limit" is -1, then all undefs are returned.
+func (l *Loader) UndefinedRelocTargets(limit int) []Sym {
+ result := []Sym{}
+ rslice := []Reloc{}
+ for si := Sym(1); si < Sym(len(l.objSyms)); si++ {
+ relocs := l.Relocs(si)
+ rslice = relocs.ReadSyms(rslice)
+ for ri := 0; ri < relocs.Count; ri++ {
+ r := &rslice[ri]
+ if r.Sym != 0 && l.SymType(r.Sym) == sym.SXREF && l.RawSymName(r.Sym) != ".got" {
+ result = append(result, r.Sym)
+ if limit != -1 && len(result) >= limit {
+ break
+ }
+ }
+ }
+ }
+ return result
+}
+
+// AssignTextSymbolOrder populates the Textp2 slices within each
+// library and compilation unit, insuring that packages are laid down
+// in dependency order (internal first, then everything else). Return value
+// is a slice of all text syms.
+func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, extsyms []Sym) []Sym {
+
+ // Library Textp2 lists should be empty at this point.
+ for _, lib := range libs {
+ if len(lib.Textp2) != 0 {
+ panic("expected empty Textp2 slice for library")
+ }
+ if len(lib.DupTextSyms2) != 0 {
+ panic("expected empty DupTextSyms2 slice for library")
+ }
+ }
+
+ // Used to record which dupok symbol we've assigned to a unit.
+ // Can't use the onlist attribute here because it will need to
+ // clear for the later assignment of the sym.Symbol to a unit.
+ // NB: we can convert to using onList once we no longer have to
+ // call the regular addToTextp.
+ assignedToUnit := MakeBitmap(l.NSym() + 1)
+
+ // Start off textp2 with reachable external syms.
+ textp2 := []Sym{}
+ for _, sym := range extsyms {
+ if !l.attrReachable.Has(sym) {
+ continue
+ }
+ textp2 = append(textp2, sym)
+ }
+
+ // Walk through all text symbols from Go object files and append
+ // them to their corresponding library's textp2 list.
+ for _, o := range l.objs[1:] {
+ r := o.r
+ lib := r.unit.Lib
+ for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
+ gi := l.toGlobal(r, i)
+ if !l.attrReachable.Has(gi) {
+ continue
+ }
+ osym := goobj2.Sym{}
+ osym.ReadWithoutName(r.Reader, r.SymOff(i))
+ st := sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
+ if st != sym.STEXT {
+ continue
+ }
+ dupok := osym.Dupok()
+ if r2, i2 := l.toLocal(gi); r2 != r || i2 != i {
+ // A dupok text symbol is resolved to another package.
+ // We still need to record its presence in the current
+ // package, as the trampoline pass expects packages
+ // are laid out in dependency order.
+ lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
+ continue // symbol in different object
+ }
+ if dupok {
+ lib.DupTextSyms2 = append(lib.DupTextSyms2, sym.LoaderSym(gi))
+ }
+
+ lib.Textp2 = append(lib.Textp2, sym.LoaderSym(gi))
+ }
+ }
+
+ // Now redo the assignment of text symbols to libs/units.
+ for _, doInternal := range [2]bool{true, false} {
+ for idx, lib := range libs {
+ if intlibs[idx] != doInternal {
+ continue
+ }
+ libtextp2 := []sym.LoaderSym{}
+ lists := [2][]sym.LoaderSym{lib.Textp2, lib.DupTextSyms2}
+ for _, list := range lists {
+ for _, s := range list {
+ sym := Sym(s)
+ if l.attrReachable.Has(sym) && !assignedToUnit.Has(sym) {
+ libtextp2 = append(libtextp2, s)
+ textp2 = append(textp2, sym)
+ unit := l.SymUnit(sym)
+ if unit != nil {
+ unit.Textp2 = append(unit.Textp2, s)
+ assignedToUnit.Set(sym)
+ }
+ }
+ }
+ }
+ lib.Textp2 = libtextp2
+ }
+ }
+
+ return textp2
+}
+
// For debugging.
func (l *Loader) Dump() {
fmt.Println("objs")
@@ -1328,18 +2716,24 @@
fmt.Println(obj.i, obj.r.unit.Lib)
}
}
+ fmt.Println("extStart:", l.extStart)
+ fmt.Println("Nsyms:", len(l.objSyms))
fmt.Println("syms")
- for i, s := range l.Syms {
- if i == 0 {
- continue
+ for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
+ pi := interface{}("")
+ if l.IsExternal(i) {
+ pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
+ }
+ var s *sym.Symbol
+ if int(i) < len(l.Syms) {
+ s = l.Syms[i]
}
if s != nil {
- fmt.Println(i, s, s.Type)
+ fmt.Println(i, s, s.Type, pi)
} else {
- fmt.Println(i, l.SymName(Sym(i)), "<not loaded>")
+ fmt.Println(i, l.SymName(i), "<not loaded>", pi)
}
}
- fmt.Println("overwrite:", l.overwrite)
fmt.Println("symsByName")
for name, i := range l.symsByName[0] {
fmt.Println(i, name, 0)
@@ -1347,4 +2741,9 @@
for name, i := range l.symsByName[1] {
fmt.Println(i, name, 1)
}
+ fmt.Println("payloads:")
+ for i := range l.payloads {
+ pp := l.payloads[i]
+ fmt.Println(i, pp.name, pp.ver, pp.kind)
+ }
}
diff --git a/src/cmd/link/internal/loader/loader_test.go b/src/cmd/link/internal/loader/loader_test.go
new file mode 100644
index 0000000..0503f66
--- /dev/null
+++ b/src/cmd/link/internal/loader/loader_test.go
@@ -0,0 +1,441 @@
+// 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 loader
+
+import (
+ "bytes"
+ "cmd/internal/objabi"
+ "cmd/internal/sys"
+ "cmd/link/internal/sym"
+ "fmt"
+ "testing"
+)
+
+// dummyAddSym adds the named symbol to the loader as if it had been
+// read from a Go object file. Note that it allocates a global
+// index without creating an associated object reader, so one can't
+// do anything interesting with this symbol (such as look at its
+// data or relocations).
+func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
+ idx := len(ldr.objSyms)
+ s, ok := ldr.AddSym(name, 0, or, idx, nonPkgDef, false, sym.SRODATA)
+ if !ok {
+ t.Errorf("AddrSym failed for '" + name + "'")
+ }
+ return s
+}
+
+func TestAddMaterializedSymbol(t *testing.T) {
+ edummy := func(s *sym.Symbol, str string, off int) {}
+ ldr := NewLoader(0, edummy)
+ dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
+ or := &dummyOreader
+
+ // Create some syms from a dummy object file symbol to get things going.
+ ts1 := addDummyObjSym(t, ldr, or, "type.uint8")
+ ts2 := addDummyObjSym(t, ldr, or, "mumble")
+ ts3 := addDummyObjSym(t, ldr, or, "type.string")
+
+ // Create some external symbols.
+ es1 := ldr.AddExtSym("extnew1", 0)
+ if es1 == 0 {
+ t.Fatalf("AddExtSym failed for extnew1")
+ }
+ es1x := ldr.AddExtSym("extnew1", 0)
+ if es1x != es1 {
+ t.Fatalf("AddExtSym lookup: expected %d got %d for second lookup", es1, es1x)
+ }
+ es2 := ldr.AddExtSym("go.info.type.uint8", 0)
+ if es2 == 0 {
+ t.Fatalf("AddExtSym failed for go.info.type.uint8")
+ }
+ // Create a nameless symbol
+ es3 := ldr.CreateExtSym("")
+ if es3 == 0 {
+ t.Fatalf("CreateExtSym failed for nameless sym")
+ }
+
+ // Grab symbol builder pointers
+ sb1 := ldr.MakeSymbolUpdater(es1)
+ sb2 := ldr.MakeSymbolUpdater(es2)
+ sb3 := ldr.MakeSymbolUpdater(es3)
+
+ // Suppose we create some more symbols, which triggers a grow.
+ // Make sure the symbol builder's payload pointer is valid,
+ // even across a grow.
+ ldr.growSyms(9999)
+
+ // Check get/set symbol type
+ es3typ := sb3.Type()
+ if es3typ != sym.Sxxx {
+ t.Errorf("SymType(es3): expected %v, got %v", sym.Sxxx, es3typ)
+ }
+ sb3.SetType(sym.SRODATA)
+ es3typ = sb3.Type()
+ if es3typ != sym.SRODATA {
+ t.Errorf("SymType(es3): expected %v, got %v", sym.SRODATA, es3typ)
+ }
+ es3typ = ldr.SymType(es3)
+ if es3typ != sym.SRODATA {
+ t.Errorf("SymType(es3): expected %v, got %v", sym.SRODATA, es3typ)
+ }
+
+ // New symbols should not initially be reachable.
+ if ldr.AttrReachable(es1) || ldr.AttrReachable(es2) || ldr.AttrReachable(es3) {
+ t.Errorf("newly materialized symbols should not be reachable")
+ }
+
+ // ... however it should be possible to set/unset their reachability.
+ ldr.SetAttrReachable(es3, true)
+ if !ldr.AttrReachable(es3) {
+ t.Errorf("expected reachable symbol after update")
+ }
+ ldr.SetAttrReachable(es3, false)
+ if ldr.AttrReachable(es3) {
+ t.Errorf("expected unreachable symbol after update")
+ }
+
+ // Test expansion of attr bitmaps
+ for idx := 0; idx < 36; idx++ {
+ es := ldr.AddExtSym(fmt.Sprintf("zext%d", idx), 0)
+ if ldr.AttrOnList(es) {
+ t.Errorf("expected OnList after creation")
+ }
+ ldr.SetAttrOnList(es, true)
+ if !ldr.AttrOnList(es) {
+ t.Errorf("expected !OnList after update")
+ }
+ if ldr.AttrDuplicateOK(es) {
+ t.Errorf("expected DupOK after creation")
+ }
+ ldr.SetAttrDuplicateOK(es, true)
+ if !ldr.AttrDuplicateOK(es) {
+ t.Errorf("expected !DupOK after update")
+ }
+ }
+
+ sb1 = ldr.MakeSymbolUpdater(es1)
+ sb2 = ldr.MakeSymbolUpdater(es2)
+
+ // Get/set a few other attributes
+ if ldr.AttrVisibilityHidden(es3) {
+ t.Errorf("expected initially not hidden")
+ }
+ ldr.SetAttrVisibilityHidden(es3, true)
+ if !ldr.AttrVisibilityHidden(es3) {
+ t.Errorf("expected hidden after update")
+ }
+
+ // Test get/set symbol value.
+ toTest := []Sym{ts2, es3}
+ for i, s := range toTest {
+ if v := ldr.SymValue(s); v != 0 {
+ t.Errorf("ldr.Value(%d): expected 0 got %d\n", s, v)
+ }
+ nv := int64(i + 101)
+ ldr.SetSymValue(s, nv)
+ if v := ldr.SymValue(s); v != nv {
+ t.Errorf("ldr.SetValue(%d,%d): expected %d got %d\n", s, nv, nv, v)
+ }
+ }
+
+ // Check/set alignment
+ es3al := ldr.SymAlign(es3)
+ if es3al != 0 {
+ t.Errorf("SymAlign(es3): expected 0, got %d", es3al)
+ }
+ ldr.SetSymAlign(es3, 128)
+ es3al = ldr.SymAlign(es3)
+ if es3al != 128 {
+ t.Errorf("SymAlign(es3): expected 128, got %d", es3al)
+ }
+
+ // Add some relocations to the new symbols.
+ r1 := Reloc{0, 1, objabi.R_ADDR, 0, ts1}
+ r2 := Reloc{3, 8, objabi.R_CALL, 0, ts2}
+ r3 := Reloc{7, 1, objabi.R_USETYPE, 0, ts3}
+ sb1.AddReloc(r1)
+ sb1.AddReloc(r2)
+ sb2.AddReloc(r3)
+
+ // Add some data to the symbols.
+ d1 := []byte{1, 2, 3}
+ d2 := []byte{4, 5, 6, 7}
+ sb1.AddBytes(d1)
+ sb2.AddBytes(d2)
+
+ // Now invoke the usual loader interfaces to make sure
+ // we're getting the right things back for these symbols.
+ // First relocations...
+ expRel := [][]Reloc{[]Reloc{r1, r2}, []Reloc{r3}}
+ for k, sb := range []*SymbolBuilder{sb1, sb2} {
+ rsl := sb.Relocs()
+ exp := expRel[k]
+ if !sameRelocSlice(rsl, exp) {
+ t.Errorf("expected relocs %v, got %v", exp, rsl)
+ }
+ relocs := ldr.Relocs(sb.Sym())
+ r0 := relocs.At(0)
+ if r0 != exp[0] {
+ t.Errorf("expected reloc %v, got %v", exp[0], r0)
+ }
+ }
+
+ // ... then data.
+ dat := sb2.Data()
+ if bytes.Compare(dat, d2) != 0 {
+ t.Errorf("expected es2 data %v, got %v", d2, dat)
+ }
+
+ // Nameless symbol should still be nameless.
+ es3name := ldr.RawSymName(es3)
+ if "" != es3name {
+ t.Errorf("expected es3 name of '', got '%s'", es3name)
+ }
+
+ // Read value of materialized symbol.
+ es1val := sb1.Value()
+ if 0 != es1val {
+ t.Errorf("expected es1 value of 0, got %v", es1val)
+ }
+
+ // Test other misc methods
+ irm := ldr.IsReflectMethod(es1)
+ if 0 != es1val {
+ t.Errorf("expected IsReflectMethod(es1) value of 0, got %v", irm)
+ }
+
+ // Writing data to a materialized symbol should mark it reachable.
+ if !sb1.Reachable() || !sb2.Reachable() {
+ t.Fatalf("written-to materialized symbols should be reachable")
+ }
+}
+
+func sameRelocSlice(s1 []Reloc, s2 []Reloc) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i := 0; i < len(s1); i++ {
+ if s1[i] != s2[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type addFunc func(l *Loader, s Sym, s2 Sym) Sym
+
+func TestAddDataMethods(t *testing.T) {
+ edummy := func(s *sym.Symbol, str string, off int) {}
+ ldr := NewLoader(0, edummy)
+ dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
+ or := &dummyOreader
+
+ // Populate loader with some symbols.
+ addDummyObjSym(t, ldr, or, "type.uint8")
+ ldr.AddExtSym("hello", 0)
+
+ arch := sys.ArchAMD64
+ var testpoints = []struct {
+ which string
+ addDataFunc addFunc
+ expData []byte
+ expKind sym.SymKind
+ expRel []Reloc
+ }{
+ {
+ which: "AddUint8",
+ addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
+ sb := l.MakeSymbolUpdater(s)
+ sb.AddUint8('a')
+ return s
+ },
+ expData: []byte{'a'},
+ expKind: sym.SDATA,
+ },
+ {
+ which: "AddUintXX",
+ addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
+ sb := l.MakeSymbolUpdater(s)
+ sb.AddUintXX(arch, 25185, 2)
+ return s
+ },
+ expData: []byte{'a', 'b'},
+ expKind: sym.SDATA,
+ },
+ {
+ which: "SetUint8",
+ addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
+ sb := l.MakeSymbolUpdater(s)
+ sb.AddUint8('a')
+ sb.AddUint8('b')
+ sb.SetUint8(arch, 1, 'c')
+ return s
+ },
+ expData: []byte{'a', 'c'},
+ expKind: sym.SDATA,
+ },
+ {
+ which: "AddString",
+ addDataFunc: func(l *Loader, s Sym, _ Sym) Sym {
+ sb := l.MakeSymbolUpdater(s)
+ sb.Addstring("hello")
+ return s
+ },
+ expData: []byte{'h', 'e', 'l', 'l', 'o', 0},
+ expKind: sym.SNOPTRDATA,
+ },
+ {
+ which: "AddAddrPlus",
+ addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
+ sb := l.MakeSymbolUpdater(s)
+ sb.AddAddrPlus(arch, s2, 3)
+ return s
+ },
+ expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
+ expKind: sym.SDATA,
+ expRel: []Reloc{Reloc{Type: objabi.R_ADDR, Size: 8, Add: 3, Sym: 6}},
+ },
+ {
+ which: "AddAddrPlus4",
+ addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
+ sb := l.MakeSymbolUpdater(s)
+ sb.AddAddrPlus4(arch, s2, 3)
+ return s
+ },
+ expData: []byte{0, 0, 0, 0},
+ expKind: sym.SDATA,
+ expRel: []Reloc{Reloc{Type: objabi.R_ADDR, Size: 4, Add: 3, Sym: 7}},
+ },
+ {
+ which: "AddCURelativeAddrPlus",
+ addDataFunc: func(l *Loader, s Sym, s2 Sym) Sym {
+ sb := l.MakeSymbolUpdater(s)
+ sb.AddCURelativeAddrPlus(arch, s2, 7)
+ return s
+ },
+ expData: []byte{0, 0, 0, 0, 0, 0, 0, 0},
+ expKind: sym.SDATA,
+ expRel: []Reloc{Reloc{Type: objabi.R_ADDRCUOFF, Size: 8, Add: 7, Sym: 8}},
+ },
+ }
+
+ var pmi Sym
+ for k, tp := range testpoints {
+ name := fmt.Sprintf("new%d", k+1)
+ mi := ldr.AddExtSym(name, 0)
+ if mi == 0 {
+ t.Fatalf("AddExtSym failed for '" + name + "'")
+ }
+ mi = tp.addDataFunc(ldr, mi, pmi)
+ if ldr.SymType(mi) != tp.expKind {
+ t.Errorf("testing Loader.%s: expected kind %s got %s",
+ tp.which, tp.expKind, ldr.SymType(mi))
+ }
+ if bytes.Compare(ldr.Data(mi), tp.expData) != 0 {
+ t.Errorf("testing Loader.%s: expected data %v got %v",
+ tp.which, tp.expData, ldr.Data(mi))
+ }
+ if !ldr.AttrReachable(mi) {
+ t.Fatalf("testing Loader.%s: sym updated should be reachable", tp.which)
+ }
+ relocs := ldr.Relocs(mi)
+ rsl := relocs.ReadAll(nil)
+ if !sameRelocSlice(rsl, tp.expRel) {
+ t.Fatalf("testing Loader.%s: got relocslice %+v wanted %+v",
+ tp.which, rsl, tp.expRel)
+ }
+ pmi = mi
+ }
+}
+
+func TestOuterSub(t *testing.T) {
+ edummy := func(s *sym.Symbol, str string, off int) {}
+ ldr := NewLoader(0, edummy)
+ dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
+ or := &dummyOreader
+
+ // Populate loader with some symbols.
+ addDummyObjSym(t, ldr, or, "type.uint8")
+ es1 := ldr.AddExtSym("outer", 0)
+ es2 := ldr.AddExtSym("sub1", 0)
+ es3 := ldr.AddExtSym("sub2", 0)
+ es4 := ldr.AddExtSym("sub3", 0)
+ es5 := ldr.AddExtSym("sub4", 0)
+ es6 := ldr.AddExtSym("sub5", 0)
+
+ // Should not have an outer sym initially
+ if ldr.OuterSym(es1) != 0 {
+ t.Errorf("es1 outer sym set ")
+ }
+ if ldr.SubSym(es2) != 0 {
+ t.Errorf("es2 outer sym set ")
+ }
+
+ // Establish first outer/sub relationship
+ ldr.PrependSub(es1, es2)
+ if ldr.OuterSym(es1) != 0 {
+ t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
+ }
+ if ldr.OuterSym(es2) != es1 {
+ t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
+ }
+ if ldr.SubSym(es1) != es2 {
+ t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es2)
+ }
+ if ldr.SubSym(es2) != 0 {
+ t.Errorf("ldr.SubSym(es2) got %d wanted %d", ldr.SubSym(es2), 0)
+ }
+
+ // Establish second outer/sub relationship
+ ldr.PrependSub(es1, es3)
+ if ldr.OuterSym(es1) != 0 {
+ t.Errorf("ldr.OuterSym(es1) got %d wanted %d", ldr.OuterSym(es1), 0)
+ }
+ if ldr.OuterSym(es2) != es1 {
+ t.Errorf("ldr.OuterSym(es2) got %d wanted %d", ldr.OuterSym(es2), es1)
+ }
+ if ldr.OuterSym(es3) != es1 {
+ t.Errorf("ldr.OuterSym(es3) got %d wanted %d", ldr.OuterSym(es3), es1)
+ }
+ if ldr.SubSym(es1) != es3 {
+ t.Errorf("ldr.SubSym(es1) got %d wanted %d", ldr.SubSym(es1), es3)
+ }
+ if ldr.SubSym(es3) != es2 {
+ t.Errorf("ldr.SubSym(es3) got %d wanted %d", ldr.SubSym(es3), es2)
+ }
+
+ // Some more
+ ldr.PrependSub(es1, es4)
+ ldr.PrependSub(es1, es5)
+ ldr.PrependSub(es1, es6)
+
+ // Set values.
+ ldr.SetSymValue(es2, 7)
+ ldr.SetSymValue(es3, 1)
+ ldr.SetSymValue(es4, 13)
+ ldr.SetSymValue(es5, 101)
+ ldr.SetSymValue(es6, 3)
+
+ // Sort
+ news := ldr.SortSub(es1)
+ if news != es3 {
+ t.Errorf("ldr.SortSub leader got %d wanted %d", news, es3)
+ }
+ pv := int64(-1)
+ count := 0
+ for ss := ldr.SubSym(es1); ss != 0; ss = ldr.SubSym(ss) {
+ v := ldr.SymValue(ss)
+ if v <= pv {
+ t.Errorf("ldr.SortSub sortfail at %d: val %d >= prev val %d",
+ ss, v, pv)
+ }
+ pv = v
+ count++
+ }
+ if count != 5 {
+ t.Errorf("expected %d in sub list got %d", 5, count)
+ }
+}
diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go
new file mode 100644
index 0000000..aeaec8b
--- /dev/null
+++ b/src/cmd/link/internal/loader/symbolbuilder.go
@@ -0,0 +1,330 @@
+// 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 loader
+
+import (
+ "cmd/internal/objabi"
+ "cmd/internal/sys"
+ "cmd/link/internal/sym"
+ "fmt"
+)
+
+// SymbolBuilder is a helper designed to help with the construction
+// of new symbol contents.
+type SymbolBuilder struct {
+ *extSymPayload // points to payload being updated
+ symIdx Sym // index of symbol being updated/constructed
+ l *Loader // loader
+}
+
+// MakeSymbolBuilder creates a symbol builder for use in constructing
+// an entirely new symbol.
+func (l *Loader) MakeSymbolBuilder(name string) *SymbolBuilder {
+ // for now assume that any new sym is intended to be static
+ symIdx := l.CreateExtSym(name)
+ if l.Syms[symIdx] != nil {
+ panic("can't build if sym.Symbol already present")
+ }
+ sb := &SymbolBuilder{l: l, symIdx: symIdx}
+ sb.extSymPayload = l.getPayload(symIdx)
+ return sb
+}
+
+// MakeSymbolUpdater creates a symbol builder helper for an existing
+// symbol 'symIdx'. If 'symIdx' is not an external symbol, then create
+// a clone of it (copy name, properties, etc) fix things up so that
+// the lookup tables and caches point to the new version, not the old
+// version.
+func (l *Loader) MakeSymbolUpdater(symIdx Sym) *SymbolBuilder {
+ if symIdx == 0 {
+ panic("can't update the null symbol")
+ }
+ if !l.IsExternal(symIdx) {
+ // Create a clone with the same name/version/kind etc.
+ l.cloneToExternal(symIdx)
+ }
+ // Now that we're doing phase 2 DWARF generation using the loader
+ // but before the wavefront has reached dodata(), we can't have this
+ // assertion here. Commented out for now.
+ if false {
+ if l.Syms[symIdx] != nil {
+ panic(fmt.Sprintf("can't build if sym.Symbol %q already present", l.RawSymName(symIdx)))
+ }
+ }
+
+ // Construct updater and return.
+ sb := &SymbolBuilder{l: l, symIdx: symIdx}
+ sb.extSymPayload = l.getPayload(symIdx)
+ return sb
+}
+
+// CreateSymForUpdate creates a symbol with given name and version,
+// returns a CreateSymForUpdate for update. If the symbol already
+// exists, it will update in-place.
+func (l *Loader) CreateSymForUpdate(name string, version int) *SymbolBuilder {
+ return l.MakeSymbolUpdater(l.LookupOrCreateSym(name, version))
+}
+
+// Getters for properties of the symbol we're working on.
+
+func (sb *SymbolBuilder) Sym() Sym { return sb.symIdx }
+func (sb *SymbolBuilder) Name() string { return sb.name }
+func (sb *SymbolBuilder) Version() int { return sb.ver }
+func (sb *SymbolBuilder) Type() sym.SymKind { return sb.kind }
+func (sb *SymbolBuilder) Size() int64 { return sb.size }
+func (sb *SymbolBuilder) Data() []byte { return sb.data }
+func (sb *SymbolBuilder) Value() int64 { return sb.l.SymValue(sb.symIdx) }
+func (sb *SymbolBuilder) Align() int32 { return sb.l.SymAlign(sb.symIdx) }
+func (sb *SymbolBuilder) Localentry() uint8 { return sb.l.SymLocalentry(sb.symIdx) }
+func (sb *SymbolBuilder) OnList() bool { return sb.l.AttrOnList(sb.symIdx) }
+func (sb *SymbolBuilder) External() bool { return sb.l.AttrExternal(sb.symIdx) }
+func (sb *SymbolBuilder) Extname() string { return sb.l.SymExtname(sb.symIdx) }
+func (sb *SymbolBuilder) CgoExportDynamic() bool { return sb.l.AttrCgoExportDynamic(sb.symIdx) }
+func (sb *SymbolBuilder) Dynimplib() string { return sb.l.SymDynimplib(sb.symIdx) }
+func (sb *SymbolBuilder) Dynimpvers() string { return sb.l.SymDynimpvers(sb.symIdx) }
+func (sb *SymbolBuilder) SubSym() Sym { return sb.l.SubSym(sb.symIdx) }
+func (sb *SymbolBuilder) GoType() Sym { return sb.l.SymGoType(sb.symIdx) }
+
+// Setters for symbol properties.
+
+func (sb *SymbolBuilder) SetType(kind sym.SymKind) { sb.kind = kind }
+func (sb *SymbolBuilder) SetSize(size int64) { sb.size = size }
+func (sb *SymbolBuilder) SetData(data []byte) { sb.data = data }
+func (sb *SymbolBuilder) SetOnList(v bool) { sb.l.SetAttrOnList(sb.symIdx, v) }
+func (sb *SymbolBuilder) SetExternal(v bool) { sb.l.SetAttrExternal(sb.symIdx, v) }
+func (sb *SymbolBuilder) SetValue(v int64) { sb.l.SetSymValue(sb.symIdx, v) }
+func (sb *SymbolBuilder) SetAlign(align int32) { sb.l.SetSymAlign(sb.symIdx, align) }
+func (sb *SymbolBuilder) SetLocalentry(value uint8) { sb.l.SetSymLocalentry(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetExtname(value string) { sb.l.SetSymExtname(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetDynimplib(value string) { sb.l.SetSymDynimplib(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetDynimpvers(value string) { sb.l.SetSymDynimpvers(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetPlt(value int32) { sb.l.SetPlt(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetGot(value int32) { sb.l.SetGot(sb.symIdx, value) }
+func (sb *SymbolBuilder) SetSpecial(value bool) { sb.l.SetAttrSpecial(sb.symIdx, value) }
+
+func (sb *SymbolBuilder) SetNotInSymbolTable(value bool) {
+ sb.l.SetAttrNotInSymbolTable(sb.symIdx, value)
+}
+
+func (sb *SymbolBuilder) AddBytes(data []byte) {
+ sb.setReachable()
+ if sb.kind == 0 {
+ sb.kind = sym.SDATA
+ }
+ sb.data = append(sb.data, data...)
+ sb.size = int64(len(sb.data))
+}
+
+func (sb *SymbolBuilder) Relocs() []Reloc {
+ return sb.relocs
+}
+
+func (sb *SymbolBuilder) SetRelocs(rslice []Reloc) {
+ sb.relocs = rslice
+}
+
+func (sb *SymbolBuilder) WriteRelocs(rslice []Reloc) {
+ if len(sb.relocs) != len(rslice) {
+ panic("src/dest length mismatch")
+ }
+ copy(sb.relocs, rslice)
+}
+
+func (sb *SymbolBuilder) AddReloc(r Reloc) {
+ sb.relocs = append(sb.relocs, r)
+}
+
+func (sb *SymbolBuilder) Reachable() bool {
+ return sb.l.AttrReachable(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) SetReachable(v bool) {
+ sb.l.SetAttrReachable(sb.symIdx, v)
+}
+
+func (sb *SymbolBuilder) setReachable() {
+ sb.SetReachable(true)
+}
+
+func (sb *SymbolBuilder) ReadOnly() bool {
+ return sb.l.AttrReadOnly(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) SetReadOnly(v bool) {
+ sb.l.SetAttrReadOnly(sb.symIdx, v)
+}
+
+func (sb *SymbolBuilder) DuplicateOK() bool {
+ return sb.l.AttrDuplicateOK(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) SetDuplicateOK(v bool) {
+ sb.l.SetAttrDuplicateOK(sb.symIdx, v)
+}
+
+func (sb *SymbolBuilder) Outer() Sym {
+ return sb.l.OuterSym(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) Sub() Sym {
+ return sb.l.SubSym(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) SortSub() {
+ sb.l.SortSub(sb.symIdx)
+}
+
+func (sb *SymbolBuilder) PrependSub(sub Sym) {
+ sb.l.PrependSub(sb.symIdx, sub)
+}
+
+func (sb *SymbolBuilder) AddUint8(v uint8) int64 {
+ off := sb.size
+ if sb.kind == 0 {
+ sb.kind = sym.SDATA
+ }
+ sb.setReachable()
+ sb.size++
+ sb.data = append(sb.data, v)
+ return off
+}
+
+func (sb *SymbolBuilder) AddUintXX(arch *sys.Arch, v uint64, wid int) int64 {
+ off := sb.size
+ sb.setReachable()
+ sb.setUintXX(arch, off, v, int64(wid))
+ return off
+}
+
+func (sb *SymbolBuilder) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64 {
+ if sb.kind == 0 {
+ sb.kind = sym.SDATA
+ }
+ if sb.size < off+wid {
+ sb.size = off + wid
+ sb.Grow(sb.size)
+ }
+
+ switch wid {
+ case 1:
+ sb.data[off] = uint8(v)
+ case 2:
+ arch.ByteOrder.PutUint16(sb.data[off:], uint16(v))
+ case 4:
+ arch.ByteOrder.PutUint32(sb.data[off:], uint32(v))
+ case 8:
+ arch.ByteOrder.PutUint64(sb.data[off:], v)
+ }
+
+ return off + wid
+}
+
+func (sb *SymbolBuilder) AddUint16(arch *sys.Arch, v uint16) int64 {
+ return sb.AddUintXX(arch, uint64(v), 2)
+}
+
+func (sb *SymbolBuilder) AddUint32(arch *sys.Arch, v uint32) int64 {
+ return sb.AddUintXX(arch, uint64(v), 4)
+}
+
+func (sb *SymbolBuilder) AddUint64(arch *sys.Arch, v uint64) int64 {
+ return sb.AddUintXX(arch, v, 8)
+}
+
+func (sb *SymbolBuilder) AddUint(arch *sys.Arch, v uint64) int64 {
+ return sb.AddUintXX(arch, v, arch.PtrSize)
+}
+
+func (sb *SymbolBuilder) SetUint8(arch *sys.Arch, r int64, v uint8) int64 {
+ sb.setReachable()
+ return sb.setUintXX(arch, r, uint64(v), 1)
+}
+
+func (sb *SymbolBuilder) SetUint16(arch *sys.Arch, r int64, v uint16) int64 {
+ sb.setReachable()
+ return sb.setUintXX(arch, r, uint64(v), 2)
+}
+
+func (sb *SymbolBuilder) SetUint32(arch *sys.Arch, r int64, v uint32) int64 {
+ sb.setReachable()
+ return sb.setUintXX(arch, r, uint64(v), 4)
+}
+
+func (sb *SymbolBuilder) SetUint(arch *sys.Arch, r int64, v uint64) int64 {
+ sb.setReachable()
+ return sb.setUintXX(arch, r, v, int64(arch.PtrSize))
+}
+
+func (sb *SymbolBuilder) Addstring(str string) int64 {
+ sb.setReachable()
+ if sb.kind == 0 {
+ sb.kind = sym.SNOPTRDATA
+ }
+ r := sb.size
+ if sb.name == ".shstrtab" {
+ // FIXME: find a better mechanism for this
+ sb.l.elfsetstring(nil, str, int(r))
+ }
+ sb.data = append(sb.data, str...)
+ sb.data = append(sb.data, 0)
+ sb.size = int64(len(sb.data))
+ return r
+}
+
+func (sb *SymbolBuilder) addRel() *Reloc {
+ sb.relocs = append(sb.relocs, Reloc{})
+ return &sb.relocs[len(sb.relocs)-1]
+}
+
+func (sb *SymbolBuilder) addSymRef(tgt Sym, add int64, typ objabi.RelocType, rsize int) int64 {
+ if sb.kind == 0 {
+ sb.kind = sym.SDATA
+ }
+ i := sb.size
+
+ sb.size += int64(rsize)
+ sb.Grow(sb.size)
+
+ r := sb.addRel()
+ r.Sym = tgt
+ r.Off = int32(i)
+ r.Size = uint8(rsize)
+ r.Type = typ
+ r.Add = add
+
+ return i + int64(r.Size)
+}
+
+// Add a symbol reference (relocation) with given type, addend, and size
+// (the most generic form).
+func (sb *SymbolBuilder) AddSymRef(arch *sys.Arch, tgt Sym, add int64, typ objabi.RelocType, rsize int) int64 {
+ sb.setReachable()
+ return sb.addSymRef(tgt, add, typ, rsize)
+}
+
+func (sb *SymbolBuilder) AddAddrPlus(arch *sys.Arch, tgt Sym, add int64) int64 {
+ sb.setReachable()
+ return sb.addSymRef(tgt, add, objabi.R_ADDR, arch.PtrSize)
+}
+
+func (sb *SymbolBuilder) AddAddrPlus4(arch *sys.Arch, tgt Sym, add int64) int64 {
+ sb.setReachable()
+ return sb.addSymRef(tgt, add, objabi.R_ADDR, 4)
+}
+
+func (sb *SymbolBuilder) AddPCRelPlus(arch *sys.Arch, tgt Sym, add int64) int64 {
+ sb.setReachable()
+ return sb.addSymRef(tgt, add, objabi.R_PCREL, 4)
+}
+
+func (sb *SymbolBuilder) AddCURelativeAddrPlus(arch *sys.Arch, tgt Sym, add int64) int64 {
+ sb.setReachable()
+ return sb.addSymRef(tgt, add, objabi.R_ADDRCUOFF, arch.PtrSize)
+}
+
+func (sb *SymbolBuilder) AddSize(arch *sys.Arch, tgt Sym) int64 {
+ sb.setReachable()
+ return sb.addSymRef(tgt, 0, objabi.R_SIZE, arch.PtrSize)
+}
diff --git a/src/cmd/link/internal/loadmacho/ldmacho.go b/src/cmd/link/internal/loadmacho/ldmacho.go
index 85a1ebc..d1ff82f 100644
--- a/src/cmd/link/internal/loadmacho/ldmacho.go
+++ b/src/cmd/link/internal/loadmacho/ldmacho.go
@@ -14,7 +14,6 @@
"cmd/link/internal/sym"
"encoding/binary"
"fmt"
- "io"
"sort"
)
@@ -101,7 +100,7 @@
flags uint32
res1 uint32
res2 uint32
- sym *sym.Symbol
+ sym loader.Sym
rel []ldMachoRel
}
@@ -132,7 +131,7 @@
desc uint16
kind int8
value uint64
- sym *sym.Symbol
+ sym loader.Sym
}
type ldMachoDysymtab struct {
@@ -320,10 +319,9 @@
return 0
}
rel := make([]ldMachoRel, sect.nreloc)
- n := int(sect.nreloc * 8)
- buf := make([]byte, n)
m.f.MustSeek(m.base+int64(sect.reloff), 0)
- if _, err := io.ReadFull(m.f, buf); err != nil {
+ buf, _, err := m.f.Slice(uint64(sect.nreloc * 8))
+ if err != nil {
return -1
}
for i := uint32(0); i < sect.nreloc; i++ {
@@ -364,10 +362,9 @@
func macholoaddsym(m *ldMachoObj, d *ldMachoDysymtab) int {
n := int(d.nindirectsyms)
-
- p := make([]byte, n*4)
m.f.MustSeek(m.base+int64(d.indirectsymoff), 0)
- if _, err := io.ReadFull(m.f, p); err != nil {
+ p, _, err := m.f.Slice(uint64(n * 4))
+ if err != nil {
return -1
}
@@ -383,9 +380,9 @@
return 0
}
- strbuf := make([]byte, symtab.strsize)
m.f.MustSeek(m.base+int64(symtab.stroff), 0)
- if _, err := io.ReadFull(m.f, strbuf); err != nil {
+ strbuf, _, err := m.f.Slice(uint64(symtab.strsize))
+ if err != nil {
return -1
}
@@ -394,9 +391,9 @@
symsize = 16
}
n := int(symtab.nsym * uint32(symsize))
- symbuf := make([]byte, n)
m.f.MustSeek(m.base+int64(symtab.symoff), 0)
- if _, err := io.ReadFull(m.f, symbuf); err != nil {
+ symbuf, _, err := m.f.Slice(uint64(n))
+ if err != nil {
return -1
}
sym := make([]ldMachoSym, symtab.nsym)
@@ -424,28 +421,17 @@
return 0
}
-func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) ([]*sym.Symbol, error) {
- newSym := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version, syms)
- }
- return load(arch, syms.IncVersion(), newSym, f, pkg, length, pn)
-}
-
-func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
- return load(arch, syms.IncVersion(), syms.Lookup, f, pkg, length, pn)
-}
-
-// load the Mach-O file pn from f.
+// Load the Mach-O file pn from f.
// Symbols are written into syms, and a slice of the text symbols is returned.
-func load(arch *sys.Arch, localSymVersion int, lookup func(string, int) *sym.Symbol, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
- errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
+func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, err error) {
+ errorf := func(str string, args ...interface{}) ([]loader.Sym, error) {
return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...))
}
base := f.Offset()
- var hdr [7 * 4]uint8
- if _, err := io.ReadFull(f, hdr[:]); err != nil {
+ hdr, _, err := f.Slice(7 * 4)
+ if err != nil {
return errorf("reading hdr: %v", err)
}
@@ -499,8 +485,8 @@
}
m.cmd = make([]ldMachoCmd, ncmd)
- cmdp := make([]byte, cmdsz)
- if _, err := io.ReadFull(f, cmdp); err != nil {
+ cmdp, _, err := f.Slice(uint64(cmdsz))
+ if err != nil {
return errorf("reading cmds: %v", err)
}
@@ -559,8 +545,8 @@
}
f.MustSeek(m.base+int64(c.seg.fileoff), 0)
- dat := make([]byte, c.seg.filesz)
- if _, err := io.ReadFull(f, dat); err != nil {
+ dat, readOnly, err := f.Slice(uint64(c.seg.filesz))
+ if err != nil {
return errorf("cannot load object data: %v", err)
}
@@ -573,30 +559,32 @@
continue
}
name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
- s := lookup(name, localSymVersion)
- if s.Type != 0 {
+ s := l.LookupOrCreateSym(name, localSymVersion)
+ bld := l.MakeSymbolUpdater(s)
+ if bld.Type() != 0 {
return errorf("duplicate %s/%s", sect.segname, sect.name)
}
if sect.flags&0xff == 1 { // S_ZEROFILL
- s.P = make([]byte, sect.size)
+ bld.SetData(make([]byte, sect.size))
} else {
- s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
+ bld.SetReadOnly(readOnly)
+ bld.SetData(dat[sect.addr-c.seg.vmaddr:][:sect.size])
}
- s.Size = int64(len(s.P))
+ bld.SetSize(int64(len(bld.Data())))
if sect.segname == "__TEXT" {
if sect.name == "__text" {
- s.Type = sym.STEXT
+ bld.SetType(sym.STEXT)
} else {
- s.Type = sym.SRODATA
+ bld.SetType(sym.SRODATA)
}
} else {
if sect.name == "__bss" {
- s.Type = sym.SNOPTRBSS
- s.P = s.P[:0]
+ bld.SetType(sym.SNOPTRBSS)
+ bld.SetData(nil)
} else {
- s.Type = sym.SNOPTRDATA
+ bld.SetType(sym.SNOPTRDATA)
}
}
@@ -621,12 +609,12 @@
if machsym.type_&N_EXT == 0 {
v = localSymVersion
}
- s := lookup(name, v)
+ s := l.LookupOrCreateSym(name, v)
if machsym.type_&N_EXT == 0 {
- s.Attr |= sym.AttrDuplicateOK
+ l.SetAttrDuplicateOK(s, true)
}
if machsym.desc&(N_WEAK_REF|N_WEAK_DEF) != 0 {
- s.Attr |= sym.AttrDuplicateOK
+ l.SetAttrDuplicateOK(s, true)
}
machsym.sym = s
if machsym.sectnum == 0 { // undefined
@@ -637,35 +625,32 @@
}
sect := &c.seg.sect[machsym.sectnum-1]
+ bld := l.MakeSymbolUpdater(s)
outer := sect.sym
- if outer == nil {
+ if outer == 0 {
continue // ignore reference to invalid section
}
- if s.Outer != nil {
- if s.Attr.DuplicateOK() {
+ if osym := l.OuterSym(s); osym != 0 {
+ if l.AttrDuplicateOK(s) {
continue
}
- return errorf("duplicate symbol reference: %s in both %s and %s", s.Name, s.Outer.Name, sect.sym.Name)
+ return errorf("duplicate symbol reference: %s in both %s and %s", l.SymName(s), l.SymName(osym), l.SymName(sect.sym))
}
- s.Type = outer.Type
- s.Attr |= sym.AttrSubSymbol
- s.Sub = outer.Sub
- outer.Sub = s
- s.Outer = outer
- s.Value = int64(machsym.value - sect.addr)
- if !s.Attr.CgoExportDynamic() {
- s.SetDynimplib("") // satisfy dynimport
+ bld.SetType(l.SymType(outer))
+ l.PrependSub(outer, s)
+
+ bld.SetValue(int64(machsym.value - sect.addr))
+ if !l.AttrCgoExportDynamic(s) {
+ bld.SetDynimplib("") // satisfy dynimport
}
- if outer.Type == sym.STEXT {
- if s.Attr.External() && !s.Attr.DuplicateOK() {
+ if l.SymType(outer) == sym.STEXT {
+ if bld.External() && !bld.DuplicateOK() {
return errorf("%v: duplicate symbol definition", s)
}
- s.Attr |= sym.AttrExternal
+ bld.SetExternal(true)
}
-
- machsym.sym = s
}
// Sort outer lists by address, adding to textp.
@@ -673,33 +658,37 @@
for i := 0; uint32(i) < c.seg.nsect; i++ {
sect := &c.seg.sect[i]
s := sect.sym
- if s == nil {
+ if s == 0 {
continue
}
- if s.Sub != nil {
- s.Sub = sym.SortSub(s.Sub)
+ bld := l.MakeSymbolUpdater(s)
+ if bld.SubSym() != 0 {
+
+ bld.SortSub()
// assign sizes, now that we know symbols in sorted order.
- for s1 := s.Sub; s1 != nil; s1 = s1.Sub {
- if s1.Sub != nil {
- s1.Size = s1.Sub.Value - s1.Value
+ for s1 := bld.Sub(); s1 != 0; s1 = l.SubSym(s1) {
+ s1Bld := l.MakeSymbolUpdater(s1)
+ if sub := l.SubSym(s1); sub != 0 {
+ s1Bld.SetSize(l.SymValue(sub) - l.SymValue(s1))
} else {
- s1.Size = s.Value + s.Size - s1.Value
+ dlen := int64(len(l.Data(s)))
+ s1Bld.SetSize(l.SymValue(s) + dlen - l.SymValue(s1))
}
}
}
- if s.Type == sym.STEXT {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
+ if bld.Type() == sym.STEXT {
+ if bld.OnList() {
+ return errorf("symbol %s listed multiple times", bld.Name())
}
- s.Attr |= sym.AttrOnList
+ bld.SetOnList(true)
textp = append(textp, s)
- for s1 := s.Sub; s1 != nil; s1 = s1.Sub {
- if s1.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s1.Name)
+ for s1 := bld.Sub(); s1 != 0; s1 = l.SubSym(s1) {
+ if l.AttrOnList(s1) {
+ return errorf("symbol %s listed multiple times", l.RawSymName(s1))
}
- s1.Attr |= sym.AttrOnList
+ l.SetAttrOnList(s1, true)
textp = append(textp, s1)
}
}
@@ -709,14 +698,14 @@
for i := 0; uint32(i) < c.seg.nsect; i++ {
sect := &c.seg.sect[i]
s := sect.sym
- if s == nil {
+ if s == 0 {
continue
}
macholoadrel(m, sect)
if sect.rel == nil {
continue
}
- r := make([]sym.Reloc, sect.nreloc)
+ r := make([]loader.Reloc, sect.nreloc)
rpi := 0
Reloc:
for j := uint32(0); j < sect.nreloc; j++ {
@@ -741,7 +730,7 @@
return errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
}
- rp.Siz = rel.length
+ rp.Size = rel.length
rp.Off = int32(rel.addr)
// NOTE(rsc): I haven't worked out why (really when)
@@ -765,7 +754,7 @@
for k := 0; uint32(k) < c.seg.nsect; k++ {
ks := &c.seg.sect[k]
if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size {
- if ks.sym != nil {
+ if ks.sym != 0 {
rp.Sym = ks.sym
rp.Add += int64(uint64(rel.value) - ks.addr)
} else if ks.segname == "__IMPORT" && ks.name == "__pointers" {
@@ -805,11 +794,12 @@
return errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
}
- rp.Siz = rel.length
+ rp.Size = rel.length
rp.Type = objabi.MachoRelocOffset + (objabi.RelocType(rel.type_) << 1) + objabi.RelocType(rel.pcrel)
rp.Off = int32(rel.addr)
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
+ p := l.Data(s)
if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
// Calculate the addend as the offset into the section.
//
@@ -828,9 +818,9 @@
// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
secaddr := c.seg.sect[rel.symnum-1].addr
- rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
+ rp.Add = int64(uint64(int64(int32(e.Uint32(p[rp.Off:])))+int64(rp.Off)+4) - secaddr)
} else {
- rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
+ rp.Add = int64(int32(e.Uint32(p[rp.Off:])))
}
// An unsigned internal relocation has a value offset
@@ -844,7 +834,7 @@
// it *is* the PC being subtracted. Use that to make
// it match our version of PC-relative.
if rel.pcrel != 0 && arch.Family == sys.I386 {
- rp.Add += int64(rp.Off) + int64(rp.Siz)
+ rp.Add += int64(rp.Off) + int64(rp.Size)
}
if rel.extrn == 0 {
if rel.symnum < 1 || rel.symnum > c.seg.nsect {
@@ -852,7 +842,7 @@
}
rp.Sym = c.seg.sect[rel.symnum-1].sym
- if rp.Sym == nil {
+ if rp.Sym == 0 {
return errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
}
@@ -874,9 +864,9 @@
rpi++
}
- sort.Sort(sym.RelocByOff(r[:rpi]))
- s.R = r
- s.R = s.R[:rpi]
+ sort.Sort(loader.RelocByOff(r[:rpi]))
+ sb := l.MakeSymbolUpdater(sect.sym)
+ sb.SetRelocs(r[:rpi])
}
return textp, nil
diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go
index 8b6aac3..88819f3 100644
--- a/src/cmd/link/internal/loadpe/ldpe.go
+++ b/src/cmd/link/internal/loadpe/ldpe.go
@@ -145,22 +145,26 @@
return n, nil
}
-func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
- lookup := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version, syms)
+// makeUpdater creates a loader.SymbolBuilder if one hasn't been created previously.
+// We use this to lazily make SymbolBuilders as we don't always need a builder, and creating them for all symbols might be an error.
+func makeUpdater(l *loader.Loader, bld *loader.SymbolBuilder, s loader.Sym) *loader.SymbolBuilder {
+ if bld != nil {
+ return bld
}
- return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn)
+ bld = l.MakeSymbolUpdater(s)
+ return bld
}
-func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
- return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn)
-}
-
-// load loads the PE file pn from input.
+// Load loads the PE file pn from input.
// Symbols are written into syms, and a slice of the text symbols is returned.
// If an .rsrc section is found, its symbol is returned as rsrc.
-func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
- sectsyms := make(map[*pe.Section]*sym.Symbol)
+func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, rsrc loader.Sym, err error) {
+ lookup := func(name string, version int) (*loader.SymbolBuilder, loader.Sym) {
+ s := l.LookupOrCreateSym(name, version)
+ sb := l.MakeSymbolUpdater(s)
+ return sb, s
+ }
+ sectsyms := make(map[*pe.Section]loader.Sym)
sectdata := make(map[*pe.Section][]byte)
// Some input files are archives containing multiple of
@@ -172,7 +176,7 @@
// TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
f, err := pe.NewFile(sr)
if err != nil {
- return nil, nil, err
+ return nil, 0, err
}
defer f.Close()
@@ -191,34 +195,34 @@
}
name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
- s := lookup(name, localSymVersion)
+ bld, s := lookup(name, localSymVersion)
switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
- s.Type = sym.SRODATA
+ bld.SetType(sym.SRODATA)
case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
- s.Type = sym.SNOPTRBSS
+ bld.SetType(sym.SNOPTRBSS)
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
- s.Type = sym.SNOPTRDATA
+ bld.SetType(sym.SNOPTRDATA)
case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
- s.Type = sym.STEXT
+ bld.SetType(sym.STEXT)
default:
- return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
+ return nil, 0, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
}
- if s.Type != sym.SNOPTRBSS {
+ if bld.Type() != sym.SNOPTRBSS {
data, err := sect.Data()
if err != nil {
- return nil, nil, err
+ return nil, 0, err
}
sectdata[sect] = data
- s.P = data
+ bld.SetData(data)
}
- s.Size = int64(sect.Size)
+ bld.SetSize(int64(sect.Size))
sectsyms[sect] = s
if sect.Name == ".rsrc" {
rsrc = s
@@ -242,35 +246,35 @@
continue
}
- rs := make([]sym.Reloc, rsect.NumberOfRelocations)
+ rs := make([]loader.Reloc, rsect.NumberOfRelocations)
for j, r := range rsect.Relocs {
rp := &rs[j]
if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
- return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
+ return nil, 0, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
}
pesym := &f.COFFSymbols[r.SymbolTableIndex]
- gosym, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
+ _, gosym, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
if err != nil {
- return nil, nil, err
+ return nil, 0, err
}
- if gosym == nil {
+ if gosym == 0 {
name, err := pesym.FullName(f.StringTable)
if err != nil {
name = string(pesym.Name[:])
}
- return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
+ return nil, 0, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
}
rp.Sym = gosym
- rp.Siz = 4
+ rp.Size = 4
rp.Off = int32(r.VirtualAddress)
switch arch.Family {
default:
- return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
+ return nil, 0, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
case sys.I386, sys.AMD64:
switch r.Type {
default:
- return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
+ return nil, 0, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
@@ -286,7 +290,7 @@
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
- rp.Siz = 8
+ rp.Size = 8
rp.Type = objabi.R_ADDR
@@ -297,7 +301,7 @@
case sys.ARM:
switch r.Type {
default:
- return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
+ return nil, 0, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
case IMAGE_REL_ARM_SECREL:
rp.Type = objabi.R_PCREL
@@ -324,11 +328,10 @@
}
}
- sort.Sort(sym.RelocByOff(rs[:rsect.NumberOfRelocations]))
+ sort.Sort(loader.RelocByOff(rs[:rsect.NumberOfRelocations]))
- s := sectsyms[rsect]
- s.R = rs
- s.R = s.R[:rsect.NumberOfRelocations]
+ bld := l.MakeSymbolUpdater(sectsyms[rsect])
+ bld.SetRelocs(rs[:rsect.NumberOfRelocations])
}
// enter sub-symbols into symbol table.
@@ -339,7 +342,7 @@
name, err := pesym.FullName(f.StringTable)
if err != nil {
- return nil, nil, err
+ return nil, 0, err
}
if name == "" {
continue
@@ -361,54 +364,56 @@
}
}
- s, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
+ bld, s, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
if err != nil {
- return nil, nil, err
+ return nil, 0, err
}
if pesym.SectionNumber == 0 { // extern
- if s.Type == sym.SDYNIMPORT {
- s.SetPlt(-2) // flag for dynimport in PE object files.
+ if l.SymType(s) == sym.SDYNIMPORT {
+ bld = makeUpdater(l, bld, s)
+ bld.SetPlt(-2) // flag for dynimport in PE object files.
}
- if s.Type == sym.SXREF && pesym.Value > 0 { // global data
- s.Type = sym.SNOPTRDATA
- s.Size = int64(pesym.Value)
+ if l.SymType(s) == sym.SXREF && pesym.Value > 0 { // global data
+ bld = makeUpdater(l, bld, s)
+ bld.SetType(sym.SNOPTRDATA)
+ bld.SetSize(int64(pesym.Value))
}
continue
} else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
sect = f.Sections[pesym.SectionNumber-1]
if _, found := sectsyms[sect]; !found {
- return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
+ return nil, 0, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
}
} else {
- return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
+ return nil, 0, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
}
if sect == nil {
- return nil, rsrc, nil
+ return nil, 0, nil
}
- if s.Outer != nil {
- if s.Attr.DuplicateOK() {
+ if l.OuterSym(s) != 0 {
+ if l.AttrDuplicateOK(s) {
continue
}
- return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name)
+ outerName := l.SymName(l.OuterSym(s))
+ sectName := l.SymName(sectsyms[sect])
+ return nil, 0, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, l.SymName(s), outerName, sectName)
}
+ bld = makeUpdater(l, bld, s)
sectsym := sectsyms[sect]
- s.Sub = sectsym.Sub
- sectsym.Sub = s
- s.Type = sectsym.Type
- s.Attr |= sym.AttrSubSymbol
- s.Value = int64(pesym.Value)
- s.Size = 4
- s.Outer = sectsym
- if sectsym.Type == sym.STEXT {
- if s.Attr.External() && !s.Attr.DuplicateOK() {
- return nil, nil, fmt.Errorf("%s: duplicate symbol definition", s.Name)
+ bld.SetType(l.SymType(sectsym))
+ l.PrependSub(sectsym, s)
+ bld.SetValue(int64(pesym.Value))
+ bld.SetSize(4)
+ if l.SymType(sectsym) == sym.STEXT {
+ if bld.External() && !bld.DuplicateOK() {
+ return nil, 0, fmt.Errorf("%s: duplicate symbol definition", l.SymName(s))
}
- s.Attr |= sym.AttrExternal
+ bld.SetExternal(true)
}
}
@@ -416,23 +421,16 @@
// This keeps textp in increasing address order.
for _, sect := range f.Sections {
s := sectsyms[sect]
- if s == nil {
+ if s == 0 {
continue
}
- if s.Sub != nil {
- s.Sub = sym.SortSub(s.Sub)
- }
- if s.Type == sym.STEXT {
- if s.Attr.OnList() {
- return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- textp = append(textp, s)
- for s = s.Sub; s != nil; s = s.Sub {
- if s.Attr.OnList() {
- return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
+ l.SortSub(s)
+ if l.SymType(s) == sym.STEXT {
+ for ; s != 0; s = l.SubSym(s) {
+ if l.AttrOnList(s) {
+ return nil, 0, fmt.Errorf("symbol %s listed multiple times", l.SymName(s))
}
- s.Attr |= sym.AttrOnList
+ l.SetAttrOnList(s, true)
textp = append(textp, s)
}
}
@@ -445,14 +443,14 @@
return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
}
-func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
+func readpesym(l *loader.Loader, arch *sys.Arch, lookup func(string, int) loader.Sym, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]loader.Sym, localSymVersion int) (*loader.SymbolBuilder, loader.Sym, error) {
symname, err := pesym.FullName(f.StringTable)
if err != nil {
- return nil, err
+ return nil, 0, err
}
var name string
if issect(pesym) {
- name = sectsyms[f.Sections[pesym.SectionNumber-1]].Name
+ name = l.SymName(sectsyms[f.Sections[pesym.SectionNumber-1]])
} else {
name = symname
switch arch.Family {
@@ -483,10 +481,11 @@
name = name[:i]
}
- var s *sym.Symbol
+ var s loader.Sym
+ var bld *loader.SymbolBuilder
switch pesym.Type {
default:
- return nil, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
+ return nil, 0, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
switch pesym.StorageClass {
@@ -495,19 +494,22 @@
case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
s = lookup(name, localSymVersion)
- s.Attr |= sym.AttrDuplicateOK
+ bld = makeUpdater(l, bld, s)
+ bld.SetDuplicateOK(true)
default:
- return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
+ return nil, 0, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
}
}
- if s != nil && s.Type == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
- s.Type = sym.SXREF
+ if s != 0 && l.SymType(s) == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
+ bld = makeUpdater(l, bld, s)
+ bld.SetType(sym.SXREF)
}
if strings.HasPrefix(symname, "__imp_") {
- s.SetGot(-2) // flag for __imp_
+ bld = makeUpdater(l, bld, s)
+ bld.SetGot(-2) // flag for __imp_
}
- return s, nil
+ return bld, s, nil
}
diff --git a/src/cmd/link/internal/loadxcoff/ldxcoff.go b/src/cmd/link/internal/loadxcoff/ldxcoff.go
index 759b176..906e871 100644
--- a/src/cmd/link/internal/loadxcoff/ldxcoff.go
+++ b/src/cmd/link/internal/loadxcoff/ldxcoff.go
@@ -19,7 +19,7 @@
// ldSection is an XCOFF section with its symbols.
type ldSection struct {
xcoff.Section
- sym *sym.Symbol
+ sym loader.Sym
}
// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating xcoffBiobuf
@@ -39,23 +39,10 @@
return n, nil
}
-// Load loads xcoff files with the indexed object files.
-func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
- lookup := func(name string, version int) *sym.Symbol {
- return l.LookupOrCreate(name, version, syms)
- }
- return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn)
-}
-
-// LoadOld uses the old version of object loading.
-func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
- return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn)
-}
-
// loads the Xcoff file pn from f.
-// Symbols are written into syms, and a slice of the text symbols is returned.
-func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
- errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
+// Symbols are written into loader, and a slice of the text symbols is returned.
+func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, err error) {
+ errorf := func(str string, args ...interface{}) ([]loader.Sym, error) {
return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...))
}
@@ -75,34 +62,35 @@
lds := new(ldSection)
lds.Section = *sect
name := fmt.Sprintf("%s(%s)", pkg, lds.Name)
- s := lookup(name, localSymVersion)
+ symbol := l.LookupOrCreateSym(name, localSymVersion)
+ s := l.MakeSymbolUpdater(symbol)
switch lds.Type {
default:
return errorf("unrecognized section type 0x%x", lds.Type)
case xcoff.STYP_TEXT:
- s.Type = sym.STEXT
+ s.SetType(sym.STEXT)
case xcoff.STYP_DATA:
- s.Type = sym.SNOPTRDATA
+ s.SetType(sym.SNOPTRDATA)
case xcoff.STYP_BSS:
- s.Type = sym.SNOPTRBSS
+ s.SetType(sym.SNOPTRBSS)
}
- s.Size = int64(lds.Size)
- if s.Type != sym.SNOPTRBSS {
+ s.SetSize(int64(lds.Size))
+ if s.Type() != sym.SNOPTRBSS {
data, err := lds.Section.Data()
if err != nil {
return nil, err
}
- s.P = data
+ s.SetData(data)
}
- lds.sym = s
+ lds.sym = symbol
ldSections = append(ldSections, lds)
}
// sx = symbol from file
- // s = symbol for syms
+ // s = symbol for loader
for _, sx := range f.Symbols {
// get symbol type
stype, errmsg := getSymbolType(f, sx)
@@ -113,14 +101,14 @@
continue
}
- s := lookup(sx.Name, 0)
+ s := l.LookupOrCreateSym(sx.Name, 0)
// Text symbol
- if s.Type == sym.STEXT {
- if s.Attr.OnList() {
- return errorf("symbol %s listed multiple times", s.Name)
+ if l.SymType(s) == sym.STEXT {
+ if l.AttrOnList(s) {
+ return errorf("symbol %s listed multiple times", l.SymName(s))
}
- s.Attr |= sym.AttrOnList
+ l.SetAttrOnList(s, true)
textp = append(textp, s)
}
}
@@ -131,11 +119,11 @@
if sect.Type != xcoff.STYP_TEXT && sect.Type != xcoff.STYP_DATA {
continue
}
- rs := make([]sym.Reloc, sect.Nreloc)
+ rs := make([]loader.Reloc, sect.Nreloc)
for i, rx := range sect.Relocs {
r := &rs[i]
- r.Sym = lookup(rx.Symbol.Name, 0)
+ r.Sym = l.LookupOrCreateSym(rx.Symbol.Name, 0)
if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress {
return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress)
}
@@ -149,27 +137,26 @@
if rx.Length != 64 {
return errorf("section %s: relocation R_POS has length different from 64: %d", sect.Name, rx.Length)
}
- r.Siz = 8
+ r.Size = 8
r.Type = objabi.R_CONST
r.Add = int64(rx.Symbol.Value)
case xcoff.R_RBR:
- r.Siz = 4
+ r.Size = 4
r.Type = objabi.R_CALLPOWER
r.Add = 0 //
}
}
- s := sect.sym
- s.R = rs
- s.R = s.R[:sect.Nreloc]
+ bld := l.MakeSymbolUpdater(sect.sym)
+ bld.SetRelocs(rs[:sect.Nreloc])
}
return textp, nil
}
// Convert symbol xcoff type to sym.SymKind
-// Returns nil if this shouldn't be added into syms (like .file or .dw symbols )
+// Returns nil if this shouldn't be added into loader (like .file or .dw symbols )
func getSymbolType(f *xcoff.File, s *xcoff.Symbol) (stype sym.SymKind, err string) {
// .file symbol
if s.SectionNumber == -2 {
diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go
index 16c94c1..c2cabc8 100644
--- a/src/cmd/link/internal/mips/asm.go
+++ b/src/cmd/link/internal/mips/asm.go
@@ -34,6 +34,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"fmt"
@@ -44,7 +45,7 @@
return
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
log.Fatalf("adddynrel not implemented")
return false
}
@@ -74,7 +75,7 @@
return true
}
-func elfsetupplt(ctxt *ld.Link) {
+func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
return
}
@@ -96,8 +97,8 @@
}
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
switch r.Type {
default:
return val, false
@@ -116,12 +117,12 @@
ld.Errorf(s, "missing section for %s", rs.Name)
}
r.Xsym = rs
- return applyrel(ctxt.Arch, r, s, val, r.Xadd), true
+ return applyrel(target.Arch, r, s, val, r.Xadd), true
case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS:
r.Done = false
r.Xsym = r.Sym
r.Xadd = r.Add
- return applyrel(ctxt.Arch, r, s, val, r.Add), true
+ return applyrel(target.Arch, r, s, val, r.Add), true
}
}
@@ -129,10 +130,10 @@
case objabi.R_CONST:
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU:
t := ld.Symaddr(r.Sym) + r.Add
- return applyrel(ctxt.Arch, r, s, val, t), true
+ return applyrel(target.Arch, r, s, val, t), true
case objabi.R_CALLMIPS, objabi.R_JMPMIPS:
t := ld.Symaddr(r.Sym) + r.Add
@@ -145,20 +146,20 @@
ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
}
- return applyrel(ctxt.Arch, r, s, val, t), true
+ return applyrel(target.Arch, r, s, val, t), true
case objabi.R_ADDRMIPSTLS:
// thread pointer is at 0x7000 offset from the start of TLS data area
t := ld.Symaddr(r.Sym) + r.Add - 0x7000
if t < -32768 || t >= 32678 {
ld.Errorf(s, "TLS offset out of range %d", t)
}
- return applyrel(ctxt.Arch, r, s, val, t), true
+ return applyrel(target.Arch, r, s, val, t), true
}
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
return -1
}
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index 5c6fef9..a6abec1 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -34,6 +34,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"fmt"
@@ -42,7 +43,7 @@
func gentext(ctxt *ld.Link) {}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
log.Fatalf("adddynrel not implemented")
return false
}
@@ -91,7 +92,7 @@
return true
}
-func elfsetupplt(ctxt *ld.Link) {
+func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
return
}
@@ -99,8 +100,8 @@
return false
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
switch r.Type {
default:
return val, false
@@ -136,11 +137,11 @@
case objabi.R_CONST:
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
case objabi.R_ADDRMIPS,
objabi.R_ADDRMIPSU:
t := ld.Symaddr(r.Sym) + r.Add
- o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:])
+ o1 := target.Arch.ByteOrder.Uint32(s.P[r.Off:])
if r.Type == objabi.R_ADDRMIPS {
return int64(o1&0xffff0000 | uint32(t)&0xffff), true
}
@@ -151,20 +152,20 @@
if t < -32768 || t >= 32678 {
ld.Errorf(s, "TLS offset out of range %d", t)
}
- o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:])
+ o1 := target.Arch.ByteOrder.Uint32(s.P[r.Off:])
return int64(o1&0xffff0000 | uint32(t)&0xffff), true
case objabi.R_CALLMIPS,
objabi.R_JMPMIPS:
// Low 26 bits = (S + A) >> 2
t := ld.Symaddr(r.Sym) + r.Add
- o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:])
+ o1 := target.Arch.ByteOrder.Uint32(s.P[r.Off:])
return int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000), true
}
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
return -1
}
diff --git a/src/cmd/link/internal/objfile/objfile.go b/src/cmd/link/internal/objfile/objfile.go
deleted file mode 100644
index a15d3c3..0000000
--- a/src/cmd/link/internal/objfile/objfile.go
+++ /dev/null
@@ -1,659 +0,0 @@
-// Copyright 2013 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 reads Go object files for the Go linker, cmd/link.
-//
-// This package is similar to cmd/internal/objfile which also reads
-// Go object files.
-package objfile
-
-import (
- "bufio"
- "bytes"
- "cmd/internal/bio"
- "cmd/internal/dwarf"
- "cmd/internal/obj"
- "cmd/internal/objabi"
- "cmd/internal/sys"
- "cmd/link/internal/sym"
- "fmt"
- "io"
- "log"
- "os"
- "strconv"
- "strings"
- "unsafe"
-)
-
-const (
- startmagic = "\x00go114ld"
- endmagic = "\xffgo114ld"
-)
-
-var emptyPkg = []byte(`"".`)
-
-// objReader reads Go object files.
-type objReader struct {
- rd *bio.Reader
- arch *sys.Arch
- syms *sym.Symbols
- lib *sym.Library
- unit *sym.CompilationUnit
- pn string
- dupSym *sym.Symbol
- localSymVersion int
- flags int
- strictDupMsgs int
- dataSize int
-
- // rdBuf is used by readString and readSymName as scratch for reading strings.
- rdBuf []byte
-
- // List of symbol references for the file being read.
- refs []*sym.Symbol
- data []byte
- reloc []sym.Reloc
- pcdata []sym.Pcdata
- funcdata []*sym.Symbol
- funcdataoff []int64
- file []*sym.Symbol
- pkgpref string // objabi.PathToPrefix(r.lib.Pkg) + "."
-
- roObject []byte // from read-only mmap of object file (may be nil)
- roOffset int64 // offset into readonly object data examined so far
-
- dataReadOnly bool // whether data is backed by read-only memory
-}
-
-// Flags to enable optional behavior during object loading/reading.
-
-const (
- NoFlag int = iota
-
- // Sanity-check duplicate symbol contents, issuing warning
- // when duplicates have different lengths or contents.
- StrictDupsWarnFlag
-
- // Similar to StrictDupsWarnFlag, but issue fatal error.
- StrictDupsErrFlag
-)
-
-// Load loads an object file f into library lib.
-// The symbols loaded are added to syms.
-func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) int {
- start := f.Offset()
- roObject := f.SliceRO(uint64(length))
- if roObject != nil {
- f.MustSeek(int64(-length), os.SEEK_CUR)
- }
- r := &objReader{
- rd: f,
- lib: lib,
- unit: unit,
- arch: arch,
- syms: syms,
- pn: pn,
- dupSym: &sym.Symbol{Name: ".dup"},
- localSymVersion: syms.IncVersion(),
- flags: flags,
- roObject: roObject,
- pkgpref: objabi.PathToPrefix(lib.Pkg) + ".",
- }
- r.loadObjFile()
- if roObject != nil {
- if r.roOffset != length {
- log.Fatalf("%s: unexpected end at %d, want %d", pn, r.roOffset, start+length)
- }
- r.rd.MustSeek(int64(length), os.SEEK_CUR)
- } else if f.Offset() != start+length {
- log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
- }
- return r.strictDupMsgs
-}
-
-func (r *objReader) loadObjFile() {
- // Magic header
- var buf [8]uint8
- r.readFull(buf[:])
- if string(buf[:]) != startmagic {
- log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
- }
-
- // Version
- c, err := r.readByte()
- if err != nil || c != 1 {
- log.Fatalf("%s: invalid file version number %d", r.pn, c)
- }
-
- // Autolib
- for {
- lib := r.readString()
- if lib == "" {
- break
- }
- r.lib.ImportStrings = append(r.lib.ImportStrings, lib)
- }
-
- // DWARF strings
- count := r.readInt()
- r.unit.DWARFFileTable = make([]string, count)
- for i := 0; i < count; i++ {
- // TODO: This should probably be a call to mkROString.
- r.unit.DWARFFileTable[i] = r.readString()
- }
-
- // Symbol references
- r.refs = []*sym.Symbol{nil} // zeroth ref is nil
- for {
- c, err := r.peek(1)
- if err != nil {
- log.Fatalf("%s: peeking: %v", r.pn, err)
- }
- if c[0] == 0xff {
- r.readByte()
- break
- }
- r.readRef()
- }
-
- // Lengths
- r.readSlices()
-
- // Data section
- err = r.readDataSection()
- if err != nil {
- log.Fatalf("%s: error reading %s", r.pn, err)
- }
-
- // Defined symbols
- for {
- c, err := r.peek(1)
- if err != nil {
- log.Fatalf("%s: peeking: %v", r.pn, err)
- }
- if c[0] == 0xff {
- break
- }
- r.readSym()
- }
-
- // Magic footer
- buf = [8]uint8{}
- r.readFull(buf[:])
- if string(buf[:]) != endmagic {
- log.Fatalf("%s: invalid file end", r.pn)
- }
-}
-
-func (r *objReader) readSlices() {
- r.dataSize = r.readInt()
- n := r.readInt()
- r.reloc = make([]sym.Reloc, n)
- n = r.readInt()
- r.pcdata = make([]sym.Pcdata, n)
- _ = r.readInt() // TODO: remove on next object file rev (autom count)
- n = r.readInt()
- r.funcdata = make([]*sym.Symbol, n)
- r.funcdataoff = make([]int64, n)
- n = r.readInt()
- r.file = make([]*sym.Symbol, n)
-}
-
-func (r *objReader) readDataSection() (err error) {
- if r.roObject != nil {
- r.data, r.dataReadOnly, err =
- r.roObject[r.roOffset:r.roOffset+int64(r.dataSize)], true, nil
- r.roOffset += int64(r.dataSize)
- return
- }
- r.data, r.dataReadOnly, err = r.rd.Slice(uint64(r.dataSize))
- return
-}
-
-// Symbols are prefixed so their content doesn't get confused with the magic footer.
-const symPrefix = 0xfe
-
-func (r *objReader) readSym() {
- var c byte
- var err error
- if c, err = r.readByte(); c != symPrefix || err != nil {
- log.Fatalln("readSym out of sync")
- }
- if c, err = r.readByte(); err != nil {
- log.Fatalln("error reading input: ", err)
- }
- t := sym.AbiSymKindToSymKind[c]
- s := r.readSymIndex()
- flags := r.readInt()
- dupok := flags&1 != 0
- local := flags&2 != 0
- makeTypelink := flags&4 != 0
- size := r.readInt()
- typ := r.readSymIndex()
- data := r.readData()
- nreloc := r.readInt()
- isdup := false
-
- var dup *sym.Symbol
- if s.Type != 0 && s.Type != sym.SXREF {
- if (t == sym.SDATA || t == sym.SBSS || t == sym.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
- if s.Size < int64(size) {
- s.Size = int64(size)
- }
- if typ != nil && s.Gotype == nil {
- s.Gotype = typ
- }
- return
- }
-
- if (s.Type == sym.SDATA || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
- goto overwrite
- }
- if s.Type != sym.SBSS && s.Type != sym.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
- log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
- }
- if len(s.P) > 0 {
- dup = s
- s = r.dupSym
- isdup = true
- }
- }
-
-overwrite:
- s.File = r.pkgpref[:len(r.pkgpref)-1]
- s.Unit = r.unit
- if dupok {
- s.Attr |= sym.AttrDuplicateOK
- }
- if t == sym.SXREF {
- log.Fatalf("bad sxref")
- }
- if t == 0 {
- log.Fatalf("missing type for %s in %s", s.Name, r.pn)
- }
- if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
- t = s.Type
- }
- s.Type = t
- if s.Size < int64(size) {
- s.Size = int64(size)
- }
- s.Attr.Set(sym.AttrLocal, local)
- s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
- if typ != nil {
- s.Gotype = typ
- }
- if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
- dup.Gotype = typ
- }
- s.P = data
- s.Attr.Set(sym.AttrReadOnly, r.dataReadOnly)
- if nreloc > 0 {
- s.R = r.reloc[:nreloc:nreloc]
- if !isdup {
- r.reloc = r.reloc[nreloc:]
- }
-
- for i := 0; i < nreloc; i++ {
- s.R[i] = sym.Reloc{
- Off: r.readInt32(),
- Siz: r.readUint8(),
- Type: objabi.RelocType(r.readInt32()),
- Add: r.readInt64(),
- Sym: r.readSymIndex(),
- }
- }
- }
-
- if s.Type == sym.STEXT {
- s.FuncInfo = new(sym.FuncInfo)
- pc := s.FuncInfo
-
- pc.Args = r.readInt32()
- pc.Locals = r.readInt32()
- if r.readUint8() != 0 {
- s.Attr |= sym.AttrNoSplit
- }
- flags := r.readInt()
- if flags&(1<<2) != 0 {
- s.Attr |= sym.AttrReflectMethod
- }
- if flags&(1<<3) != 0 {
- s.Attr |= sym.AttrShared
- }
- if flags&(1<<4) != 0 {
- s.Attr |= sym.AttrTopFrame
- }
- n := r.readInt()
- if n != 0 {
- log.Fatalf("stale object file: autom count nonzero")
- }
-
- pc.Pcsp.P = r.readData()
- pc.Pcfile.P = r.readData()
- pc.Pcline.P = r.readData()
- pc.Pcinline.P = r.readData()
- n = r.readInt()
- pc.Pcdata = r.pcdata[:n:n]
- if !isdup {
- r.pcdata = r.pcdata[n:]
- }
- for i := 0; i < n; i++ {
- pc.Pcdata[i].P = r.readData()
- }
- n = r.readInt()
- pc.Funcdata = r.funcdata[:n:n]
- pc.Funcdataoff = r.funcdataoff[:n:n]
- if !isdup {
- r.funcdata = r.funcdata[n:]
- r.funcdataoff = r.funcdataoff[n:]
- }
- for i := 0; i < n; i++ {
- pc.Funcdata[i] = r.readSymIndex()
- }
- for i := 0; i < n; i++ {
- pc.Funcdataoff[i] = r.readInt64()
- }
- n = r.readInt()
- pc.File = r.file[:n:n]
- if !isdup {
- r.file = r.file[n:]
- }
- for i := 0; i < n; i++ {
- pc.File[i] = r.readSymIndex()
- }
- n = r.readInt()
- pc.InlTree = make([]sym.InlinedCall, n)
- for i := 0; i < n; i++ {
- pc.InlTree[i].Parent = r.readInt32()
- pc.InlTree[i].File = r.readSymIndex()
- pc.InlTree[i].Line = r.readInt32()
- pc.InlTree[i].Func = r.readSymIndex().Name
- pc.InlTree[i].ParentPC = r.readInt32()
- }
-
- if !dupok {
- if s.Attr.OnList() {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Attr |= sym.AttrOnList
- r.lib.Textp = append(r.lib.Textp, s)
- } else {
- // there may ba a dup in another package
- // put into a temp list and add to text later
- if !isdup {
- r.lib.DupTextSyms = append(r.lib.DupTextSyms, s)
- } else {
- r.lib.DupTextSyms = append(r.lib.DupTextSyms, dup)
- }
- }
- }
- if s.Type == sym.SDWARFINFO {
- r.patchDWARFName(s)
- }
-
- if isdup && r.flags&(StrictDupsWarnFlag|StrictDupsErrFlag) != 0 {
- // Compare the just-read symbol with the previously read
- // symbol of the same name, verifying that they have the same
- // payload. If not, issue a warning and possibly an error.
- if !bytes.Equal(s.P, dup.P) {
- reason := "same length but different contents"
- if len(s.P) != len(dup.P) {
- reason = fmt.Sprintf("new length %d != old length %d",
- len(data), len(dup.P))
- }
- fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason)
-
- // For the moment, whitelist DWARF subprogram DIEs for
- // auto-generated wrapper functions. What seems to happen
- // here is that we get different line numbers on formal
- // params; I am guessing that the pos is being inherited
- // from the spot where the wrapper is needed.
- whitelist := (strings.HasPrefix(dup.Name, "go.info.go.interface") ||
- strings.HasPrefix(dup.Name, "go.info.go.builtin") ||
- strings.HasPrefix(dup.Name, "go.isstmt.go.builtin") ||
- strings.HasPrefix(dup.Name, "go.debuglines"))
- if !whitelist {
- r.strictDupMsgs++
- }
- }
- }
-}
-
-func (r *objReader) patchDWARFName(s *sym.Symbol) {
- // 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.pkgpref)
- patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
-
- s.P = append(patched, s.P[e:]...)
- 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)
- }
- }
-}
-
-func (r *objReader) readFull(b []byte) {
- if r.roObject != nil {
- copy(b, r.roObject[r.roOffset:])
- r.roOffset += int64(len(b))
- return
- }
- _, err := io.ReadFull(r.rd, b)
- if err != nil {
- log.Fatalf("%s: error reading %s", r.pn, err)
- }
-}
-
-func (r *objReader) readByte() (byte, error) {
- if r.roObject != nil {
- b := r.roObject[r.roOffset]
- r.roOffset++
- return b, nil
- }
- return r.rd.ReadByte()
-}
-
-func (r *objReader) peek(n int) ([]byte, error) {
- if r.roObject != nil {
- return r.roObject[r.roOffset : r.roOffset+int64(n)], nil
- }
- return r.rd.Peek(n)
-}
-
-func (r *objReader) readRef() {
- if c, err := r.readByte(); c != symPrefix || err != nil {
- log.Fatalf("readSym out of sync")
- }
- name := r.readSymName()
- var v int
- if abi := r.readInt(); abi == -1 {
- // Static
- v = r.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 for %q: %d", name, abi)
- }
- s := r.syms.Lookup(name, v)
- r.refs = append(r.refs, s)
-
- if s == nil || v == r.localSymVersion {
- return
- }
- if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
- x, err := strconv.ParseUint(s.Name[5:], 16, 64)
- if err != nil {
- log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
- }
- s.Type = 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(r.arch, uint32(x))
- case "$f64.", "$i64.":
- s.AddUint64(r.arch, x)
- default:
- log.Panicf("unrecognized $-symbol: %s", s.Name)
- }
- s.Attr.Set(sym.AttrReachable, false)
- }
- if strings.HasPrefix(s.Name, "runtime.gcbits.") {
- s.Attr |= sym.AttrLocal
- }
-}
-
-func (r *objReader) readInt64() int64 {
- uv := uint64(0)
- for shift := uint(0); ; shift += 7 {
- if shift >= 64 {
- log.Fatalf("corrupt input")
- }
- c, err := r.readByte()
- if err != nil {
- log.Fatalln("error reading input: ", err)
- }
- uv |= uint64(c&0x7F) << shift
- if c&0x80 == 0 {
- break
- }
- }
-
- return int64(uv>>1) ^ (int64(uv<<63) >> 63)
-}
-
-func (r *objReader) readInt() int {
- n := r.readInt64()
- if int64(int(n)) != n {
- log.Panicf("%v out of range for int", n)
- }
- return int(n)
-}
-
-func (r *objReader) readInt32() int32 {
- n := r.readInt64()
- if int64(int32(n)) != n {
- log.Panicf("%v out of range for int32", n)
- }
- return int32(n)
-}
-
-func (r *objReader) readInt16() int16 {
- n := r.readInt64()
- if int64(int16(n)) != n {
- log.Panicf("%v out of range for int16", n)
- }
- return int16(n)
-}
-
-func (r *objReader) readUint8() uint8 {
- n := r.readInt64()
- if int64(uint8(n)) != n {
- log.Panicf("%v out of range for uint8", n)
- }
- return uint8(n)
-}
-
-func (r *objReader) readString() string {
- n := r.readInt()
- if cap(r.rdBuf) < n {
- r.rdBuf = make([]byte, 2*n)
- }
- r.readFull(r.rdBuf[:n])
- return string(r.rdBuf[:n])
-}
-
-func (r *objReader) readData() []byte {
- n := r.readInt()
- p := r.data[:n:n]
- r.data = r.data[n:]
- return p
-}
-
-type stringHeader struct {
- str unsafe.Pointer
- len int
-}
-
-func mkROString(rodata []byte) string {
- if len(rodata) == 0 {
- return ""
- }
- ss := stringHeader{str: unsafe.Pointer(&rodata[0]), len: len(rodata)}
- s := *(*string)(unsafe.Pointer(&ss))
- return s
-}
-
-// readSymName reads a symbol name, replacing all "". with pkg.
-func (r *objReader) readSymName() string {
- n := r.readInt()
- if n == 0 {
- r.readInt64()
- return ""
- }
- if cap(r.rdBuf) < n {
- r.rdBuf = make([]byte, 2*n)
- }
- sOffset := r.roOffset
- origName, err := r.peek(n)
- if err == bufio.ErrBufferFull {
- // Long symbol names are rare but exist. One source is type
- // symbols for types with long string forms. See #15104.
- origName = make([]byte, n)
- r.readFull(origName)
- } else if err != nil {
- log.Fatalf("%s: error reading symbol: %v", r.pn, err)
- }
- adjName := r.rdBuf[:0]
- nPkgRefs := 0
- for {
- i := bytes.Index(origName, emptyPkg)
- if i == -1 {
- var s string
- if r.roObject != nil && nPkgRefs == 0 {
- s = mkROString(r.roObject[sOffset : sOffset+int64(n)])
- } else {
- s = string(append(adjName, origName...))
- }
- // Read past the peeked origName, now that we're done with it,
- // using the rfBuf (also no longer used) as the scratch space.
- // TODO: use bufio.Reader.Discard if available instead?
- if err == nil {
- r.readFull(r.rdBuf[:n])
- }
- r.rdBuf = adjName[:0] // in case 2*n wasn't enough
- return s
- }
- nPkgRefs++
- adjName = append(adjName, origName[:i]...)
- adjName = append(adjName, r.pkgpref[:len(r.pkgpref)-1]...)
- adjName = append(adjName, '.')
- origName = origName[i+len(emptyPkg):]
- }
-}
-
-// Reads the index of a symbol reference and resolves it to a symbol
-func (r *objReader) readSymIndex() *sym.Symbol {
- i := r.readInt()
- return r.refs[i]
-}
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 9fbcff5..d0993e3 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -34,6 +34,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"encoding/binary"
@@ -262,11 +263,11 @@
stub.AddUint32(ctxt.Arch, 0x4e800420) // bctr
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
if ctxt.IsELF {
return addelfdynrel(ctxt, s, r)
} else if ctxt.HeadType == objabi.Haix {
- return ld.Xcoffadddynrel(ctxt, s, r)
+ return ld.Xcoffadddynrel(&ctxt.Target, s, r)
}
return false
}
@@ -313,7 +314,7 @@
r.Type = objabi.R_ADDR
if targ.Type == sym.SDYNIMPORT {
// These happen in .toc sections
- ld.Adddynsym(ctxt, targ)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, targ)
rela := ctxt.Syms.Lookup(".rela", 0)
rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
@@ -498,14 +499,13 @@
return true
}
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- if plt.Size == 0 {
+func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() == 0 {
// The dynamic linker stores the address of the
// dynamic resolver and the DSO identifier in the two
// doublewords at the beginning of the .plt section
// before the PLT array. Reserve space for these.
- plt.Size = 16
+ plt.SetSize(16)
}
}
@@ -513,31 +513,13 @@
return false
}
-// Return the value of .TOC. for symbol s
-func symtoc(ctxt *ld.Link, s *sym.Symbol) int64 {
- var toc *sym.Symbol
-
- if s.Outer != nil {
- toc = ctxt.Syms.ROLookup(".TOC.", int(s.Outer.Version))
- } else {
- toc = ctxt.Syms.ROLookup(".TOC.", int(s.Version))
- }
-
- if toc == nil {
- ld.Errorf(s, "TOC-relative relocation in object without .TOC.")
- return 0
- }
-
- return toc.Value
-}
-
// archreloctoc relocates a TOC relative symbol.
// If the symbol pointed by this TOC relative symbol is in .data or .bss, the
// default load instruction can be changed to an addi instruction and the
// symbol address can be used directly.
// This code is for AIX only.
-func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
- if ctxt.HeadType == objabi.Hlinux {
+func archreloctoc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
+ if target.IsLinux() {
ld.Errorf(s, "archrelocaddr called for %s relocation\n", r.Sym.Name)
}
var o1, o2 uint32
@@ -555,13 +537,13 @@
ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor")
}
- if ctxt.LinkMode == ld.LinkInternal && tarSym != nil && tarSym.Attr.Reachable() && (tarSym.Sect.Seg == &ld.Segdata) {
- t = ld.Symaddr(tarSym) + r.Add - ctxt.Syms.ROLookup("TOC", 0).Value
+ if target.IsInternal() && tarSym != nil && tarSym.Attr.Reachable() && (tarSym.Sect.Seg == &ld.Segdata) {
+ t = ld.Symaddr(tarSym) + r.Add - syms.TOC.Value
// change ld to addi in the second instruction
o2 = (o2 & 0x03FF0000) | 0xE<<26
useAddi = true
} else {
- t = ld.Symaddr(r.Sym) + r.Add - ctxt.Syms.ROLookup("TOC", 0).Value
+ t = ld.Symaddr(r.Sym) + r.Add - syms.TOC.Value
}
if t != int64(int32(t)) {
@@ -593,12 +575,12 @@
// archrelocaddr relocates a symbol address.
// This code is for AIX only.
-func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
- if ctxt.HeadType == objabi.Haix {
+func archrelocaddr(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
+ if target.IsAIX() {
ld.Errorf(s, "archrelocaddr called for %s relocation\n", r.Sym.Name)
}
var o1, o2 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o1 = uint32(val >> 32)
o2 = uint32(val)
} else {
@@ -635,7 +617,7 @@
return -1
}
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
return int64(o1)<<32 | int64(o2)
}
return int64(o2)<<32 | int64(o1)
@@ -770,13 +752,13 @@
ctxt.Arch.ByteOrder.PutUint32(tramp.P[12:], o4)
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
// On AIX, relocations (except TLS ones) must be also done to the
// value with the current addresses.
switch r.Type {
default:
- if ctxt.HeadType != objabi.Haix {
+ if target.IsAIX() {
return val, false
}
case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE:
@@ -806,14 +788,14 @@
}
r.Xsym = rs
- if ctxt.HeadType != objabi.Haix {
+ if !target.IsAIX() {
return val, true
}
case objabi.R_CALLPOWER:
r.Done = false
r.Xsym = r.Sym
r.Xadd = r.Add
- if ctxt.HeadType != objabi.Haix {
+ if !target.IsAIX() {
return val, true
}
}
@@ -823,11 +805,11 @@
case objabi.R_CONST:
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
case objabi.R_ADDRPOWER_TOCREL, objabi.R_ADDRPOWER_TOCREL_DS:
- return archreloctoc(ctxt, r, s, val), true
+ return archreloctoc(target, syms, r, s, val), true
case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS:
- return archrelocaddr(ctxt, r, s, val), true
+ return archrelocaddr(target, syms, r, s, val), true
case objabi.R_CALLPOWER:
// Bits 6 through 29 = (S + A - P) >> 2
@@ -843,7 +825,7 @@
}
return val | int64(uint32(t)&^0xfc000003), true
case objabi.R_POWER_TOC: // S + A - .TOC.
- return ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s), true
+ return ld.Symaddr(r.Sym) + r.Add - syms.DotTOC.Value, true
case objabi.R_POWER_TLS_LE:
// The thread pointer points 0x7000 bytes after the start of the
@@ -851,7 +833,7 @@
// Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
// Specification".
v := r.Sym.Value - 0x7000
- if ctxt.HeadType == objabi.Haix {
+ if target.IsAIX() {
// On AIX, the thread pointer points 0x7800 bytes after
// the TLS.
v -= 0x800
@@ -865,7 +847,7 @@
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
switch r.Variant & sym.RV_TYPE_MASK {
default:
ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
@@ -879,7 +861,7 @@
// Whether to check for signed or unsigned
// overflow depends on the instruction
var o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o1 = binary.BigEndian.Uint32(s.P[r.Off-2:])
} else {
o1 = binary.LittleEndian.Uint32(s.P[r.Off:])
@@ -913,7 +895,7 @@
// Whether to check for signed or unsigned
// overflow depends on the instruction
var o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o1 = binary.BigEndian.Uint32(s.P[r.Off-2:])
} else {
o1 = binary.LittleEndian.Uint32(s.P[r.Off:])
@@ -937,7 +919,7 @@
case sym.RV_POWER_DS:
var o1 uint32
- if ctxt.Arch.ByteOrder == binary.BigEndian {
+ if target.IsBigEndian() {
o1 = uint32(binary.BigEndian.Uint16(s.P[r.Off:]))
} else {
o1 = uint32(binary.LittleEndian.Uint16(s.P[r.Off:]))
@@ -961,13 +943,13 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ctxt.Syms.Lookup(".plt", 0)
rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
- elfsetupplt(ctxt)
+ panic("plt is not set up")
}
// Create the glink resolver if necessary
@@ -1056,7 +1038,7 @@
// before the first symbol resolver stub.
s := ctxt.Syms.Lookup(".dynamic", 0)
- ld.Elfwritedynentsymplus(ctxt, s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
+ ld.Elfwritedynentsymplus(ctxt.Arch, s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
return glink
}
diff --git a/src/cmd/link/internal/riscv64/asm.go b/src/cmd/link/internal/riscv64/asm.go
index b089728..bd8380b 100644
--- a/src/cmd/link/internal/riscv64/asm.go
+++ b/src/cmd/link/internal/riscv64/asm.go
@@ -9,6 +9,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"fmt"
"log"
@@ -17,11 +18,11 @@
func gentext(ctxt *ld.Link) {
}
-func adddynrela(ctxt *ld.Link, rel *sym.Symbol, s *sym.Symbol, r *sym.Reloc) {
+func adddynrela(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, rel *sym.Symbol, s *sym.Symbol, r *sym.Reloc) {
log.Fatalf("adddynrela not implemented")
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
log.Fatalf("adddynrel not implemented")
return false
}
@@ -31,7 +32,7 @@
return false
}
-func elfsetupplt(ctxt *ld.Link) {
+func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
log.Fatalf("elfsetuplt")
}
@@ -40,7 +41,7 @@
return false
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
switch r.Type {
case objabi.R_CALLRISCV:
// Nothing to do.
@@ -91,7 +92,7 @@
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
log.Fatalf("archrelocvariant")
return -1
}
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index 94a5a2f..57437f2 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -34,6 +34,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"fmt"
@@ -104,7 +105,7 @@
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
targ := r.Sym
r.InitExt()
@@ -333,10 +334,8 @@
return true
}
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- got := ctxt.Syms.Lookup(".got", 0)
- if plt.Size == 0 {
+func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() == 0 {
// stg %r1,56(%r15)
plt.AddUint8(0xe3)
plt.AddUint8(0x10)
@@ -347,7 +346,7 @@
// larl %r1,_GLOBAL_OFFSET_TABLE_
plt.AddUint8(0xc0)
plt.AddUint8(0x10)
- plt.AddPCRelPlus(ctxt.Arch, got, 6)
+ plt.AddSymRef(ctxt.Arch, got.Sym(), 6, objabi.R_PCRELDBL, 4)
// mvc 48(8,%r15),8(%r1)
plt.AddUint8(0xd2)
plt.AddUint8(0x07)
@@ -376,7 +375,7 @@
plt.AddUint8(0x00)
// assume got->size == 0 too
- got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
+ got.AddAddrPlus(ctxt.Arch, dynamic, 0)
got.AddUint64(ctxt.Arch, 0)
got.AddUint64(ctxt.Arch, 0)
@@ -387,8 +386,8 @@
return false
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
return val, false
}
@@ -396,13 +395,13 @@
case objabi.R_CONST:
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
}
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
switch r.Variant & sym.RV_TYPE_MASK {
default:
ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
@@ -424,14 +423,14 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ctxt.Syms.Lookup(".plt", 0)
got := ctxt.Syms.Lookup(".got", 0)
rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
- elfsetupplt(ctxt)
+ panic("plt is not set up")
}
// larl %r1,_GLOBAL_OFFSET_TABLE_+index
@@ -487,7 +486,7 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
got := ctxt.Syms.Lookup(".got", 0)
s.SetGot(int32(got.Size))
got.AddUint64(ctxt.Arch, 0)
diff --git a/src/cmd/link/internal/sym/compilation_unit.go b/src/cmd/link/internal/sym/compilation_unit.go
index 02fb0cf..b8b6845 100644
--- a/src/cmd/link/internal/sym/compilation_unit.go
+++ b/src/cmd/link/internal/sym/compilation_unit.go
@@ -6,6 +6,10 @@
import "cmd/internal/dwarf"
+// LoaderSym holds a loader.Sym value. We can't refer to this
+// type from the sym package since loader imports sym.
+type LoaderSym int
+
// CompilationUnit is an abstraction used by DWARF to represent a chunk of
// debug-related data. We create a CompilationUnit per Object file in a
// library (so, one for all the Go code, one for each assembly file, etc.).
@@ -20,4 +24,10 @@
RangeSyms []*Symbol // Symbols for debug_range
Textp []*Symbol // Text symbols in this CU
DWARFFileTable []string // The file table used to generate the .debug_lines
+
+ Consts2 LoaderSym // Package constants DIEs (loader)
+ FuncDIEs2 []LoaderSym // Function DIE subtrees (loader)
+ AbsFnDIEs2 []LoaderSym // Abstract function DIE subtrees (loader)
+ RangeSyms2 []LoaderSym // Symbols for debug_range (loader)
+ Textp2 []LoaderSym // Text symbols in this CU (loader)
}
diff --git a/src/cmd/link/internal/sym/library.go b/src/cmd/link/internal/sym/library.go
index 4f2023b..21568df 100644
--- a/src/cmd/link/internal/sym/library.go
+++ b/src/cmd/link/internal/sym/library.go
@@ -18,6 +18,9 @@
Main bool
Safe bool
Units []*CompilationUnit
+
+ Textp2 []LoaderSym // text syms defined in this library
+ DupTextSyms2 []LoaderSym // dupok text syms defined in this library
}
func (l Library) String() string {
diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go
index e9819a0..1fee966 100644
--- a/src/cmd/link/internal/sym/symbol.go
+++ b/src/cmd/link/internal/sym/symbol.go
@@ -103,6 +103,10 @@
return s.Size
}
+func (s *Symbol) Length(dwarfContext interface{}) int64 {
+ return s.Size
+}
+
func (s *Symbol) Grow(siz int64) {
if int64(int(siz)) != siz {
log.Fatalf("symgrow size %d too long", siz)
diff --git a/src/cmd/link/internal/sym/symbols.go b/src/cmd/link/internal/sym/symbols.go
index e772496..e64779d 100644
--- a/src/cmd/link/internal/sym/symbols.go
+++ b/src/cmd/link/internal/sym/symbols.go
@@ -31,105 +31,34 @@
package sym
type Symbols struct {
- symbolBatch []Symbol
-
// Symbol lookup based on name and indexed by version.
- hash []map[string]*Symbol
+ versions int
Allsym []*Symbol
+
+ // Provided by the loader
+
+ // Look up the symbol with the given name and version, creating the
+ // symbol if it is not found.
+ Lookup func(name string, v int) *Symbol
+
+ // Look up the symbol with the given name and version, returning nil
+ // if it is not found.
+ ROLookup func(name string, v int) *Symbol
+
+ // Rename renames a symbol.
+ Rename func(old, new string, v int)
}
func NewSymbols() *Symbols {
- hash := make([]map[string]*Symbol, SymVerStatic)
- // Preallocate about 2mb for hash of non static symbols
- hash[0] = make(map[string]*Symbol, 100000)
- // And another 1mb for internal ABI text symbols.
- hash[SymVerABIInternal] = make(map[string]*Symbol, 50000)
return &Symbols{
- hash: hash,
- Allsym: make([]*Symbol, 0, 100000),
+ versions: SymVerStatic,
+ Allsym: make([]*Symbol, 0, 100000),
}
}
-func (syms *Symbols) Newsym(name string, v int) *Symbol {
- batch := syms.symbolBatch
- if len(batch) == 0 {
- batch = make([]Symbol, 1000)
- }
- s := &batch[0]
- syms.symbolBatch = batch[1:]
-
- s.Dynid = -1
- s.Name = name
- s.Version = int16(v)
- syms.Allsym = append(syms.Allsym, s)
-
- return s
-}
-
-// Look up the symbol with the given name and version, creating the
-// symbol if it is not found.
-func (syms *Symbols) Lookup(name string, v int) *Symbol {
- m := syms.hash[v]
- s := m[name]
- if s != nil {
- return s
- }
- s = syms.Newsym(name, v)
- m[name] = s
- return s
-}
-
-// Look up the symbol with the given name and version, returning nil
-// if it is not found.
-func (syms *Symbols) ROLookup(name string, v int) *Symbol {
- 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))
- return len(syms.hash) - 1
-}
-
-// Rename renames a symbol.
-func (syms *Symbols) Rename(old, new string, v int, reachparent map[*Symbol]*Symbol) {
- s := syms.hash[v][old]
- oldExtName := s.Extname()
- s.Name = new
- if oldExtName == old {
- s.SetExtname(new)
- }
- delete(syms.hash[v], old)
-
- dup := syms.hash[v][new]
- if dup == nil {
- syms.hash[v][new] = s
- } else {
- if s.Type == 0 {
- dup.Attr |= s.Attr
- if s.Attr.Reachable() && reachparent != nil {
- reachparent[dup] = reachparent[s]
- }
- *s = *dup
- } else if dup.Type == 0 {
- s.Attr |= dup.Attr
- if dup.Attr.Reachable() && reachparent != nil {
- reachparent[s] = reachparent[dup]
- }
- *dup = *s
- syms.hash[v][new] = s
- }
- }
+ syms.versions++
+ return syms.versions - 1
}
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index 3fe36db..1e407d0 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -34,6 +34,7 @@
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/ld"
+ "cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"log"
@@ -167,7 +168,7 @@
initarray_entry.AddAddr(ctxt.Arch, initfunc)
}
-func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
+func adddynrel(ctxt *ld.Link, target *ld.Target, syms *ld.ArchSyms, s *sym.Symbol, r *sym.Reloc) bool {
targ := r.Sym
switch r.Type {
@@ -312,7 +313,7 @@
break
}
if ctxt.IsELF {
- ld.Adddynsym(ctxt, targ)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, targ)
rel := ctxt.Syms.Lookup(".rel", 0)
rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
@@ -332,7 +333,7 @@
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- ld.Adddynsym(ctxt, targ)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, targ)
got := ctxt.Syms.Lookup(".got", 0)
s.Type = got.Type
@@ -492,46 +493,44 @@
return true
}
-func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
- if ctxt.LinkMode == ld.LinkExternal {
+func archreloc(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
+ if target.IsExternal() {
return val, false
}
switch r.Type {
case objabi.R_CONST:
return r.Add, true
case objabi.R_GOTOFF:
- return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
+ return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(syms.GOT), true
}
return val, false
}
-func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
+func archrelocvariant(target *ld.Target, syms *ld.ArchSyms, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return t
}
-func elfsetupplt(ctxt *ld.Link) {
- plt := ctxt.Syms.Lookup(".plt", 0)
- got := ctxt.Syms.Lookup(".got.plt", 0)
- if plt.Size == 0 {
+func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
+ if plt.Size() == 0 {
// pushl got+4
plt.AddUint8(0xff)
plt.AddUint8(0x35)
- plt.AddAddrPlus(ctxt.Arch, got, 4)
+ plt.AddAddrPlus(ctxt.Arch, got.Sym(), 4)
// jmp *got+8
plt.AddUint8(0xff)
plt.AddUint8(0x25)
- plt.AddAddrPlus(ctxt.Arch, got, 8)
+ plt.AddAddrPlus(ctxt.Arch, got.Sym(), 8)
// zero pad
plt.AddUint32(ctxt.Arch, 0)
// assume got->size == 0 too
- got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
+ got.AddAddrPlus(ctxt.Arch, dynamic, 0)
got.AddUint32(ctxt.Arch, 0)
got.AddUint32(ctxt.Arch, 0)
@@ -543,14 +542,14 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
if ctxt.IsELF {
plt := ctxt.Syms.Lookup(".plt", 0)
got := ctxt.Syms.Lookup(".got.plt", 0)
rel := ctxt.Syms.Lookup(".rel.plt", 0)
if plt.Size == 0 {
- elfsetupplt(ctxt)
+ panic("plt is not set up")
}
// jmpq *got+size
@@ -603,7 +602,7 @@
return
}
- ld.Adddynsym(ctxt, s)
+ ld.Adddynsym(&ctxt.Target, &ctxt.ArchSyms, s)
got := ctxt.Syms.Lookup(".got", 0)
s.SetGot(int32(got.Size))
got.AddUint32(ctxt.Arch, 0)