mirror of https://github.com/golang/go.git
Merge "cmd: merge branch 'dev.link' into master"
This commit is contained in:
commit
bababde766
|
|
@ -23,6 +23,7 @@ var (
|
|||
Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
|
||||
AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
|
||||
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
|
||||
Newobj = flag.Bool("newobj", false, "use new object file format")
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -40,18 +40,18 @@ func main() {
|
|||
}
|
||||
ctxt.Flag_dynlink = *flags.Dynlink
|
||||
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
|
||||
ctxt.Flag_newobj = *flags.Newobj
|
||||
ctxt.Bso = bufio.NewWriter(os.Stdout)
|
||||
defer ctxt.Bso.Flush()
|
||||
|
||||
architecture.Init(ctxt)
|
||||
|
||||
// Create object file, write header.
|
||||
out, err := os.Create(*flags.OutputFile)
|
||||
buf, err := bio.Create(*flags.OutputFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer bio.MustClose(out)
|
||||
buf := bufio.NewWriter(bio.MustWriter(out))
|
||||
defer buf.Close()
|
||||
|
||||
if !*flags.SymABIs {
|
||||
fmt.Fprintf(buf, "go object %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version)
|
||||
|
|
@ -83,6 +83,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
if ok && !*flags.SymABIs {
|
||||
ctxt.NumberSyms(true)
|
||||
obj.WriteObjFile(ctxt, buf, "")
|
||||
}
|
||||
if !ok || diag {
|
||||
|
|
@ -91,9 +92,8 @@ func main() {
|
|||
} else {
|
||||
log.Print("assembly failed")
|
||||
}
|
||||
out.Close()
|
||||
buf.Close()
|
||||
os.Remove(*flags.OutputFile)
|
||||
os.Exit(1)
|
||||
}
|
||||
buf.Flush()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/src"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
|
@ -945,10 +946,12 @@ func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
|
|||
|
||||
func (w *exportWriter) varExt(n *Node) {
|
||||
w.linkname(n.Sym)
|
||||
w.symIdx(n.Sym)
|
||||
}
|
||||
|
||||
func (w *exportWriter) funcExt(n *Node) {
|
||||
w.linkname(n.Sym)
|
||||
w.symIdx(n.Sym)
|
||||
|
||||
// Escape analysis.
|
||||
for _, fs := range types.RecvsParams {
|
||||
|
|
@ -987,6 +990,22 @@ func (w *exportWriter) linkname(s *types.Sym) {
|
|||
w.string(s.Linkname)
|
||||
}
|
||||
|
||||
func (w *exportWriter) symIdx(s *types.Sym) {
|
||||
if Ctxt.Flag_newobj {
|
||||
lsym := s.Linksym()
|
||||
if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inline bodies.
|
||||
|
||||
func (w *exportWriter) stmtList(list Nodes) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package gc
|
|||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/src"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
|
@ -651,10 +652,12 @@ func (r *importReader) byte() byte {
|
|||
|
||||
func (r *importReader) varExt(n *Node) {
|
||||
r.linkname(n.Sym)
|
||||
r.symIdx(n.Sym)
|
||||
}
|
||||
|
||||
func (r *importReader) funcExt(n *Node) {
|
||||
r.linkname(n.Sym)
|
||||
r.symIdx(n.Sym)
|
||||
|
||||
// Escape analysis.
|
||||
for _, fs := range types.RecvsParams {
|
||||
|
|
@ -683,6 +686,20 @@ func (r *importReader) linkname(s *types.Sym) {
|
|||
s.Linkname = r.string()
|
||||
}
|
||||
|
||||
func (r *importReader) symIdx(s *types.Sym) {
|
||||
if Ctxt.Flag_newobj {
|
||||
lsym := s.Linksym()
|
||||
idx := int32(r.int64())
|
||||
if idx != -1 {
|
||||
if s.Linkname != "" {
|
||||
Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
|
||||
}
|
||||
lsym.SymIdx = idx
|
||||
lsym.Set(obj.AttrIndexed, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importReader) doInline(n *Node) {
|
||||
if len(n.Func.Inl.Body) != 0 {
|
||||
Fatalf("%v already has inline body", n)
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ func Main(archInit func(*Arch)) {
|
|||
if supportsDynlink(thearch.LinkArch.Arch) {
|
||||
flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
|
||||
flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
|
||||
flag.BoolVar(&Ctxt.Flag_linkshared, "linkshared", false, "generate code that will be linked against Go shared libraries")
|
||||
}
|
||||
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
|
||||
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
|
||||
|
|
@ -274,12 +275,14 @@ func Main(archInit func(*Arch)) {
|
|||
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
|
||||
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
|
||||
flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
|
||||
flag.BoolVar(&Ctxt.Flag_newobj, "newobj", false, "use new object file format")
|
||||
|
||||
objabi.Flagparse(usage)
|
||||
|
||||
// Record flags that affect the build result. (And don't
|
||||
// record flags that don't, since that would cause spurious
|
||||
// changes in the binary.)
|
||||
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes")
|
||||
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "newobj")
|
||||
|
||||
if smallFrames {
|
||||
maxStackVarSize = 128 * 1024
|
||||
|
|
@ -746,6 +749,8 @@ func Main(archInit func(*Arch)) {
|
|||
|
||||
// Write object data to disk.
|
||||
timings.Start("be", "dumpobj")
|
||||
dumpdata()
|
||||
Ctxt.NumberSyms(false)
|
||||
dumpobj()
|
||||
if asmhdr != "" {
|
||||
dumpasmhdr()
|
||||
|
|
|
|||
|
|
@ -111,21 +111,7 @@ func dumpCompilerObj(bout *bio.Writer) {
|
|||
dumpexport(bout)
|
||||
}
|
||||
|
||||
func dumpLinkerObj(bout *bio.Writer) {
|
||||
printObjHeader(bout)
|
||||
|
||||
if len(pragcgobuf) != 0 {
|
||||
// write empty export section; must be before cgo section
|
||||
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
|
||||
fmt.Fprintf(bout, "\n$$ // cgo\n")
|
||||
if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
|
||||
Fatalf("serializing pragcgobuf: %v", err)
|
||||
}
|
||||
fmt.Fprintf(bout, "\n$$\n\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(bout, "\n!\n")
|
||||
|
||||
func dumpdata() {
|
||||
externs := len(externdcl)
|
||||
|
||||
dumpglobls()
|
||||
|
|
@ -163,8 +149,24 @@ func dumpLinkerObj(bout *bio.Writer) {
|
|||
}
|
||||
|
||||
addGCLocals()
|
||||
}
|
||||
|
||||
obj.WriteObjFile(Ctxt, bout.Writer, myimportpath)
|
||||
func dumpLinkerObj(bout *bio.Writer) {
|
||||
printObjHeader(bout)
|
||||
|
||||
if len(pragcgobuf) != 0 {
|
||||
// write empty export section; must be before cgo section
|
||||
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
|
||||
fmt.Fprintf(bout, "\n$$ // cgo\n")
|
||||
if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
|
||||
Fatalf("serializing pragcgobuf: %v", err)
|
||||
}
|
||||
fmt.Fprintf(bout, "\n$$\n\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(bout, "\n!\n")
|
||||
|
||||
obj.WriteObjFile(Ctxt, bout, myimportpath)
|
||||
}
|
||||
|
||||
func addptabs() {
|
||||
|
|
|
|||
|
|
@ -80,11 +80,18 @@ func (sym *Sym) Linksym() *obj.LSym {
|
|||
if sym == nil {
|
||||
return nil
|
||||
}
|
||||
initPkg := func(r *obj.LSym) {
|
||||
if sym.Linkname != "" {
|
||||
r.Pkg = "_"
|
||||
} else {
|
||||
r.Pkg = sym.Pkg.Prefix
|
||||
}
|
||||
}
|
||||
if sym.Func() {
|
||||
// This is a function symbol. Mark it as "internal ABI".
|
||||
return Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
|
||||
return Ctxt.LookupABIInit(sym.LinksymName(), obj.ABIInternal, initPkg)
|
||||
}
|
||||
return Ctxt.Lookup(sym.LinksymName())
|
||||
return Ctxt.LookupInit(sym.LinksymName(), initPkg)
|
||||
}
|
||||
|
||||
// Less reports whether symbol a is ordered before symbol b.
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ var bootstrapDirs = []string{
|
|||
"cmd/internal/gcprog",
|
||||
"cmd/internal/dwarf",
|
||||
"cmd/internal/edit",
|
||||
"cmd/internal/goobj2",
|
||||
"cmd/internal/objabi",
|
||||
"cmd/internal/obj",
|
||||
"cmd/internal/obj/arm",
|
||||
|
|
@ -72,6 +73,7 @@ var bootstrapDirs = []string{
|
|||
"cmd/link/internal/arm64",
|
||||
"cmd/link/internal/ld",
|
||||
"cmd/link/internal/loadelf",
|
||||
"cmd/link/internal/loader",
|
||||
"cmd/link/internal/loadmacho",
|
||||
"cmd/link/internal/loadpe",
|
||||
"cmd/link/internal/loadxcoff",
|
||||
|
|
|
|||
|
|
@ -585,7 +585,7 @@ func (t *tester) registerTests() {
|
|||
},
|
||||
})
|
||||
// Also test a cgo package.
|
||||
if t.cgoEnabled {
|
||||
if t.cgoEnabled && t.internalLink() {
|
||||
t.tests = append(t.tests, distTest{
|
||||
name: "pie_internal_cgo",
|
||||
heading: "internal linking of -buildmode=pie",
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@
|
|||
// -ldflags '[pattern=]arg list'
|
||||
// arguments to pass on each go tool link invocation.
|
||||
// -linkshared
|
||||
// link against shared libraries previously created with
|
||||
// -buildmode=shared.
|
||||
// build code that will be linked against shared libraries previously
|
||||
// created with -buildmode=shared.
|
||||
// -mod mode
|
||||
// module download mode to use: readonly or vendor.
|
||||
// See 'go help modules' for more.
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ and test commands:
|
|||
-ldflags '[pattern=]arg list'
|
||||
arguments to pass on each go tool link invocation.
|
||||
-linkshared
|
||||
link against shared libraries previously created with
|
||||
-buildmode=shared.
|
||||
build code that will be linked against shared libraries previously
|
||||
created with -buildmode=shared.
|
||||
-mod mode
|
||||
module download mode to use: readonly or vendor.
|
||||
See 'go help modules' for more.
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ func buildModeInit() {
|
|||
base.Fatalf("-linkshared not supported on %s\n", platform)
|
||||
}
|
||||
codegenArg = "-dynlink"
|
||||
forcedGcflags = append(forcedGcflags, "-linkshared")
|
||||
// TODO(mwhudson): remove -w when that gets fixed in linker.
|
||||
forcedLdflags = append(forcedLdflags, "-linkshared", "-w")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1372,7 +1372,13 @@ func PutDefaultFunc(ctxt Context, s *FnState) error {
|
|||
abbrev := DW_ABRV_FUNCTION
|
||||
Uleb128put(ctxt, s.Info, int64(abbrev))
|
||||
|
||||
putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(s.Name)), s.Name)
|
||||
// Expand '"".' to import path.
|
||||
name := s.Name
|
||||
if s.Importpath != "" {
|
||||
name = strings.Replace(name, "\"\".", objabi.PathToPrefix(s.Importpath)+".", -1)
|
||||
}
|
||||
|
||||
putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
|
||||
putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC)
|
||||
putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC)
|
||||
putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
|
||||
|
|
|
|||
|
|
@ -502,6 +502,14 @@ func (r *objReader) parseObject(prefix []byte) error {
|
|||
}
|
||||
// TODO: extract OS + build ID if/when we need it
|
||||
|
||||
p, err := r.peek(8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bytes.Equal(p, []byte("\x00go114LD")) {
|
||||
r.readNew()
|
||||
return nil
|
||||
}
|
||||
r.readFull(r.tmp[:8])
|
||||
if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) {
|
||||
return r.error(errCorruptObject)
|
||||
|
|
|
|||
|
|
@ -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 goobj
|
||||
|
||||
import (
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/objabi"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Read object file in new format. For now we still fill
|
||||
// the data to the current goobj API.
|
||||
func (r *objReader) readNew() {
|
||||
start := uint32(r.offset)
|
||||
|
||||
length := r.limit - r.offset
|
||||
objbytes := make([]byte, length)
|
||||
r.readFull(objbytes)
|
||||
rr := goobj2.NewReaderFromBytes(objbytes, false)
|
||||
if rr == nil {
|
||||
panic("cannot read object file")
|
||||
}
|
||||
|
||||
// Imports
|
||||
r.p.Imports = rr.Autolib()
|
||||
|
||||
pkglist := rr.Pkglist()
|
||||
|
||||
abiToVer := func(abi uint16) int64 {
|
||||
var vers int64
|
||||
if abi == goobj2.SymABIstatic {
|
||||
// Static symbol
|
||||
vers = r.p.MaxVersion
|
||||
}
|
||||
return vers
|
||||
}
|
||||
|
||||
resolveSymRef := func(s goobj2.SymRef) SymID {
|
||||
var i int
|
||||
switch p := s.PkgIdx; p {
|
||||
case goobj2.PkgIdxInvalid:
|
||||
if s.SymIdx != 0 {
|
||||
panic("bad sym ref")
|
||||
}
|
||||
return SymID{}
|
||||
case goobj2.PkgIdxNone:
|
||||
i = int(s.SymIdx) + rr.NSym()
|
||||
case goobj2.PkgIdxBuiltin:
|
||||
name, abi := goobj2.BuiltinName(int(s.SymIdx))
|
||||
return SymID{name, int64(abi)}
|
||||
case goobj2.PkgIdxSelf:
|
||||
i = int(s.SymIdx)
|
||||
default:
|
||||
pkg := pkglist[p]
|
||||
return SymID{fmt.Sprintf("%s.<#%d>", pkg, s.SymIdx), 0}
|
||||
}
|
||||
sym := goobj2.Sym{}
|
||||
sym.Read(rr, rr.SymOff(i))
|
||||
return SymID{sym.Name, abiToVer(sym.ABI)}
|
||||
}
|
||||
|
||||
// Read things for the current goobj API for now.
|
||||
|
||||
// Symbols
|
||||
pcdataBase := start + rr.PcdataBase()
|
||||
n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref()
|
||||
ndef := rr.NSym() + rr.NNonpkgdef()
|
||||
for i := 0; i < n; i++ {
|
||||
osym := goobj2.Sym{}
|
||||
osym.Read(rr, rr.SymOff(i))
|
||||
if osym.Name == "" {
|
||||
continue // not a real symbol
|
||||
}
|
||||
// In a symbol name in an object file, "". denotes the
|
||||
// prefix for the package in which the object file has been found.
|
||||
// Expand it.
|
||||
name := strings.ReplaceAll(osym.Name, `"".`, r.pkgprefix)
|
||||
symID := SymID{Name: name, Version: abiToVer(osym.ABI)}
|
||||
r.p.SymRefs = append(r.p.SymRefs, symID)
|
||||
|
||||
if i >= ndef {
|
||||
continue // not a defined symbol from here
|
||||
}
|
||||
|
||||
// Symbol data
|
||||
dataOff := rr.DataOff(i)
|
||||
siz := int64(rr.DataSize(i))
|
||||
|
||||
sym := Sym{
|
||||
SymID: symID,
|
||||
Kind: objabi.SymKind(osym.Type),
|
||||
DupOK: osym.Dupok(),
|
||||
Size: int64(osym.Siz),
|
||||
Data: Data{int64(start + dataOff), siz},
|
||||
}
|
||||
r.p.Syms = append(r.p.Syms, &sym)
|
||||
|
||||
// Reloc
|
||||
nreloc := rr.NReloc(i)
|
||||
sym.Reloc = make([]Reloc, nreloc)
|
||||
for j := 0; j < nreloc; j++ {
|
||||
rel := goobj2.Reloc{}
|
||||
rel.Read(rr, rr.RelocOff(i, j))
|
||||
sym.Reloc[j] = Reloc{
|
||||
Offset: int64(rel.Off),
|
||||
Size: int64(rel.Siz),
|
||||
Type: objabi.RelocType(rel.Type),
|
||||
Add: rel.Add,
|
||||
Sym: resolveSymRef(rel.Sym),
|
||||
}
|
||||
}
|
||||
|
||||
// Aux symbol info
|
||||
isym := -1
|
||||
funcdata := make([]goobj2.SymRef, 0, 4)
|
||||
naux := rr.NAux(i)
|
||||
for j := 0; j < naux; j++ {
|
||||
a := goobj2.Aux{}
|
||||
a.Read(rr, rr.AuxOff(i, j))
|
||||
switch a.Type {
|
||||
case goobj2.AuxGotype:
|
||||
sym.Type = resolveSymRef(a.Sym)
|
||||
case goobj2.AuxFuncInfo:
|
||||
if a.Sym.PkgIdx != goobj2.PkgIdxSelf {
|
||||
panic("funcinfo symbol not defined in current package")
|
||||
}
|
||||
isym = int(a.Sym.SymIdx)
|
||||
case goobj2.AuxFuncdata:
|
||||
funcdata = append(funcdata, a.Sym)
|
||||
case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
|
||||
// nothing to do
|
||||
default:
|
||||
panic("unknown aux type")
|
||||
}
|
||||
}
|
||||
|
||||
// Symbol Info
|
||||
if isym == -1 {
|
||||
continue
|
||||
}
|
||||
b := rr.BytesAt(rr.DataOff(isym), rr.DataSize(isym))
|
||||
info := goobj2.FuncInfo{}
|
||||
info.Read(b)
|
||||
|
||||
info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends
|
||||
f := &Func{
|
||||
Args: int64(info.Args),
|
||||
Frame: int64(info.Locals),
|
||||
NoSplit: info.NoSplit != 0,
|
||||
Leaf: osym.Leaf(),
|
||||
TopFrame: osym.TopFrame(),
|
||||
PCSP: Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)},
|
||||
PCFile: Data{int64(pcdataBase + info.Pcfile), int64(info.Pcline - info.Pcfile)},
|
||||
PCLine: Data{int64(pcdataBase + info.Pcline), int64(info.Pcinline - info.Pcline)},
|
||||
PCInline: Data{int64(pcdataBase + info.Pcinline), int64(info.Pcdata[0] - info.Pcinline)},
|
||||
PCData: make([]Data, len(info.Pcdata)-1), // -1 as we appended one above
|
||||
FuncData: make([]FuncData, len(info.Funcdataoff)),
|
||||
File: make([]string, len(info.File)),
|
||||
InlTree: make([]InlinedCall, len(info.InlTree)),
|
||||
}
|
||||
sym.Func = f
|
||||
for k := range f.PCData {
|
||||
f.PCData[k] = Data{int64(pcdataBase + info.Pcdata[k]), int64(info.Pcdata[k+1] - info.Pcdata[k])}
|
||||
}
|
||||
for k := range f.FuncData {
|
||||
symID := resolveSymRef(funcdata[k])
|
||||
f.FuncData[k] = FuncData{symID, int64(info.Funcdataoff[k])}
|
||||
}
|
||||
for k := range f.File {
|
||||
symID := resolveSymRef(info.File[k])
|
||||
f.File[k] = symID.Name
|
||||
}
|
||||
for k := range f.InlTree {
|
||||
inl := &info.InlTree[k]
|
||||
f.InlTree[k] = InlinedCall{
|
||||
Parent: int64(inl.Parent),
|
||||
File: resolveSymRef(inl.File).Name,
|
||||
Line: int64(inl.Line),
|
||||
Func: resolveSymRef(inl.Func),
|
||||
ParentPC: int64(inl.ParentPC),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package goobj2
|
||||
|
||||
// Builtin (compiler-generated) function references appear
|
||||
// frequently. We assign special indices for them, so they
|
||||
// don't need to be referenced by name.
|
||||
|
||||
// NBuiltin returns the number of listed builtin
|
||||
// symbols.
|
||||
func NBuiltin() int {
|
||||
return len(builtins)
|
||||
}
|
||||
|
||||
// BuiltinName returns the name and ABI of the i-th
|
||||
// builtin symbol.
|
||||
func BuiltinName(i int) (string, int) {
|
||||
return builtins[i].name, builtins[i].abi
|
||||
}
|
||||
|
||||
// BuiltinIdx returns the index of the builtin with the
|
||||
// given name and abi, or -1 if it is not a builtin.
|
||||
func BuiltinIdx(name string, abi int) int {
|
||||
i, ok := builtinMap[name]
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
if builtins[i].abi != abi {
|
||||
return -1
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
//go:generate go run mkbuiltin.go
|
||||
|
||||
var builtinMap map[string]int
|
||||
|
||||
func init() {
|
||||
builtinMap = make(map[string]int, len(builtins))
|
||||
for i, b := range builtins {
|
||||
builtinMap[b.name] = i
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
// Code generated by mkbuiltin.go. DO NOT EDIT.
|
||||
|
||||
package goobj2
|
||||
|
||||
var builtins = [...]struct {
|
||||
name string
|
||||
abi int
|
||||
}{
|
||||
{"runtime.newobject", 1},
|
||||
{"runtime.panicdivide", 1},
|
||||
{"runtime.panicshift", 1},
|
||||
{"runtime.panicmakeslicelen", 1},
|
||||
{"runtime.throwinit", 1},
|
||||
{"runtime.panicwrap", 1},
|
||||
{"runtime.gopanic", 1},
|
||||
{"runtime.gorecover", 1},
|
||||
{"runtime.goschedguarded", 1},
|
||||
{"runtime.goPanicIndex", 1},
|
||||
{"runtime.goPanicIndexU", 1},
|
||||
{"runtime.goPanicSliceAlen", 1},
|
||||
{"runtime.goPanicSliceAlenU", 1},
|
||||
{"runtime.goPanicSliceAcap", 1},
|
||||
{"runtime.goPanicSliceAcapU", 1},
|
||||
{"runtime.goPanicSliceB", 1},
|
||||
{"runtime.goPanicSliceBU", 1},
|
||||
{"runtime.goPanicSlice3Alen", 1},
|
||||
{"runtime.goPanicSlice3AlenU", 1},
|
||||
{"runtime.goPanicSlice3Acap", 1},
|
||||
{"runtime.goPanicSlice3AcapU", 1},
|
||||
{"runtime.goPanicSlice3B", 1},
|
||||
{"runtime.goPanicSlice3BU", 1},
|
||||
{"runtime.goPanicSlice3C", 1},
|
||||
{"runtime.goPanicSlice3CU", 1},
|
||||
{"runtime.printbool", 1},
|
||||
{"runtime.printfloat", 1},
|
||||
{"runtime.printint", 1},
|
||||
{"runtime.printhex", 1},
|
||||
{"runtime.printuint", 1},
|
||||
{"runtime.printcomplex", 1},
|
||||
{"runtime.printstring", 1},
|
||||
{"runtime.printpointer", 1},
|
||||
{"runtime.printiface", 1},
|
||||
{"runtime.printeface", 1},
|
||||
{"runtime.printslice", 1},
|
||||
{"runtime.printnl", 1},
|
||||
{"runtime.printsp", 1},
|
||||
{"runtime.printlock", 1},
|
||||
{"runtime.printunlock", 1},
|
||||
{"runtime.concatstring2", 1},
|
||||
{"runtime.concatstring3", 1},
|
||||
{"runtime.concatstring4", 1},
|
||||
{"runtime.concatstring5", 1},
|
||||
{"runtime.concatstrings", 1},
|
||||
{"runtime.cmpstring", 1},
|
||||
{"runtime.intstring", 1},
|
||||
{"runtime.slicebytetostring", 1},
|
||||
{"runtime.slicebytetostringtmp", 1},
|
||||
{"runtime.slicerunetostring", 1},
|
||||
{"runtime.stringtoslicebyte", 1},
|
||||
{"runtime.stringtoslicerune", 1},
|
||||
{"runtime.slicecopy", 1},
|
||||
{"runtime.slicestringcopy", 1},
|
||||
{"runtime.decoderune", 1},
|
||||
{"runtime.countrunes", 1},
|
||||
{"runtime.convI2I", 1},
|
||||
{"runtime.convT16", 1},
|
||||
{"runtime.convT32", 1},
|
||||
{"runtime.convT64", 1},
|
||||
{"runtime.convTstring", 1},
|
||||
{"runtime.convTslice", 1},
|
||||
{"runtime.convT2E", 1},
|
||||
{"runtime.convT2Enoptr", 1},
|
||||
{"runtime.convT2I", 1},
|
||||
{"runtime.convT2Inoptr", 1},
|
||||
{"runtime.assertE2I", 1},
|
||||
{"runtime.assertE2I2", 1},
|
||||
{"runtime.assertI2I", 1},
|
||||
{"runtime.assertI2I2", 1},
|
||||
{"runtime.panicdottypeE", 1},
|
||||
{"runtime.panicdottypeI", 1},
|
||||
{"runtime.panicnildottype", 1},
|
||||
{"runtime.ifaceeq", 1},
|
||||
{"runtime.efaceeq", 1},
|
||||
{"runtime.fastrand", 1},
|
||||
{"runtime.makemap64", 1},
|
||||
{"runtime.makemap", 1},
|
||||
{"runtime.makemap_small", 1},
|
||||
{"runtime.mapaccess1", 1},
|
||||
{"runtime.mapaccess1_fast32", 1},
|
||||
{"runtime.mapaccess1_fast64", 1},
|
||||
{"runtime.mapaccess1_faststr", 1},
|
||||
{"runtime.mapaccess1_fat", 1},
|
||||
{"runtime.mapaccess2", 1},
|
||||
{"runtime.mapaccess2_fast32", 1},
|
||||
{"runtime.mapaccess2_fast64", 1},
|
||||
{"runtime.mapaccess2_faststr", 1},
|
||||
{"runtime.mapaccess2_fat", 1},
|
||||
{"runtime.mapassign", 1},
|
||||
{"runtime.mapassign_fast32", 1},
|
||||
{"runtime.mapassign_fast32ptr", 1},
|
||||
{"runtime.mapassign_fast64", 1},
|
||||
{"runtime.mapassign_fast64ptr", 1},
|
||||
{"runtime.mapassign_faststr", 1},
|
||||
{"runtime.mapiterinit", 1},
|
||||
{"runtime.mapdelete", 1},
|
||||
{"runtime.mapdelete_fast32", 1},
|
||||
{"runtime.mapdelete_fast64", 1},
|
||||
{"runtime.mapdelete_faststr", 1},
|
||||
{"runtime.mapiternext", 1},
|
||||
{"runtime.mapclear", 1},
|
||||
{"runtime.makechan64", 1},
|
||||
{"runtime.makechan", 1},
|
||||
{"runtime.chanrecv1", 1},
|
||||
{"runtime.chanrecv2", 1},
|
||||
{"runtime.chansend1", 1},
|
||||
{"runtime.closechan", 1},
|
||||
{"runtime.writeBarrier", 0},
|
||||
{"runtime.typedmemmove", 1},
|
||||
{"runtime.typedmemclr", 1},
|
||||
{"runtime.typedslicecopy", 1},
|
||||
{"runtime.selectnbsend", 1},
|
||||
{"runtime.selectnbrecv", 1},
|
||||
{"runtime.selectnbrecv2", 1},
|
||||
{"runtime.selectsetpc", 1},
|
||||
{"runtime.selectgo", 1},
|
||||
{"runtime.block", 1},
|
||||
{"runtime.makeslice", 1},
|
||||
{"runtime.makeslice64", 1},
|
||||
{"runtime.growslice", 1},
|
||||
{"runtime.memmove", 1},
|
||||
{"runtime.memclrNoHeapPointers", 1},
|
||||
{"runtime.memclrHasPointers", 1},
|
||||
{"runtime.memequal", 1},
|
||||
{"runtime.memequal0", 1},
|
||||
{"runtime.memequal8", 1},
|
||||
{"runtime.memequal16", 1},
|
||||
{"runtime.memequal32", 1},
|
||||
{"runtime.memequal64", 1},
|
||||
{"runtime.memequal128", 1},
|
||||
{"runtime.f32equal", 1},
|
||||
{"runtime.f64equal", 1},
|
||||
{"runtime.c64equal", 1},
|
||||
{"runtime.c128equal", 1},
|
||||
{"runtime.strequal", 1},
|
||||
{"runtime.interequal", 1},
|
||||
{"runtime.nilinterequal", 1},
|
||||
{"runtime.memhash", 1},
|
||||
{"runtime.memhash0", 1},
|
||||
{"runtime.memhash8", 1},
|
||||
{"runtime.memhash16", 1},
|
||||
{"runtime.memhash32", 1},
|
||||
{"runtime.memhash64", 1},
|
||||
{"runtime.memhash128", 1},
|
||||
{"runtime.f32hash", 1},
|
||||
{"runtime.f64hash", 1},
|
||||
{"runtime.c64hash", 1},
|
||||
{"runtime.c128hash", 1},
|
||||
{"runtime.strhash", 1},
|
||||
{"runtime.interhash", 1},
|
||||
{"runtime.nilinterhash", 1},
|
||||
{"runtime.int64div", 1},
|
||||
{"runtime.uint64div", 1},
|
||||
{"runtime.int64mod", 1},
|
||||
{"runtime.uint64mod", 1},
|
||||
{"runtime.float64toint64", 1},
|
||||
{"runtime.float64touint64", 1},
|
||||
{"runtime.float64touint32", 1},
|
||||
{"runtime.int64tofloat64", 1},
|
||||
{"runtime.uint64tofloat64", 1},
|
||||
{"runtime.uint32tofloat64", 1},
|
||||
{"runtime.complex128div", 1},
|
||||
{"runtime.racefuncenter", 1},
|
||||
{"runtime.racefuncenterfp", 1},
|
||||
{"runtime.racefuncexit", 1},
|
||||
{"runtime.raceread", 1},
|
||||
{"runtime.racewrite", 1},
|
||||
{"runtime.racereadrange", 1},
|
||||
{"runtime.racewriterange", 1},
|
||||
{"runtime.msanread", 1},
|
||||
{"runtime.msanwrite", 1},
|
||||
{"runtime.checkptrAlignment", 1},
|
||||
{"runtime.checkptrArithmetic", 1},
|
||||
{"runtime.x86HasPOPCNT", 0},
|
||||
{"runtime.x86HasSSE41", 0},
|
||||
{"runtime.arm64HasATOMICS", 0},
|
||||
{"runtime.gcWriteBarrier", 0},
|
||||
{"runtime.deferproc", 1},
|
||||
{"runtime.deferprocStack", 1},
|
||||
{"runtime.deferreturn", 1},
|
||||
{"runtime.newproc", 1},
|
||||
{"runtime.morestack", 0},
|
||||
{"runtime.morestackc", 0},
|
||||
{"runtime.morestack_noctxt", 0},
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package goobj2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// FuncInfo is serialized as a symbol (aux symbol). The symbol data is
|
||||
// the binary encoding of the struct below.
|
||||
//
|
||||
// TODO: make each pcdata a separate symbol?
|
||||
type FuncInfo struct {
|
||||
NoSplit uint8
|
||||
|
||||
Args uint32
|
||||
Locals uint32
|
||||
|
||||
Pcsp uint32
|
||||
Pcfile uint32
|
||||
Pcline uint32
|
||||
Pcinline uint32
|
||||
Pcdata []uint32
|
||||
PcdataEnd uint32
|
||||
Funcdataoff []uint32
|
||||
File []SymRef // TODO: just use string?
|
||||
|
||||
InlTree []InlTreeNode
|
||||
}
|
||||
|
||||
func (a *FuncInfo) Write(w *bytes.Buffer) {
|
||||
w.WriteByte(a.NoSplit)
|
||||
|
||||
var b [4]byte
|
||||
writeUint32 := func(x uint32) {
|
||||
binary.LittleEndian.PutUint32(b[:], x)
|
||||
w.Write(b[:])
|
||||
}
|
||||
|
||||
writeUint32(a.Args)
|
||||
writeUint32(a.Locals)
|
||||
|
||||
writeUint32(a.Pcsp)
|
||||
writeUint32(a.Pcfile)
|
||||
writeUint32(a.Pcline)
|
||||
writeUint32(a.Pcinline)
|
||||
writeUint32(uint32(len(a.Pcdata)))
|
||||
for _, x := range a.Pcdata {
|
||||
writeUint32(x)
|
||||
}
|
||||
writeUint32(a.PcdataEnd)
|
||||
writeUint32(uint32(len(a.Funcdataoff)))
|
||||
for _, x := range a.Funcdataoff {
|
||||
writeUint32(x)
|
||||
}
|
||||
writeUint32(uint32(len(a.File)))
|
||||
for _, f := range a.File {
|
||||
writeUint32(f.PkgIdx)
|
||||
writeUint32(f.SymIdx)
|
||||
}
|
||||
writeUint32(uint32(len(a.InlTree)))
|
||||
for i := range a.InlTree {
|
||||
a.InlTree[i].Write(w)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *FuncInfo) Read(b []byte) {
|
||||
a.NoSplit = b[0]
|
||||
b = b[1:]
|
||||
|
||||
readUint32 := func() uint32 {
|
||||
x := binary.LittleEndian.Uint32(b)
|
||||
b = b[4:]
|
||||
return x
|
||||
}
|
||||
|
||||
a.Args = readUint32()
|
||||
a.Locals = readUint32()
|
||||
|
||||
a.Pcsp = readUint32()
|
||||
a.Pcfile = readUint32()
|
||||
a.Pcline = readUint32()
|
||||
a.Pcinline = readUint32()
|
||||
pcdatalen := readUint32()
|
||||
a.Pcdata = make([]uint32, pcdatalen)
|
||||
for i := range a.Pcdata {
|
||||
a.Pcdata[i] = readUint32()
|
||||
}
|
||||
a.PcdataEnd = readUint32()
|
||||
funcdataofflen := readUint32()
|
||||
a.Funcdataoff = make([]uint32, funcdataofflen)
|
||||
for i := range a.Funcdataoff {
|
||||
a.Funcdataoff[i] = readUint32()
|
||||
}
|
||||
filelen := readUint32()
|
||||
a.File = make([]SymRef, filelen)
|
||||
for i := range a.File {
|
||||
a.File[i] = SymRef{readUint32(), readUint32()}
|
||||
}
|
||||
inltreelen := readUint32()
|
||||
a.InlTree = make([]InlTreeNode, inltreelen)
|
||||
for i := range a.InlTree {
|
||||
b = a.InlTree[i].Read(b)
|
||||
}
|
||||
}
|
||||
|
||||
// InlTreeNode is the serialized form of FileInfo.InlTree.
|
||||
type InlTreeNode struct {
|
||||
Parent int32
|
||||
File SymRef
|
||||
Line int32
|
||||
Func SymRef
|
||||
ParentPC int32
|
||||
}
|
||||
|
||||
func (inl *InlTreeNode) Write(w *bytes.Buffer) {
|
||||
var b [4]byte
|
||||
writeUint32 := func(x uint32) {
|
||||
binary.LittleEndian.PutUint32(b[:], x)
|
||||
w.Write(b[:])
|
||||
}
|
||||
writeUint32(uint32(inl.Parent))
|
||||
writeUint32(inl.File.PkgIdx)
|
||||
writeUint32(inl.File.SymIdx)
|
||||
writeUint32(uint32(inl.Line))
|
||||
writeUint32(inl.Func.PkgIdx)
|
||||
writeUint32(inl.Func.SymIdx)
|
||||
writeUint32(uint32(inl.ParentPC))
|
||||
}
|
||||
|
||||
// Read an InlTreeNode from b, return the remaining bytes.
|
||||
func (inl *InlTreeNode) Read(b []byte) []byte {
|
||||
readUint32 := func() uint32 {
|
||||
x := binary.LittleEndian.Uint32(b)
|
||||
b = b[4:]
|
||||
return x
|
||||
}
|
||||
inl.Parent = int32(readUint32())
|
||||
inl.File = SymRef{readUint32(), readUint32()}
|
||||
inl.Line = int32(readUint32())
|
||||
inl.Func = SymRef{readUint32(), readUint32()}
|
||||
inl.ParentPC = int32(readUint32())
|
||||
return b
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
// 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.
|
||||
|
||||
// +build ignore
|
||||
|
||||
// Generate builtinlist.go from cmd/compile/internal/gc/builtin/runtime.go.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var stdout = flag.Bool("stdout", false, "write to stdout instead of builtinlist.go")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
|
||||
fmt.Fprintln(&b)
|
||||
fmt.Fprintln(&b, "package goobj2")
|
||||
|
||||
mkbuiltin(&b)
|
||||
|
||||
out, err := format.Source(b.Bytes())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if *stdout {
|
||||
_, err = os.Stdout.Write(out)
|
||||
} else {
|
||||
err = ioutil.WriteFile("builtinlist.go", out, 0666)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func mkbuiltin(w io.Writer) {
|
||||
pkg := "runtime"
|
||||
fset := token.NewFileSet()
|
||||
path := filepath.Join("..", "..", "compile", "internal", "gc", "builtin", "runtime.go")
|
||||
f, err := parser.ParseFile(fset, path, nil, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
decls := make(map[string]bool)
|
||||
|
||||
fmt.Fprintf(w, "var builtins = [...]struct{ name string; abi int }{\n")
|
||||
for _, decl := range f.Decls {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if decl.Recv != nil {
|
||||
log.Fatal("methods unsupported")
|
||||
}
|
||||
if decl.Body != nil {
|
||||
log.Fatal("unexpected function body")
|
||||
}
|
||||
declName := pkg + "." + decl.Name.Name
|
||||
decls[declName] = true
|
||||
fmt.Fprintf(w, "{%q, 1},\n", declName) // functions are ABIInternal (1)
|
||||
case *ast.GenDecl:
|
||||
if decl.Tok == token.IMPORT {
|
||||
continue
|
||||
}
|
||||
if decl.Tok != token.VAR {
|
||||
log.Fatal("unhandled declaration kind", decl.Tok)
|
||||
}
|
||||
for _, spec := range decl.Specs {
|
||||
spec := spec.(*ast.ValueSpec)
|
||||
if len(spec.Values) != 0 {
|
||||
log.Fatal("unexpected values")
|
||||
}
|
||||
for _, name := range spec.Names {
|
||||
declName := pkg + "." + name.Name
|
||||
decls[declName] = true
|
||||
fmt.Fprintf(w, "{%q, 0},\n", declName) // variables are ABI0
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Fatal("unhandled decl type", decl)
|
||||
}
|
||||
}
|
||||
|
||||
// The list above only contains ones that are used by the frontend.
|
||||
// The backend may create more references of builtin functions.
|
||||
// Add them.
|
||||
for _, b := range extra {
|
||||
name := pkg + "." + b.name
|
||||
if decls[name] {
|
||||
log.Fatalf("%q already added -- mkbuiltin.go out of sync?", name)
|
||||
}
|
||||
fmt.Fprintf(w, "{%q, %d},\n", name, b.abi)
|
||||
}
|
||||
fmt.Fprintln(w, "}")
|
||||
}
|
||||
|
||||
var extra = [...]struct {
|
||||
name string
|
||||
abi int
|
||||
}{
|
||||
{"gcWriteBarrier", 0}, // asm function, ABI0
|
||||
{"deferproc", 1},
|
||||
{"deferprocStack", 1},
|
||||
{"deferreturn", 1},
|
||||
{"newproc", 1},
|
||||
{"morestack", 0}, // asm function, ABI0
|
||||
{"morestackc", 0}, // asm function, ABI0
|
||||
{"morestack_noctxt", 0}, // asm function, ABI0
|
||||
}
|
||||
|
|
@ -0,0 +1,587 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Go new object file format, reading and writing.
|
||||
|
||||
package goobj2 // TODO: replace the goobj package?
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// New object file format.
|
||||
//
|
||||
// Header struct {
|
||||
// Magic [...]byte // "\x00go114LD"
|
||||
// Flags uint32
|
||||
// // TODO: Fingerprint
|
||||
// Offsets [...]uint32 // byte offset of each block below
|
||||
// }
|
||||
//
|
||||
// Strings [...]struct {
|
||||
// Len uint32
|
||||
// Data [...]byte
|
||||
// }
|
||||
//
|
||||
// Autolib [...]stringOff // imported packages (for file loading) // TODO: add fingerprints
|
||||
// PkgIndex [...]stringOff // referenced packages by index
|
||||
//
|
||||
// DwarfFiles [...]stringOff
|
||||
//
|
||||
// SymbolDefs [...]struct {
|
||||
// Name stringOff
|
||||
// ABI uint16
|
||||
// Type uint8
|
||||
// Flag uint8
|
||||
// Size uint32
|
||||
// }
|
||||
// NonPkgDefs [...]struct { // non-pkg symbol definitions
|
||||
// ... // same as SymbolDefs
|
||||
// }
|
||||
// NonPkgRefs [...]struct { // non-pkg symbol references
|
||||
// ... // same as SymbolDefs
|
||||
// }
|
||||
//
|
||||
// RelocIndex [...]uint32 // index to Relocs
|
||||
// AuxIndex [...]uint32 // index to Aux
|
||||
// DataIndex [...]uint32 // offset to Data
|
||||
//
|
||||
// Relocs [...]struct {
|
||||
// Off int32
|
||||
// Size uint8
|
||||
// Type uint8
|
||||
// Add int64
|
||||
// Sym symRef
|
||||
// }
|
||||
//
|
||||
// Aux [...]struct {
|
||||
// Type uint8
|
||||
// Sym symRef
|
||||
// }
|
||||
//
|
||||
// Data [...]byte
|
||||
// Pcdata [...]byte
|
||||
//
|
||||
// stringOff is a uint32 (?) offset that points to the corresponding
|
||||
// string, which is a uint32 length followed by that number of bytes.
|
||||
//
|
||||
// symRef is struct { PkgIdx, SymIdx uint32 }.
|
||||
//
|
||||
// Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
|
||||
// followed by that number of elements.
|
||||
//
|
||||
// The types below correspond to the encoded data structure in the
|
||||
// object file.
|
||||
|
||||
// Symbol indexing.
|
||||
//
|
||||
// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
|
||||
// as the symRef struct above.
|
||||
//
|
||||
// PkgIdx is either a predeclared index (see PkgIdxNone below) or
|
||||
// an index of an imported package. For the latter case, PkgIdx is the
|
||||
// index of the package in the PkgIndex array. 0 is an invalid index.
|
||||
//
|
||||
// SymIdx is the index of the symbol in the given package.
|
||||
// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
|
||||
// SymbolDefs array.
|
||||
// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
|
||||
// NonPkgDefs array (could natually overflow to NonPkgRefs array).
|
||||
// - Otherwise, SymIdx is the index of the symbol in some other package's
|
||||
// SymbolDefs array.
|
||||
//
|
||||
// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
|
||||
//
|
||||
// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
|
||||
// Relocs/Aux/Data blocks, one element per symbol, first for all the
|
||||
// defined symbols, then all the defined non-package symbols, in the
|
||||
// same order of SymbolDefs/NonPkgDefs arrays. For N total defined
|
||||
// symbols, the array is of length N+1. The last element is the total
|
||||
// number of relocations (aux symbols, data blocks, etc.).
|
||||
//
|
||||
// They can be accessed by index. For the i-th symbol, its relocations
|
||||
// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
|
||||
// elements in the Relocs array. Aux/Data are likewise. (The index is
|
||||
// 0-based.)
|
||||
|
||||
// Auxiliary symbols.
|
||||
//
|
||||
// Each symbol may (or may not) be associated with a number of auxiliary
|
||||
// symbols. They are described in the Aux block. See Aux struct below.
|
||||
// Currently a symbol's Gotype and FuncInfo are auxiliary symbols. We
|
||||
// may make use of aux symbols in more cases, e.g. DWARF symbols.
|
||||
|
||||
// Package Index.
|
||||
const (
|
||||
PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
|
||||
PkgIdxBuiltin // Predefined symbols // TODO: not used for now, we could use it for compiler-generated symbols like runtime.newobject
|
||||
PkgIdxSelf // Symbols defined in the current package
|
||||
PkgIdxInvalid = 0
|
||||
// The index of other referenced packages starts from 1.
|
||||
)
|
||||
|
||||
// Blocks
|
||||
const (
|
||||
BlkAutolib = iota
|
||||
BlkPkgIdx
|
||||
BlkDwarfFile
|
||||
BlkSymdef
|
||||
BlkNonpkgdef
|
||||
BlkNonpkgref
|
||||
BlkRelocIdx
|
||||
BlkAuxIdx
|
||||
BlkDataIdx
|
||||
BlkReloc
|
||||
BlkAux
|
||||
BlkData
|
||||
BlkPcdata
|
||||
NBlk
|
||||
)
|
||||
|
||||
// File header.
|
||||
// TODO: probably no need to export this.
|
||||
type Header struct {
|
||||
Magic string
|
||||
Flags uint32
|
||||
Offsets [NBlk]uint32
|
||||
}
|
||||
|
||||
const Magic = "\x00go114LD"
|
||||
|
||||
func (h *Header) Write(w *Writer) {
|
||||
w.RawString(h.Magic)
|
||||
w.Uint32(h.Flags)
|
||||
for _, x := range h.Offsets {
|
||||
w.Uint32(x)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Header) Read(r *Reader) error {
|
||||
b := r.BytesAt(0, len(Magic))
|
||||
h.Magic = string(b)
|
||||
if h.Magic != Magic {
|
||||
return errors.New("wrong magic, not a Go object file")
|
||||
}
|
||||
off := uint32(len(h.Magic))
|
||||
h.Flags = r.uint32At(off)
|
||||
off += 4
|
||||
for i := range h.Offsets {
|
||||
h.Offsets[i] = r.uint32At(off)
|
||||
off += 4
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Header) Size() int {
|
||||
return len(h.Magic) + 4 + 4*len(h.Offsets)
|
||||
}
|
||||
|
||||
// Symbol definition.
|
||||
type Sym struct {
|
||||
Name string
|
||||
ABI uint16
|
||||
Type uint8
|
||||
Flag uint8
|
||||
Siz uint32
|
||||
}
|
||||
|
||||
const SymABIstatic = ^uint16(0)
|
||||
|
||||
const (
|
||||
ObjFlagShared = 1 << iota
|
||||
)
|
||||
|
||||
const (
|
||||
SymFlagDupok = 1 << iota
|
||||
SymFlagLocal
|
||||
SymFlagTypelink
|
||||
SymFlagLeaf
|
||||
SymFlagCFunc
|
||||
SymFlagReflectMethod
|
||||
SymFlagGoType
|
||||
SymFlagTopFrame
|
||||
)
|
||||
|
||||
func (s *Sym) Write(w *Writer) {
|
||||
w.StringRef(s.Name)
|
||||
w.Uint16(s.ABI)
|
||||
w.Uint8(s.Type)
|
||||
w.Uint8(s.Flag)
|
||||
w.Uint32(s.Siz)
|
||||
}
|
||||
|
||||
func (s *Sym) Read(r *Reader, off uint32) {
|
||||
s.Name = r.StringRef(off)
|
||||
s.ABI = r.uint16At(off + 4)
|
||||
s.Type = r.uint8At(off + 6)
|
||||
s.Flag = r.uint8At(off + 7)
|
||||
s.Siz = r.uint32At(off + 8)
|
||||
}
|
||||
|
||||
func (s *Sym) Size() int {
|
||||
return 4 + 2 + 1 + 1 + 4
|
||||
}
|
||||
|
||||
func (s *Sym) Dupok() bool { return s.Flag&SymFlagDupok != 0 }
|
||||
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) 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 }
|
||||
|
||||
// Symbol reference.
|
||||
type SymRef struct {
|
||||
PkgIdx uint32
|
||||
SymIdx uint32
|
||||
}
|
||||
|
||||
func (s *SymRef) Write(w *Writer) {
|
||||
w.Uint32(s.PkgIdx)
|
||||
w.Uint32(s.SymIdx)
|
||||
}
|
||||
|
||||
func (s *SymRef) Read(r *Reader, off uint32) {
|
||||
s.PkgIdx = r.uint32At(off)
|
||||
s.SymIdx = r.uint32At(off + 4)
|
||||
}
|
||||
|
||||
func (s *SymRef) Size() int {
|
||||
return 4 + 4
|
||||
}
|
||||
|
||||
// Relocation.
|
||||
type Reloc struct {
|
||||
Off int32
|
||||
Siz uint8
|
||||
Type uint8
|
||||
Add int64
|
||||
Sym SymRef
|
||||
}
|
||||
|
||||
func (r *Reloc) Write(w *Writer) {
|
||||
w.Uint32(uint32(r.Off))
|
||||
w.Uint8(r.Siz)
|
||||
w.Uint8(r.Type)
|
||||
w.Uint64(uint64(r.Add))
|
||||
r.Sym.Write(w)
|
||||
}
|
||||
|
||||
func (o *Reloc) Read(r *Reader, off uint32) {
|
||||
o.Off = r.int32At(off)
|
||||
o.Siz = r.uint8At(off + 4)
|
||||
o.Type = r.uint8At(off + 5)
|
||||
o.Add = r.int64At(off + 6)
|
||||
o.Sym.Read(r, off+14)
|
||||
}
|
||||
|
||||
func (r *Reloc) Size() int {
|
||||
return 4 + 1 + 1 + 8 + r.Sym.Size()
|
||||
}
|
||||
|
||||
// Aux symbol info.
|
||||
type Aux struct {
|
||||
Type uint8
|
||||
Sym SymRef
|
||||
}
|
||||
|
||||
// Aux Type
|
||||
const (
|
||||
AuxGotype = iota
|
||||
AuxFuncInfo
|
||||
AuxFuncdata
|
||||
AuxDwarfInfo
|
||||
AuxDwarfLoc
|
||||
AuxDwarfRanges
|
||||
AuxDwarfLines
|
||||
|
||||
// TODO: more. Pcdata?
|
||||
)
|
||||
|
||||
func (a *Aux) Write(w *Writer) {
|
||||
w.Uint8(a.Type)
|
||||
a.Sym.Write(w)
|
||||
}
|
||||
|
||||
func (a *Aux) Read(r *Reader, off uint32) {
|
||||
a.Type = r.uint8At(off)
|
||||
a.Sym.Read(r, off+1)
|
||||
}
|
||||
|
||||
func (a *Aux) Size() int {
|
||||
return 1 + a.Sym.Size()
|
||||
}
|
||||
|
||||
type Writer struct {
|
||||
wr *bio.Writer
|
||||
stringMap map[string]uint32
|
||||
off uint32 // running offset
|
||||
}
|
||||
|
||||
func NewWriter(wr *bio.Writer) *Writer {
|
||||
return &Writer{wr: wr, stringMap: make(map[string]uint32)}
|
||||
}
|
||||
|
||||
func (w *Writer) AddString(s string) {
|
||||
if _, ok := w.stringMap[s]; ok {
|
||||
return
|
||||
}
|
||||
w.stringMap[s] = w.off
|
||||
w.Uint32(uint32(len(s)))
|
||||
w.RawString(s)
|
||||
}
|
||||
|
||||
func (w *Writer) StringRef(s string) {
|
||||
off, ok := w.stringMap[s]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
|
||||
}
|
||||
w.Uint32(off)
|
||||
}
|
||||
|
||||
func (w *Writer) RawString(s string) {
|
||||
w.wr.WriteString(s)
|
||||
w.off += uint32(len(s))
|
||||
}
|
||||
|
||||
func (w *Writer) Bytes(s []byte) {
|
||||
w.wr.Write(s)
|
||||
w.off += uint32(len(s))
|
||||
}
|
||||
|
||||
func (w *Writer) Uint64(x uint64) {
|
||||
var b [8]byte
|
||||
binary.LittleEndian.PutUint64(b[:], x)
|
||||
w.wr.Write(b[:])
|
||||
w.off += 8
|
||||
}
|
||||
|
||||
func (w *Writer) Uint32(x uint32) {
|
||||
var b [4]byte
|
||||
binary.LittleEndian.PutUint32(b[:], x)
|
||||
w.wr.Write(b[:])
|
||||
w.off += 4
|
||||
}
|
||||
|
||||
func (w *Writer) Uint16(x uint16) {
|
||||
var b [2]byte
|
||||
binary.LittleEndian.PutUint16(b[:], x)
|
||||
w.wr.Write(b[:])
|
||||
w.off += 2
|
||||
}
|
||||
|
||||
func (w *Writer) Uint8(x uint8) {
|
||||
w.wr.WriteByte(x)
|
||||
w.off++
|
||||
}
|
||||
|
||||
func (w *Writer) Offset() uint32 {
|
||||
return w.off
|
||||
}
|
||||
|
||||
type Reader struct {
|
||||
b []byte // mmapped bytes, if not nil
|
||||
readonly bool // whether b is backed with read-only memory
|
||||
|
||||
rd io.ReaderAt
|
||||
start uint32
|
||||
h Header // keep block offsets
|
||||
}
|
||||
|
||||
func NewReaderFromBytes(b []byte, readonly bool) *Reader {
|
||||
r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
|
||||
err := r.h.Read(r)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Reader) BytesAt(off uint32, len int) []byte {
|
||||
if len == 0 {
|
||||
return nil
|
||||
}
|
||||
end := int(off) + len
|
||||
return r.b[int(off):end:end]
|
||||
}
|
||||
|
||||
func (r *Reader) uint64At(off uint32) uint64 {
|
||||
b := r.BytesAt(off, 8)
|
||||
return binary.LittleEndian.Uint64(b)
|
||||
}
|
||||
|
||||
func (r *Reader) int64At(off uint32) int64 {
|
||||
return int64(r.uint64At(off))
|
||||
}
|
||||
|
||||
func (r *Reader) uint32At(off uint32) uint32 {
|
||||
b := r.BytesAt(off, 4)
|
||||
return binary.LittleEndian.Uint32(b)
|
||||
}
|
||||
|
||||
func (r *Reader) int32At(off uint32) int32 {
|
||||
return int32(r.uint32At(off))
|
||||
}
|
||||
|
||||
func (r *Reader) uint16At(off uint32) uint16 {
|
||||
b := r.BytesAt(off, 2)
|
||||
return binary.LittleEndian.Uint16(b)
|
||||
}
|
||||
|
||||
func (r *Reader) uint8At(off uint32) uint8 {
|
||||
b := r.BytesAt(off, 1)
|
||||
return b[0]
|
||||
}
|
||||
|
||||
func (r *Reader) StringAt(off uint32) string {
|
||||
l := r.uint32At(off)
|
||||
b := r.b[off+4 : off+4+l]
|
||||
if r.readonly {
|
||||
return toString(b) // backed by RO memory, ok to make unsafe string
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func toString(b []byte) string {
|
||||
type stringHeader struct {
|
||||
str unsafe.Pointer
|
||||
len int
|
||||
}
|
||||
|
||||
if len(b) == 0 {
|
||||
return ""
|
||||
}
|
||||
ss := stringHeader{str: unsafe.Pointer(&b[0]), len: len(b)}
|
||||
s := *(*string)(unsafe.Pointer(&ss))
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Reader) StringRef(off uint32) string {
|
||||
return r.StringAt(r.uint32At(off))
|
||||
}
|
||||
|
||||
func (r *Reader) Autolib() []string {
|
||||
n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / 4
|
||||
s := make([]string, n)
|
||||
for i := range s {
|
||||
off := r.h.Offsets[BlkAutolib] + uint32(i)*4
|
||||
s[i] = r.StringRef(off)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Reader) Pkglist() []string {
|
||||
n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / 4
|
||||
s := make([]string, n)
|
||||
for i := range s {
|
||||
off := r.h.Offsets[BlkPkgIdx] + uint32(i)*4
|
||||
s[i] = r.StringRef(off)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Reader) NPkg() int {
|
||||
return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / 4
|
||||
}
|
||||
|
||||
func (r *Reader) Pkg(i int) string {
|
||||
off := r.h.Offsets[BlkPkgIdx] + uint32(i)*4
|
||||
return r.StringRef(off)
|
||||
}
|
||||
|
||||
func (r *Reader) NDwarfFile() int {
|
||||
return int(r.h.Offsets[BlkDwarfFile+1]-r.h.Offsets[BlkDwarfFile]) / 4
|
||||
}
|
||||
|
||||
func (r *Reader) DwarfFile(i int) string {
|
||||
off := r.h.Offsets[BlkDwarfFile] + uint32(i)*4
|
||||
return r.StringRef(off)
|
||||
}
|
||||
|
||||
func (r *Reader) NSym() int {
|
||||
symsiz := (&Sym{}).Size()
|
||||
return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / symsiz
|
||||
}
|
||||
|
||||
func (r *Reader) NNonpkgdef() int {
|
||||
symsiz := (&Sym{}).Size()
|
||||
return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / symsiz
|
||||
}
|
||||
|
||||
func (r *Reader) NNonpkgref() int {
|
||||
symsiz := (&Sym{}).Size()
|
||||
return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / symsiz
|
||||
}
|
||||
|
||||
// SymOff returns the offset of the i-th symbol.
|
||||
func (r *Reader) SymOff(i int) uint32 {
|
||||
symsiz := (&Sym{}).Size()
|
||||
return r.h.Offsets[BlkSymdef] + uint32(i*symsiz)
|
||||
}
|
||||
|
||||
// NReloc returns the number of relocations of the i-th symbol.
|
||||
func (r *Reader) NReloc(i int) int {
|
||||
relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
|
||||
return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
|
||||
}
|
||||
|
||||
// RelocOff returns the offset of the j-th relocation of the i-th symbol.
|
||||
func (r *Reader) RelocOff(i int, j int) uint32 {
|
||||
relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
|
||||
relocIdx := r.uint32At(relocIdxOff)
|
||||
relocsiz := (&Reloc{}).Size()
|
||||
return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(relocsiz)
|
||||
}
|
||||
|
||||
// NAux returns the number of aux symbols of the i-th symbol.
|
||||
func (r *Reader) NAux(i int) int {
|
||||
auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
|
||||
return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
|
||||
}
|
||||
|
||||
// AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
|
||||
func (r *Reader) AuxOff(i int, j int) uint32 {
|
||||
auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
|
||||
auxIdx := r.uint32At(auxIdxOff)
|
||||
auxsiz := (&Aux{}).Size()
|
||||
return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(auxsiz)
|
||||
}
|
||||
|
||||
// DataOff returns the offset of the i-th symbol's data.
|
||||
func (r *Reader) DataOff(i int) uint32 {
|
||||
dataIdxOff := r.h.Offsets[BlkDataIdx] + uint32(i*4)
|
||||
return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
|
||||
}
|
||||
|
||||
// DataSize returns the size of the i-th symbol's data.
|
||||
func (r *Reader) DataSize(i int) int {
|
||||
return int(r.DataOff(i+1) - r.DataOff(i))
|
||||
}
|
||||
|
||||
// Data returns the i-th symbol's data.
|
||||
func (r *Reader) Data(i int) []byte {
|
||||
return r.BytesAt(r.DataOff(i), r.DataSize(i))
|
||||
}
|
||||
|
||||
// AuxDataBase returns the base offset of the aux data block.
|
||||
func (r *Reader) PcdataBase() uint32 {
|
||||
return r.h.Offsets[BlkPcdata]
|
||||
}
|
||||
|
||||
// ReadOnly returns whether r.BytesAt returns read-only bytes.
|
||||
func (r *Reader) ReadOnly() bool {
|
||||
return r.readonly
|
||||
}
|
||||
|
||||
// Flags returns the flag bits read from the object file header.
|
||||
func (r *Reader) Flags() uint32 {
|
||||
return r.h.Flags
|
||||
}
|
||||
|
|
@ -388,6 +388,10 @@ type LSym struct {
|
|||
R []Reloc
|
||||
|
||||
Func *FuncInfo
|
||||
|
||||
Pkg string
|
||||
PkgIdx int32
|
||||
SymIdx int32 // TODO: replace RefIdx
|
||||
}
|
||||
|
||||
// A FuncInfo contains extra fields for STEXT symbols.
|
||||
|
|
@ -410,6 +414,8 @@ type FuncInfo struct {
|
|||
GCRegs *LSym
|
||||
StackObjects *LSym
|
||||
OpenCodedDeferInfo *LSym
|
||||
|
||||
FuncInfoSym *LSym
|
||||
}
|
||||
|
||||
type InlMark struct {
|
||||
|
|
@ -461,7 +467,7 @@ const (
|
|||
)
|
||||
|
||||
// Attribute is a set of symbol attributes.
|
||||
type Attribute uint16
|
||||
type Attribute uint32
|
||||
|
||||
const (
|
||||
AttrDuplicateOK Attribute = 1 << iota
|
||||
|
|
@ -502,6 +508,10 @@ const (
|
|||
// keep unwinding beyond this frame.
|
||||
AttrTopFrame
|
||||
|
||||
// Indexed indicates this symbol has been assigned with an index (when using the
|
||||
// new object file format).
|
||||
AttrIndexed
|
||||
|
||||
// attrABIBase is the value at which the ABI is encoded in
|
||||
// Attribute. This must be last; all bits after this are
|
||||
// assumed to be an ABI value.
|
||||
|
|
@ -525,6 +535,7 @@ func (a Attribute) NoFrame() bool { return a&AttrNoFrame != 0 }
|
|||
func (a Attribute) Static() bool { return a&AttrStatic != 0 }
|
||||
func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 }
|
||||
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 }
|
||||
func (a Attribute) Indexed() bool { return a&AttrIndexed != 0 }
|
||||
|
||||
func (a *Attribute) Set(flag Attribute, value bool) {
|
||||
if value {
|
||||
|
|
@ -559,6 +570,7 @@ var textAttrStrings = [...]struct {
|
|||
{bit: AttrStatic, s: "STATIC"},
|
||||
{bit: AttrWasInlined, s: ""},
|
||||
{bit: AttrTopFrame, s: "TOPFRAME"},
|
||||
{bit: AttrIndexed, s: ""},
|
||||
}
|
||||
|
||||
// TextAttrString formats a for printing in as part of a TEXT prog.
|
||||
|
|
@ -637,8 +649,10 @@ type Link struct {
|
|||
Debugpcln string
|
||||
Flag_shared bool
|
||||
Flag_dynlink bool
|
||||
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
|
||||
|
|
@ -672,6 +686,14 @@ type Link struct {
|
|||
// TODO(austin): Replace this with ABI wrappers once the ABIs
|
||||
// actually diverge.
|
||||
ABIAliases []*LSym
|
||||
|
||||
// pkgIdx maps package path to index. The index is used for
|
||||
// symbol reference in the object file.
|
||||
pkgIdx map[string]int32
|
||||
|
||||
defs []*LSym // list of defined symbols in the current package
|
||||
nonpkgdefs []*LSym // list of defined non-package symbols
|
||||
nonpkgrefs []*LSym // list of referenced non-package symbols
|
||||
}
|
||||
|
||||
func (ctxt *Link) Diag(format string, args ...interface{}) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ package obj
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
|
|
@ -80,7 +81,13 @@ func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter {
|
|||
}
|
||||
}
|
||||
|
||||
func WriteObjFile(ctxt *Link, b *bufio.Writer, pkgpath string) {
|
||||
func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
|
||||
if ctxt.Flag_newobj {
|
||||
WriteObjFile2(ctxt, bout, pkgpath)
|
||||
return
|
||||
}
|
||||
|
||||
b := bout.Writer
|
||||
w := newObjWriter(ctxt, b, pkgpath)
|
||||
|
||||
// Magic header
|
||||
|
|
@ -221,8 +228,7 @@ func (w *objWriter) writeRefs(s *LSym) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *objWriter) writeSymDebug(s *LSym) {
|
||||
ctxt := w.ctxt
|
||||
func (ctxt *Link) writeSymDebug(s *LSym) {
|
||||
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
|
||||
if s.Type != 0 {
|
||||
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
|
||||
|
|
@ -302,7 +308,7 @@ func (w *objWriter) writeSymDebug(s *LSym) {
|
|||
func (w *objWriter) writeSym(s *LSym) {
|
||||
ctxt := w.ctxt
|
||||
if ctxt.Debugasm > 0 {
|
||||
w.writeSymDebug(s)
|
||||
w.ctxt.writeSymDebug(s)
|
||||
}
|
||||
|
||||
w.wr.WriteByte(symPrefix)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,429 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Writing Go object files.
|
||||
|
||||
package obj
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/bio"
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/objabi"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Entry point of writing new object file.
|
||||
func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
|
||||
if ctxt.Debugasm > 0 {
|
||||
ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
|
||||
}
|
||||
|
||||
genFuncInfoSyms(ctxt)
|
||||
|
||||
w := writer{
|
||||
Writer: goobj2.NewWriter(b),
|
||||
ctxt: ctxt,
|
||||
pkgpath: objabi.PathToPrefix(pkgpath),
|
||||
}
|
||||
|
||||
start := b.Offset()
|
||||
w.init()
|
||||
|
||||
// Header
|
||||
// We just reserve the space. We'll fill in the offsets later.
|
||||
flags := uint32(0)
|
||||
if ctxt.Flag_shared {
|
||||
flags |= goobj2.ObjFlagShared
|
||||
}
|
||||
h := goobj2.Header{Magic: goobj2.Magic, Flags: flags}
|
||||
h.Write(w.Writer)
|
||||
|
||||
// String table
|
||||
w.StringTable()
|
||||
|
||||
// Autolib
|
||||
h.Offsets[goobj2.BlkAutolib] = w.Offset()
|
||||
for _, pkg := range ctxt.Imports {
|
||||
w.StringRef(pkg)
|
||||
}
|
||||
|
||||
// Package references
|
||||
h.Offsets[goobj2.BlkPkgIdx] = w.Offset()
|
||||
for _, pkg := range w.pkglist {
|
||||
w.StringRef(pkg)
|
||||
}
|
||||
|
||||
// DWARF file table
|
||||
h.Offsets[goobj2.BlkDwarfFile] = w.Offset()
|
||||
for _, f := range ctxt.PosTable.DebugLinesFileTable() {
|
||||
w.StringRef(f)
|
||||
}
|
||||
|
||||
// Symbol definitions
|
||||
h.Offsets[goobj2.BlkSymdef] = w.Offset()
|
||||
for _, s := range ctxt.defs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Non-pkg symbol definitions
|
||||
h.Offsets[goobj2.BlkNonpkgdef] = w.Offset()
|
||||
for _, s := range ctxt.nonpkgdefs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Non-pkg symbol references
|
||||
h.Offsets[goobj2.BlkNonpkgref] = w.Offset()
|
||||
for _, s := range ctxt.nonpkgrefs {
|
||||
w.Sym(s)
|
||||
}
|
||||
|
||||
// Reloc indexes
|
||||
h.Offsets[goobj2.BlkRelocIdx] = w.Offset()
|
||||
nreloc := uint32(0)
|
||||
lists := [][]*LSym{ctxt.defs, ctxt.nonpkgdefs}
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Uint32(nreloc)
|
||||
nreloc += uint32(len(s.R))
|
||||
}
|
||||
}
|
||||
w.Uint32(nreloc)
|
||||
|
||||
// Symbol Info indexes
|
||||
h.Offsets[goobj2.BlkAuxIdx] = w.Offset()
|
||||
naux := uint32(0)
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Uint32(naux)
|
||||
naux += uint32(nAuxSym(s))
|
||||
}
|
||||
}
|
||||
w.Uint32(naux)
|
||||
|
||||
// Data indexes
|
||||
h.Offsets[goobj2.BlkDataIdx] = w.Offset()
|
||||
dataOff := uint32(0)
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Uint32(dataOff)
|
||||
dataOff += uint32(len(s.P))
|
||||
}
|
||||
}
|
||||
w.Uint32(dataOff)
|
||||
|
||||
// Relocs
|
||||
h.Offsets[goobj2.BlkReloc] = w.Offset()
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
for i := range s.R {
|
||||
w.Reloc(&s.R[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Aux symbol info
|
||||
h.Offsets[goobj2.BlkAux] = w.Offset()
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Aux(s)
|
||||
}
|
||||
}
|
||||
|
||||
// Data
|
||||
h.Offsets[goobj2.BlkData] = w.Offset()
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
w.Bytes(s.P)
|
||||
}
|
||||
}
|
||||
|
||||
// Pcdata
|
||||
h.Offsets[goobj2.BlkPcdata] = w.Offset()
|
||||
for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
|
||||
if s.Func != nil {
|
||||
pc := &s.Func.Pcln
|
||||
w.Bytes(pc.Pcsp.P)
|
||||
w.Bytes(pc.Pcfile.P)
|
||||
w.Bytes(pc.Pcline.P)
|
||||
w.Bytes(pc.Pcinline.P)
|
||||
for i := range pc.Pcdata {
|
||||
w.Bytes(pc.Pcdata[i].P)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix up block offsets in the header
|
||||
end := start + int64(w.Offset())
|
||||
b.MustSeek(start, 0)
|
||||
h.Write(w.Writer)
|
||||
b.MustSeek(end, 0)
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
*goobj2.Writer
|
||||
ctxt *Link
|
||||
pkgpath string // the package import path (escaped), "" if unknown
|
||||
pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
|
||||
}
|
||||
|
||||
// prepare package index list
|
||||
func (w *writer) init() {
|
||||
w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
|
||||
w.pkglist[0] = "" // dummy invalid package for index 0
|
||||
for pkg, i := range w.ctxt.pkgIdx {
|
||||
w.pkglist[i] = pkg
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) StringTable() {
|
||||
w.AddString("")
|
||||
for _, pkg := range w.ctxt.Imports {
|
||||
w.AddString(pkg)
|
||||
}
|
||||
for _, pkg := range w.pkglist {
|
||||
w.AddString(pkg)
|
||||
}
|
||||
w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
|
||||
if w.pkgpath != "" {
|
||||
s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
|
||||
}
|
||||
w.AddString(s.Name)
|
||||
})
|
||||
w.ctxt.traverseSyms(traverseDefs, func(s *LSym) {
|
||||
if s.Type != objabi.STEXT {
|
||||
return
|
||||
}
|
||||
pc := &s.Func.Pcln
|
||||
for _, f := range pc.File {
|
||||
w.AddString(filepath.ToSlash(f))
|
||||
}
|
||||
for _, call := range pc.InlTree.nodes {
|
||||
f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
|
||||
w.AddString(filepath.ToSlash(f))
|
||||
}
|
||||
})
|
||||
for _, f := range w.ctxt.PosTable.DebugLinesFileTable() {
|
||||
w.AddString(f)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) Sym(s *LSym) {
|
||||
abi := uint16(s.ABI())
|
||||
if s.Static() {
|
||||
abi = goobj2.SymABIstatic
|
||||
}
|
||||
flag := uint8(0)
|
||||
if s.DuplicateOK() {
|
||||
flag |= goobj2.SymFlagDupok
|
||||
}
|
||||
if s.Local() {
|
||||
flag |= goobj2.SymFlagLocal
|
||||
}
|
||||
if s.MakeTypelink() {
|
||||
flag |= goobj2.SymFlagTypelink
|
||||
}
|
||||
if s.Leaf() {
|
||||
flag |= goobj2.SymFlagLeaf
|
||||
}
|
||||
if s.CFunc() {
|
||||
flag |= goobj2.SymFlagCFunc
|
||||
}
|
||||
if s.ReflectMethod() {
|
||||
flag |= goobj2.SymFlagReflectMethod
|
||||
}
|
||||
if s.TopFrame() {
|
||||
flag |= goobj2.SymFlagTopFrame
|
||||
}
|
||||
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
|
||||
flag |= goobj2.SymFlagGoType
|
||||
}
|
||||
name := s.Name
|
||||
if strings.HasPrefix(name, "gofile..") {
|
||||
name = filepath.ToSlash(name)
|
||||
}
|
||||
o := goobj2.Sym{
|
||||
Name: name,
|
||||
ABI: abi,
|
||||
Type: uint8(s.Type),
|
||||
Flag: flag,
|
||||
Siz: uint32(s.Size),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
|
||||
func makeSymRef(s *LSym) goobj2.SymRef {
|
||||
if s == nil {
|
||||
return goobj2.SymRef{}
|
||||
}
|
||||
if s.PkgIdx == 0 || !s.Indexed() {
|
||||
fmt.Printf("unindexed symbol reference: %v\n", s)
|
||||
panic("unindexed symbol reference")
|
||||
}
|
||||
return goobj2.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
|
||||
}
|
||||
|
||||
func (w *writer) Reloc(r *Reloc) {
|
||||
o := goobj2.Reloc{
|
||||
Off: r.Off,
|
||||
Siz: r.Siz,
|
||||
Type: uint8(r.Type),
|
||||
Add: r.Add,
|
||||
Sym: makeSymRef(r.Sym),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
|
||||
func (w *writer) Aux(s *LSym) {
|
||||
if s.Gotype != nil {
|
||||
o := goobj2.Aux{
|
||||
Type: goobj2.AuxGotype,
|
||||
Sym: makeSymRef(s.Gotype),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
if s.Func != nil {
|
||||
o := goobj2.Aux{
|
||||
Type: goobj2.AuxFuncInfo,
|
||||
Sym: makeSymRef(s.Func.FuncInfoSym),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
|
||||
for _, d := range s.Func.Pcln.Funcdata {
|
||||
o := goobj2.Aux{
|
||||
Type: goobj2.AuxFuncdata,
|
||||
Sym: makeSymRef(d),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
|
||||
if s.Func.dwarfInfoSym != nil {
|
||||
o := goobj2.Aux{
|
||||
Type: goobj2.AuxDwarfInfo,
|
||||
Sym: makeSymRef(s.Func.dwarfInfoSym),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
if s.Func.dwarfLocSym != nil {
|
||||
o := goobj2.Aux{
|
||||
Type: goobj2.AuxDwarfLoc,
|
||||
Sym: makeSymRef(s.Func.dwarfLocSym),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
if s.Func.dwarfRangesSym != nil {
|
||||
o := goobj2.Aux{
|
||||
Type: goobj2.AuxDwarfRanges,
|
||||
Sym: makeSymRef(s.Func.dwarfRangesSym),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
if s.Func.dwarfDebugLinesSym != nil {
|
||||
o := goobj2.Aux{
|
||||
Type: goobj2.AuxDwarfLines,
|
||||
Sym: makeSymRef(s.Func.dwarfDebugLinesSym),
|
||||
}
|
||||
o.Write(w.Writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the number of aux symbols s have.
|
||||
func nAuxSym(s *LSym) int {
|
||||
n := 0
|
||||
if s.Gotype != nil {
|
||||
n++
|
||||
}
|
||||
if s.Func != nil {
|
||||
// FuncInfo is an aux symbol, each Funcdata is an aux symbol
|
||||
n += 1 + len(s.Func.Pcln.Funcdata)
|
||||
if s.Func.dwarfInfoSym != nil {
|
||||
n++
|
||||
}
|
||||
if s.Func.dwarfLocSym != nil {
|
||||
n++
|
||||
}
|
||||
if s.Func.dwarfRangesSym != nil {
|
||||
n++
|
||||
}
|
||||
if s.Func.dwarfDebugLinesSym != nil {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// generate symbols for FuncInfo.
|
||||
func genFuncInfoSyms(ctxt *Link) {
|
||||
infosyms := make([]*LSym, 0, len(ctxt.Text))
|
||||
var pcdataoff uint32
|
||||
var b bytes.Buffer
|
||||
symidx := int32(len(ctxt.defs))
|
||||
for _, s := range ctxt.Text {
|
||||
if s.Func == nil {
|
||||
continue
|
||||
}
|
||||
nosplit := uint8(0)
|
||||
if s.NoSplit() {
|
||||
nosplit = 1
|
||||
}
|
||||
o := goobj2.FuncInfo{
|
||||
NoSplit: nosplit,
|
||||
Args: uint32(s.Func.Args),
|
||||
Locals: uint32(s.Func.Locals),
|
||||
}
|
||||
pc := &s.Func.Pcln
|
||||
o.Pcsp = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcsp.P))
|
||||
o.Pcfile = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcfile.P))
|
||||
o.Pcline = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcline.P))
|
||||
o.Pcinline = pcdataoff
|
||||
pcdataoff += uint32(len(pc.Pcinline.P))
|
||||
o.Pcdata = make([]uint32, len(pc.Pcdata))
|
||||
for i, pcd := range pc.Pcdata {
|
||||
o.Pcdata[i] = pcdataoff
|
||||
pcdataoff += uint32(len(pcd.P))
|
||||
}
|
||||
o.PcdataEnd = pcdataoff
|
||||
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
|
||||
for i, x := range pc.Funcdataoff {
|
||||
o.Funcdataoff[i] = uint32(x)
|
||||
}
|
||||
o.File = make([]goobj2.SymRef, len(pc.File))
|
||||
for i, f := range pc.File {
|
||||
fsym := ctxt.Lookup(f)
|
||||
o.File[i] = makeSymRef(fsym)
|
||||
}
|
||||
o.InlTree = make([]goobj2.InlTreeNode, len(pc.InlTree.nodes))
|
||||
for i, inl := range pc.InlTree.nodes {
|
||||
f, l := linkgetlineFromPos(ctxt, inl.Pos)
|
||||
fsym := ctxt.Lookup(f)
|
||||
o.InlTree[i] = goobj2.InlTreeNode{
|
||||
Parent: int32(inl.Parent),
|
||||
File: makeSymRef(fsym),
|
||||
Line: l,
|
||||
Func: makeSymRef(inl.Func),
|
||||
ParentPC: inl.ParentPC,
|
||||
}
|
||||
}
|
||||
|
||||
o.Write(&b)
|
||||
isym := &LSym{
|
||||
Type: objabi.SDATA, // for now, I don't think it matters
|
||||
PkgIdx: goobj2.PkgIdxSelf,
|
||||
SymIdx: symidx,
|
||||
P: append([]byte(nil), b.Bytes()...),
|
||||
}
|
||||
isym.Set(AttrIndexed, true)
|
||||
symidx++
|
||||
infosyms = append(infosyms, isym)
|
||||
s.Func.FuncInfoSym = isym
|
||||
b.Reset()
|
||||
}
|
||||
ctxt.defs = append(ctxt.defs, infosyms...)
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
|
|||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Addr{}, 32, 48},
|
||||
{LSym{}, 56, 104},
|
||||
{LSym{}, 76, 128},
|
||||
{Prog{}, 132, 200},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,10 +32,12 @@
|
|||
package obj
|
||||
|
||||
import (
|
||||
"cmd/internal/goobj2"
|
||||
"cmd/internal/objabi"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func Linknew(arch *LinkArch) *Link {
|
||||
|
|
@ -78,6 +80,13 @@ func (ctxt *Link) LookupStatic(name string) *LSym {
|
|||
// LookupABI looks up a symbol with the given ABI.
|
||||
// If it does not exist, it creates it.
|
||||
func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
|
||||
return ctxt.LookupABIInit(name, abi, nil)
|
||||
}
|
||||
|
||||
// LookupABI looks up a symbol with the given ABI.
|
||||
// If it does not exist, it creates it and
|
||||
// passes it to init for one-time initialization.
|
||||
func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
|
||||
var hash map[string]*LSym
|
||||
switch abi {
|
||||
case ABI0:
|
||||
|
|
@ -94,6 +103,9 @@ func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
|
|||
s = &LSym{Name: name}
|
||||
s.SetABI(abi)
|
||||
hash[name] = s
|
||||
if init != nil {
|
||||
init(s)
|
||||
}
|
||||
}
|
||||
ctxt.hashmu.Unlock()
|
||||
return s
|
||||
|
|
@ -147,3 +159,167 @@ func (ctxt *Link) Int64Sym(i int64) *LSym {
|
|||
s.Set(AttrLocal, true)
|
||||
})
|
||||
}
|
||||
|
||||
// Assign index to symbols.
|
||||
// asm is set to true if this is called by the assembler (i.e. not the compiler),
|
||||
// in which case all the symbols are non-package (for now).
|
||||
func (ctxt *Link) NumberSyms(asm bool) {
|
||||
if !ctxt.Flag_newobj {
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
ctxt.pkgIdx = make(map[string]int32)
|
||||
ctxt.defs = []*LSym{}
|
||||
ctxt.nonpkgdefs = []*LSym{}
|
||||
|
||||
var idx, nonpkgidx int32 = 0, 0
|
||||
ctxt.traverseSyms(traverseDefs, func(s *LSym) {
|
||||
if isNonPkgSym(ctxt, asm, s) {
|
||||
s.PkgIdx = goobj2.PkgIdxNone
|
||||
s.SymIdx = nonpkgidx
|
||||
if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
|
||||
panic("bad index")
|
||||
}
|
||||
ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
|
||||
nonpkgidx++
|
||||
} else {
|
||||
s.PkgIdx = goobj2.PkgIdxSelf
|
||||
s.SymIdx = idx
|
||||
if idx != int32(len(ctxt.defs)) {
|
||||
panic("bad index")
|
||||
}
|
||||
ctxt.defs = append(ctxt.defs, s)
|
||||
idx++
|
||||
}
|
||||
s.Set(AttrIndexed, true)
|
||||
})
|
||||
|
||||
ipkg := int32(1) // 0 is invalid index
|
||||
nonpkgdef := nonpkgidx
|
||||
ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
|
||||
if rs.PkgIdx != goobj2.PkgIdxInvalid {
|
||||
return
|
||||
}
|
||||
if !ctxt.Flag_linkshared {
|
||||
// Assign special index for builtin symbols.
|
||||
// Don't do it when linking against shared libraries, as the runtime
|
||||
// may be in a different library.
|
||||
if i := goobj2.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
|
||||
rs.PkgIdx = goobj2.PkgIdxBuiltin
|
||||
rs.SymIdx = int32(i)
|
||||
rs.Set(AttrIndexed, true)
|
||||
return
|
||||
}
|
||||
}
|
||||
pkg := rs.Pkg
|
||||
if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
|
||||
rs.PkgIdx = goobj2.PkgIdxNone
|
||||
rs.SymIdx = nonpkgidx
|
||||
rs.Set(AttrIndexed, true)
|
||||
if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
|
||||
panic("bad index")
|
||||
}
|
||||
ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
|
||||
nonpkgidx++
|
||||
return
|
||||
}
|
||||
if k, ok := ctxt.pkgIdx[pkg]; ok {
|
||||
rs.PkgIdx = k
|
||||
return
|
||||
}
|
||||
rs.PkgIdx = ipkg
|
||||
ctxt.pkgIdx[pkg] = ipkg
|
||||
ipkg++
|
||||
})
|
||||
}
|
||||
|
||||
// Returns whether s is a non-package symbol, which needs to be referenced
|
||||
// by name instead of by index.
|
||||
func isNonPkgSym(ctxt *Link, asm bool, s *LSym) bool {
|
||||
if asm && !s.Static() {
|
||||
// asm symbols are referenced by name only, except static symbols
|
||||
// which are file-local and can be referenced by index.
|
||||
return true
|
||||
}
|
||||
if ctxt.Flag_linkshared {
|
||||
// The referenced symbol may be in a different shared library so
|
||||
// the linker cannot see its index.
|
||||
return true
|
||||
}
|
||||
if s.Pkg == "_" {
|
||||
// The frontend uses package "_" to mark symbols that should not
|
||||
// be referenced by index, e.g. linkname'd symbols.
|
||||
return true
|
||||
}
|
||||
if s.DuplicateOK() {
|
||||
// Dupok symbol needs to be dedup'd by name.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type traverseFlag uint32
|
||||
|
||||
const (
|
||||
traverseDefs traverseFlag = 1 << iota
|
||||
traverseRefs
|
||||
traverseAux
|
||||
|
||||
traverseAll = traverseDefs | traverseRefs | traverseAux
|
||||
)
|
||||
|
||||
// Traverse symbols based on flag, call fn for each symbol.
|
||||
func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
|
||||
lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
|
||||
for _, list := range lists {
|
||||
for _, s := range list {
|
||||
if flag&traverseDefs != 0 {
|
||||
fn(s)
|
||||
}
|
||||
if flag&traverseRefs != 0 {
|
||||
for _, r := range s.R {
|
||||
if r.Sym != nil {
|
||||
fn(r.Sym)
|
||||
}
|
||||
}
|
||||
}
|
||||
if flag&traverseAux != 0 {
|
||||
if s.Gotype != nil {
|
||||
fn(s.Gotype)
|
||||
}
|
||||
if s.Type == objabi.STEXT {
|
||||
pc := &s.Func.Pcln
|
||||
for _, d := range pc.Funcdata {
|
||||
if d != nil {
|
||||
fn(d)
|
||||
}
|
||||
}
|
||||
for _, f := range pc.File {
|
||||
if fsym := ctxt.Lookup(f); fsym != nil {
|
||||
fn(fsym)
|
||||
}
|
||||
}
|
||||
for _, call := range pc.InlTree.nodes {
|
||||
if call.Func != nil {
|
||||
fn(call.Func)
|
||||
}
|
||||
f, _ := linkgetlineFromPos(ctxt, call.Pos)
|
||||
if fsym := ctxt.Lookup(f); fsym != nil {
|
||||
fn(fsym)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
|
|||
case objabi.R_ADDRCUOFF:
|
||||
// debug_range and debug_loc elements use this relocation type to get an
|
||||
// offset from the start of the compile unit.
|
||||
o = Symaddr(r.Sym) + r.Add - Symaddr(r.Sym.Unit.Lib.Textp[0])
|
||||
o = Symaddr(r.Sym) + r.Add - Symaddr(r.Sym.Unit.Textp[0])
|
||||
|
||||
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
|
||||
case objabi.R_GOTPCREL:
|
||||
|
|
@ -1086,13 +1086,13 @@ func (p *GCProg) AddSym(s *sym.Symbol) {
|
|||
}
|
||||
|
||||
ptrsize := int64(p.ctxt.Arch.PtrSize)
|
||||
nptr := decodetypePtrdata(p.ctxt.Arch, typ) / ptrsize
|
||||
nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / ptrsize
|
||||
|
||||
if debugGCProg {
|
||||
fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
|
||||
}
|
||||
|
||||
if decodetypeUsegcprog(p.ctxt.Arch, typ) == 0 {
|
||||
if decodetypeUsegcprog(p.ctxt.Arch, typ.P) == 0 {
|
||||
// Copy pointers from mask into program.
|
||||
mask := decodetypeGcmask(p.ctxt, typ)
|
||||
for i := int64(0); i < nptr; i++ {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,15 @@ import (
|
|||
//
|
||||
// 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),
|
||||
|
|
@ -114,22 +123,70 @@ func deadcode(ctxt *Link) {
|
|||
}
|
||||
}
|
||||
|
||||
for _, lib := range ctxt.Library {
|
||||
lib.Textp = lib.Textp[:0]
|
||||
}
|
||||
addToTextp(ctxt)
|
||||
}
|
||||
|
||||
func addToTextp(ctxt *Link) {
|
||||
// Remove dead text but keep file information (z symbols).
|
||||
textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
|
||||
textp := []*sym.Symbol{}
|
||||
for _, s := range ctxt.Textp {
|
||||
if s.Attr.Reachable() {
|
||||
if s.Unit != nil {
|
||||
s.Unit.Lib.Textp = append(s.Unit.Lib.Textp, s)
|
||||
s.Unit.Textp = append(s.Unit.Textp, s)
|
||||
}
|
||||
textp = append(textp, s)
|
||||
}
|
||||
}
|
||||
|
||||
// Put reachable text symbols into Textp.
|
||||
// do it in postorder so that packages are laid down in dependency order
|
||||
// internal first, then everything else
|
||||
ctxt.Library = postorder(ctxt.Library)
|
||||
for _, doInternal := range [2]bool{true, false} {
|
||||
for _, lib := range ctxt.Library {
|
||||
if isRuntimeDepPkg(lib.Pkg) != doInternal {
|
||||
continue
|
||||
}
|
||||
libtextp := lib.Textp[:0]
|
||||
for _, s := range lib.Textp {
|
||||
if s.Attr.Reachable() {
|
||||
textp = append(textp, s)
|
||||
libtextp = append(libtextp, s)
|
||||
if s.Unit != nil {
|
||||
s.Unit.Textp = append(s.Unit.Textp, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s := range lib.DupTextSyms {
|
||||
if s.Attr.Reachable() && !s.Attr.OnList() {
|
||||
textp = append(textp, s)
|
||||
libtextp = append(libtextp, s)
|
||||
if s.Unit != nil {
|
||||
s.Unit.Textp = append(s.Unit.Textp, s)
|
||||
}
|
||||
s.Attr |= sym.AttrOnList
|
||||
// dupok symbols may be defined in multiple packages. its
|
||||
// associated package is chosen sort of arbitrarily (the
|
||||
// first containing package that the linker loads). canonicalize
|
||||
// it here to the package with which it will be laid down
|
||||
// in text.
|
||||
s.File = objabi.PathToPrefix(lib.Pkg)
|
||||
}
|
||||
}
|
||||
lib.Textp = libtextp
|
||||
}
|
||||
}
|
||||
ctxt.Textp = textp
|
||||
|
||||
if len(ctxt.Shlibs) > 0 {
|
||||
// We might have overwritten some functions above (this tends to happen for the
|
||||
// autogenerated type equality/hashing functions) and we don't want to generated
|
||||
// pcln table entries for these any more so remove them from Textp.
|
||||
textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
|
||||
for _, s := range ctxt.Textp {
|
||||
if s.Type != sym.SDYNIMPORT {
|
||||
textp = append(textp, s)
|
||||
}
|
||||
}
|
||||
ctxt.Textp = textp
|
||||
}
|
||||
}
|
||||
|
||||
// methodref holds the relocations from a receiver type symbol to its
|
||||
|
|
@ -274,7 +331,7 @@ func (d *deadcodepass) flood() {
|
|||
// later will give a better error than deadcode.
|
||||
continue
|
||||
}
|
||||
if decodetypeKind(d.ctxt.Arch, s)&kindMask == kindInterface {
|
||||
if decodetypeKind(d.ctxt.Arch, s.P)&kindMask == kindInterface {
|
||||
for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) {
|
||||
if d.ctxt.Debugvlog > 1 {
|
||||
d.ctxt.Logf("reached iface method: %s\n", sig)
|
||||
|
|
|
|||
|
|
@ -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 ld
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
type workQueue []loader.Sym
|
||||
|
||||
// Implement container/heap.Interface.
|
||||
func (q *workQueue) Len() int { return len(*q) }
|
||||
func (q *workQueue) Less(i, j int) bool { return (*q)[i] < (*q)[j] }
|
||||
func (q *workQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
|
||||
func (q *workQueue) Push(i interface{}) { *q = append(*q, i.(loader.Sym)) }
|
||||
func (q *workQueue) Pop() interface{} { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
|
||||
|
||||
// Functions for deadcode pass to use.
|
||||
// Deadcode pass should call push/pop, not Push/Pop.
|
||||
func (q *workQueue) push(i loader.Sym) { heap.Push(q, i) }
|
||||
func (q *workQueue) pop() loader.Sym { return heap.Pop(q).(loader.Sym) }
|
||||
func (q *workQueue) empty() bool { return len(*q) == 0 }
|
||||
|
||||
type deadcodePass2 struct {
|
||||
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
|
||||
reflectSeen bool // whether we have seen a reflect method call
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) init() {
|
||||
d.ldr.InitReachable()
|
||||
d.ifaceMethod = make(map[methodsig]bool)
|
||||
if d.ctxt.Reachparent != nil {
|
||||
d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
|
||||
}
|
||||
heap.Init(&d.wq)
|
||||
|
||||
if d.ctxt.BuildMode == BuildModeShared {
|
||||
// Mark all symbols defined in this library as reachable when
|
||||
// building a shared library.
|
||||
n := d.ldr.NDef()
|
||||
for i := 1; i < n; i++ {
|
||||
s := loader.Sym(i)
|
||||
if !d.ldr.IsDup(s) {
|
||||
d.mark(s, 0)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var names []string
|
||||
|
||||
// In a normal binary, start at main.main and the init
|
||||
// functions and mark what is reachable from there.
|
||||
if d.ctxt.linkShared && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
|
||||
names = append(names, "main.main", "main..inittask")
|
||||
} else {
|
||||
// The external linker refers main symbol directly.
|
||||
if d.ctxt.LinkMode == LinkExternal && (d.ctxt.BuildMode == BuildModeExe || d.ctxt.BuildMode == BuildModePIE) {
|
||||
if d.ctxt.HeadType == objabi.Hwindows && d.ctxt.Arch.Family == sys.I386 {
|
||||
*flagEntrySymbol = "_main"
|
||||
} else {
|
||||
*flagEntrySymbol = "main"
|
||||
}
|
||||
}
|
||||
names = append(names, *flagEntrySymbol)
|
||||
if d.ctxt.BuildMode == BuildModePlugin {
|
||||
names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
|
||||
|
||||
// We don't keep the go.plugin.exports symbol,
|
||||
// but we do keep the symbols it refers to.
|
||||
exportsIdx := d.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynexpMap := d.ctxt.cgo_export_dynamic
|
||||
if d.ctxt.LinkMode == LinkExternal {
|
||||
dynexpMap = d.ctxt.cgo_export_static
|
||||
}
|
||||
for exp := range dynexpMap {
|
||||
names = append(names, exp)
|
||||
}
|
||||
|
||||
// DWARF constant DIE symbols are not referenced, but needed by
|
||||
// the dwarf pass.
|
||||
if !*FlagW {
|
||||
for _, lib := range d.ctxt.Library {
|
||||
names = append(names, dwarf.ConstInfoPrefix+lib.Pkg)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
// Mark symbol as an data/ABI0 symbol.
|
||||
d.mark(d.ldr.Lookup(name, 0), 0)
|
||||
// Also mark any Go functions (internal ABI).
|
||||
d.mark(d.ldr.Lookup(name, sym.SymVerABIInternal), 0)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
relocs := d.ldr.Relocs(symIdx)
|
||||
symRelocs = relocs.ReadAll(symRelocs)
|
||||
|
||||
if d.ldr.IsGoType(symIdx) {
|
||||
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) {
|
||||
if d.ctxt.Debugvlog > 1 {
|
||||
d.ctxt.Logf("reached iface method: %s\n", sig)
|
||||
}
|
||||
d.ifaceMethod[sig] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var methods []methodref2
|
||||
for i := 0; i < relocs.Count; i++ {
|
||||
r := symRelocs[i]
|
||||
if r.Type == objabi.R_WEAKADDROFF {
|
||||
continue
|
||||
}
|
||||
if r.Type == objabi.R_METHODOFF {
|
||||
if i+2 >= relocs.Count {
|
||||
panic("expect three consecutive R_METHODOFF relocs")
|
||||
}
|
||||
methods = append(methods, methodref2{src: symIdx, r: i})
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
if r.Type == 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)
|
||||
}
|
||||
auxSyms = d.ldr.ReadAuxSyms(symIdx, auxSyms)
|
||||
for i := 0; i < len(auxSyms); i++ {
|
||||
d.mark(auxSyms[i], symIdx)
|
||||
}
|
||||
// Some host object symbols have an outer object, which acts like a
|
||||
// "carrier" symbol, or it holds all the symbols for a particular
|
||||
// section. We need to mark all "referenced" symbols from that carrier,
|
||||
// so we make sure we're pulling in all outer symbols, and their sub
|
||||
// symbols. This is not ideal, and these carrier/section symbols could
|
||||
// be removed.
|
||||
d.mark(d.ldr.OuterSym(symIdx), symIdx)
|
||||
d.mark(d.ldr.SubSym(symIdx), symIdx)
|
||||
|
||||
if len(methods) != 0 {
|
||||
// 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)
|
||||
if len(methods) != len(methodsigs) {
|
||||
panic(fmt.Sprintf("%q has %d method relocations for %d methods", d.ldr.SymName(symIdx), len(methods), len(methodsigs)))
|
||||
}
|
||||
for i, m := range methodsigs {
|
||||
methods[i].m = m
|
||||
}
|
||||
d.markableMethods = append(d.markableMethods, methods...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) mark(symIdx, parent loader.Sym) {
|
||||
if symIdx != 0 && !d.ldr.Reachable.Has(symIdx) {
|
||||
d.wq.push(symIdx)
|
||||
d.ldr.Reachable.Set(symIdx)
|
||||
if d.ctxt.Reachparent != nil {
|
||||
d.ldr.Reachparent[symIdx] = parent
|
||||
}
|
||||
if *flagDumpDep {
|
||||
to := d.ldr.SymName(symIdx)
|
||||
if to != "" {
|
||||
from := "_"
|
||||
if parent != 0 {
|
||||
from = d.ldr.SymName(parent)
|
||||
}
|
||||
fmt.Printf("%s -> %s\n", from, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func deadcode2(ctxt *Link) {
|
||||
ldr := ctxt.loader
|
||||
d := deadcodePass2{ctxt: ctxt, ldr: ldr}
|
||||
d.init()
|
||||
d.flood()
|
||||
|
||||
callSym := ldr.Lookup("reflect.Value.Call", sym.SymVerABIInternal)
|
||||
methSym := ldr.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
|
||||
if ctxt.DynlinkingGo() {
|
||||
// Exported methods may satisfy interfaces we don't know
|
||||
// about yet when dynamically linking.
|
||||
d.reflectSeen = true
|
||||
}
|
||||
|
||||
for {
|
||||
// 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))
|
||||
|
||||
// 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.
|
||||
rem := d.markableMethods[:0]
|
||||
for _, m := range d.markableMethods {
|
||||
if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
|
||||
d.markMethod(m)
|
||||
} else {
|
||||
rem = append(rem, m)
|
||||
}
|
||||
}
|
||||
d.markableMethods = rem
|
||||
|
||||
if d.wq.empty() {
|
||||
// No new work was discovered. Done.
|
||||
break
|
||||
}
|
||||
d.flood()
|
||||
}
|
||||
|
||||
n := ldr.NSym()
|
||||
|
||||
if ctxt.BuildMode != BuildModeShared {
|
||||
// Keep a itablink if the symbol it points at is being kept.
|
||||
// (When BuildModeShared, always keep itablinks.)
|
||||
for i := 1; i < n; i++ {
|
||||
s := 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// methodref2 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 methodref2 struct {
|
||||
m methodsig
|
||||
src loader.Sym // receiver type symbol
|
||||
r int // the index of R_METHODOFF relocations
|
||||
}
|
||||
|
||||
func (m methodref2) isExported() bool {
|
||||
for _, r := range m.m {
|
||||
return unicode.IsUpper(r)
|
||||
}
|
||||
panic("methodref has no signature")
|
||||
}
|
||||
|
||||
// decodeMethodSig2 decodes an array of method signature information.
|
||||
// Each element of the array is size bytes. The first 4 bytes is a
|
||||
// nameOff for the method name, and the next 4 bytes is a typeOff for
|
||||
// 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 {
|
||||
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))
|
||||
// FIXME: add some sort of caching here, since we may see some of the
|
||||
// same symbols over time for param types.
|
||||
d.ReadRelocs(mtypSym)
|
||||
mp := ldr.Data(mtypSym)
|
||||
|
||||
buf.WriteRune('(')
|
||||
inCount := decodetypeFuncInCount(arch, mp)
|
||||
for i := 0; i < inCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := d.decodetypeFuncInType2(ldr, arch, mtypSym, d.rtmp, i)
|
||||
buf.WriteString(ldr.SymName(a))
|
||||
}
|
||||
buf.WriteString(") (")
|
||||
outCount := decodetypeFuncOutCount(arch, mp)
|
||||
for i := 0; i < outCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
a := d.decodetypeFuncOutType2(ldr, arch, mtypSym, d.rtmp, i)
|
||||
buf.WriteString(ldr.SymName(a))
|
||||
}
|
||||
buf.WriteRune(')')
|
||||
|
||||
off += size
|
||||
methods = append(methods, methodsig(buf.String()))
|
||||
buf.Reset()
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) decodeIfaceMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []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 {
|
||||
return nil
|
||||
}
|
||||
if rel.Sym != 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
|
||||
numMethods := int(decodetypeIfaceMethodCount(arch, p))
|
||||
sizeofIMethod := 4 + 4
|
||||
return d.decodeMethodSig2(ldr, arch, symIdx, symRelocs, off, sizeofIMethod, numMethods)
|
||||
}
|
||||
|
||||
func (d *deadcodePass2) decodetypeMethods2(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, symRelocs []loader.Reloc) []methodsig {
|
||||
p := ldr.Data(symIdx)
|
||||
if !decodetypeHasUncommon(arch, p) {
|
||||
panic(fmt.Sprintf("no methods on %q", ldr.SymName(symIdx)))
|
||||
}
|
||||
off := commonsize(arch) // reflect.rtype
|
||||
switch decodetypeKind(arch, p) & kindMask {
|
||||
case kindStruct: // reflect.structType
|
||||
off += 4 * arch.PtrSize
|
||||
case kindPtr: // reflect.ptrType
|
||||
off += arch.PtrSize
|
||||
case kindFunc: // reflect.funcType
|
||||
off += arch.PtrSize // 4 bytes, pointer aligned
|
||||
case kindSlice: // reflect.sliceType
|
||||
off += arch.PtrSize
|
||||
case kindArray: // reflect.arrayType
|
||||
off += 3 * arch.PtrSize
|
||||
case kindChan: // reflect.chanType
|
||||
off += 2 * arch.PtrSize
|
||||
case kindMap: // reflect.mapType
|
||||
off += 4*arch.PtrSize + 8
|
||||
case kindInterface: // reflect.interfaceType
|
||||
off += 3 * arch.PtrSize
|
||||
default:
|
||||
// just Sizeof(rtype)
|
||||
}
|
||||
|
||||
mcount := int(decodeInuxi(arch, p[off+4:], 2))
|
||||
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)
|
||||
}
|
||||
|
|
@ -65,28 +65,28 @@ func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize } // ru
|
|||
func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetypeKind(arch *sys.Arch, s *sym.Symbol) uint8 {
|
||||
return s.P[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
|
||||
func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
|
||||
return p[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetypeUsegcprog(arch *sys.Arch, s *sym.Symbol) uint8 {
|
||||
return s.P[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
|
||||
func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
|
||||
return p[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
|
||||
}
|
||||
|
||||
// Type.commonType.size
|
||||
func decodetypeSize(arch *sys.Arch, s *sym.Symbol) int64 {
|
||||
return int64(decodeInuxi(arch, s.P, arch.PtrSize)) // 0x8 / 0x10
|
||||
func decodetypeSize(arch *sys.Arch, p []byte) int64 {
|
||||
return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
|
||||
}
|
||||
|
||||
// Type.commonType.ptrdata
|
||||
func decodetypePtrdata(arch *sys.Arch, s *sym.Symbol) int64 {
|
||||
return int64(decodeInuxi(arch, s.P[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
|
||||
func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
|
||||
return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
|
||||
}
|
||||
|
||||
// Type.commonType.tflag
|
||||
func decodetypeHasUncommon(arch *sys.Arch, s *sym.Symbol) bool {
|
||||
return s.P[2*arch.PtrSize+4]&tflagUncommon != 0
|
||||
func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
|
||||
return p[2*arch.PtrSize+4]&tflagUncommon != 0
|
||||
}
|
||||
|
||||
// Find the elf.Section of a given shared library that contains a given address.
|
||||
|
|
@ -138,7 +138,7 @@ func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
|
|||
func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
|
||||
if s.Type == sym.SDYNIMPORT {
|
||||
addr := decodetypeGcprogShlib(ctxt, s)
|
||||
ptrdata := decodetypePtrdata(ctxt.Arch, s)
|
||||
ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
|
||||
sect := findShlibSection(ctxt, s.File, addr)
|
||||
if sect != nil {
|
||||
r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
|
||||
|
|
@ -181,17 +181,17 @@ func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
|
|||
}
|
||||
|
||||
// Type.FuncType.dotdotdot
|
||||
func decodetypeFuncDotdotdot(arch *sys.Arch, s *sym.Symbol) bool {
|
||||
return uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2))&(1<<15) != 0
|
||||
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
|
||||
return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
|
||||
}
|
||||
|
||||
// Type.FuncType.inCount
|
||||
func decodetypeFuncInCount(arch *sys.Arch, s *sym.Symbol) int {
|
||||
return int(decodeInuxi(arch, s.P[commonsize(arch):], 2))
|
||||
func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
|
||||
return int(decodeInuxi(arch, p[commonsize(arch):], 2))
|
||||
}
|
||||
|
||||
func decodetypeFuncOutCount(arch *sys.Arch, s *sym.Symbol) int {
|
||||
return int(uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2)) & (1<<15 - 1))
|
||||
func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
|
||||
return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
|
||||
}
|
||||
|
||||
func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
|
|
@ -199,14 +199,14 @@ func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
|||
if arch.PtrSize == 8 {
|
||||
uadd += 4
|
||||
}
|
||||
if decodetypeHasUncommon(arch, s) {
|
||||
if decodetypeHasUncommon(arch, s.P) {
|
||||
uadd += uncommonSize()
|
||||
}
|
||||
return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
|
||||
}
|
||||
|
||||
func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
|
||||
return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s))
|
||||
return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
|
||||
}
|
||||
|
||||
// Type.StructType.fields.Slice::length
|
||||
|
|
@ -216,7 +216,7 @@ func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
|
|||
|
||||
func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
|
||||
off := commonsize(arch) + 4*arch.PtrSize
|
||||
if decodetypeHasUncommon(arch, s) {
|
||||
if decodetypeHasUncommon(arch, s.P) {
|
||||
off += uncommonSize()
|
||||
}
|
||||
off += i * structfieldSize(arch)
|
||||
|
|
@ -264,8 +264,8 @@ func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
|
|||
}
|
||||
|
||||
// InterfaceType.methods.length
|
||||
func decodetypeIfaceMethodCount(arch *sys.Arch, s *sym.Symbol) int64 {
|
||||
return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
|
||||
return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
|
||||
}
|
||||
|
||||
// methodsig is a fully qualified typed method signature, like
|
||||
|
|
@ -299,7 +299,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth
|
|||
mtypSym := decodeRelocSym(s, int32(off+4))
|
||||
|
||||
buf.WriteRune('(')
|
||||
inCount := decodetypeFuncInCount(arch, mtypSym)
|
||||
inCount := decodetypeFuncInCount(arch, mtypSym.P)
|
||||
for i := 0; i < inCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
|
|
@ -307,7 +307,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth
|
|||
buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
|
||||
}
|
||||
buf.WriteString(") (")
|
||||
outCount := decodetypeFuncOutCount(arch, mtypSym)
|
||||
outCount := decodetypeFuncOutCount(arch, mtypSym.P)
|
||||
for i := 0; i < outCount; i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
|
|
@ -324,7 +324,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth
|
|||
}
|
||||
|
||||
func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
|
||||
if decodetypeKind(arch, s)&kindMask != kindInterface {
|
||||
if decodetypeKind(arch, s.P)&kindMask != kindInterface {
|
||||
panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
|
||||
}
|
||||
r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
|
||||
|
|
@ -335,17 +335,17 @@ func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
|
|||
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
|
||||
}
|
||||
off := int(r.Add) // array of reflect.imethod values
|
||||
numMethods := int(decodetypeIfaceMethodCount(arch, s))
|
||||
numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
|
||||
sizeofIMethod := 4 + 4
|
||||
return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
|
||||
}
|
||||
|
||||
func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
|
||||
if !decodetypeHasUncommon(arch, s) {
|
||||
if !decodetypeHasUncommon(arch, s.P) {
|
||||
panic(fmt.Sprintf("no methods on %q", s.Name))
|
||||
}
|
||||
off := commonsize(arch) // reflect.rtype
|
||||
switch decodetypeKind(arch, s) & kindMask {
|
||||
switch decodetypeKind(arch, s.P) & kindMask {
|
||||
case kindStruct: // reflect.structType
|
||||
off += 4 * arch.PtrSize
|
||||
case kindPtr: // reflect.ptrType
|
||||
|
|
|
|||
|
|
@ -422,8 +422,8 @@ func defgotype(ctxt *Link, gotype *sym.Symbol) *sym.Symbol {
|
|||
|
||||
func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
|
||||
name := gotype.Name[5:] // could also decode from Type.string
|
||||
kind := decodetypeKind(ctxt.Arch, gotype)
|
||||
bytesize := decodetypeSize(ctxt.Arch, gotype)
|
||||
kind := decodetypeKind(ctxt.Arch, gotype.P)
|
||||
bytesize := decodetypeSize(ctxt.Arch, gotype.P)
|
||||
|
||||
var die, typedefdie *dwarf.DWDie
|
||||
switch kind {
|
||||
|
|
@ -488,17 +488,17 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
|
|||
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
|
||||
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
||||
typedefdie = dotypedef(ctxt, &dwtypes, name, die)
|
||||
nfields := decodetypeFuncInCount(ctxt.Arch, gotype)
|
||||
nfields := decodetypeFuncInCount(ctxt.Arch, gotype.P)
|
||||
for i := 0; i < nfields; i++ {
|
||||
s := decodetypeFuncInType(ctxt.Arch, gotype, i)
|
||||
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
|
||||
newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
|
||||
}
|
||||
|
||||
if decodetypeFuncDotdotdot(ctxt.Arch, gotype) {
|
||||
if decodetypeFuncDotdotdot(ctxt.Arch, gotype.P) {
|
||||
newdie(ctxt, die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
|
||||
}
|
||||
nfields = decodetypeFuncOutCount(ctxt.Arch, gotype)
|
||||
nfields = decodetypeFuncOutCount(ctxt.Arch, gotype.P)
|
||||
for i := 0; i < nfields; i++ {
|
||||
s := decodetypeFuncOutType(ctxt.Arch, gotype, i)
|
||||
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
|
||||
|
|
@ -508,7 +508,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
|
|||
case objabi.KindInterface:
|
||||
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
|
||||
typedefdie = dotypedef(ctxt, &dwtypes, name, die)
|
||||
nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype))
|
||||
nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype.P))
|
||||
var s *sym.Symbol
|
||||
if nfields == 0 {
|
||||
s = lookupOrDiag(ctxt, "type.runtime.eface")
|
||||
|
|
@ -733,7 +733,7 @@ func synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
|
|||
gotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol)
|
||||
keytype := decodetypeMapKey(ctxt.Arch, gotype)
|
||||
valtype := decodetypeMapValue(ctxt.Arch, gotype)
|
||||
keysize, valsize := decodetypeSize(ctxt.Arch, keytype), decodetypeSize(ctxt.Arch, valtype)
|
||||
keysize, valsize := decodetypeSize(ctxt.Arch, keytype.P), decodetypeSize(ctxt.Arch, valtype.P)
|
||||
keytype, valtype = walksymtypedef(ctxt, defgotype(ctxt, keytype)), walksymtypedef(ctxt, defgotype(ctxt, valtype))
|
||||
|
||||
// compute size info like hashmap.c does.
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename s
|
|||
return
|
||||
}
|
||||
p1 += p0
|
||||
|
||||
loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
|
||||
}
|
||||
}
|
||||
|
|
@ -123,6 +122,39 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
|
|||
return
|
||||
}
|
||||
|
||||
// Find cgo_export symbols. They are roots in the deadcode pass.
|
||||
for _, f := range directives {
|
||||
switch f[0] {
|
||||
case "cgo_export_static", "cgo_export_dynamic":
|
||||
if len(f) < 2 || len(f) > 3 {
|
||||
continue
|
||||
}
|
||||
local := f[1]
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
|
||||
if local == "main" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
local = expandpkg(local, pkg)
|
||||
if f[0] == "cgo_export_static" {
|
||||
ctxt.cgo_export_static[local] = true
|
||||
} else {
|
||||
ctxt.cgo_export_dynamic[local] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
for _, f := range directives {
|
||||
switch f[0] {
|
||||
case "cgo_import_dynamic":
|
||||
|
|
@ -164,8 +196,8 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
|
|||
if i := strings.Index(remote, "#"); i >= 0 {
|
||||
remote, q = remote[:i], remote[i+1:]
|
||||
}
|
||||
s := ctxt.Syms.Lookup(local, 0)
|
||||
if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ {
|
||||
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)
|
||||
|
|
@ -183,7 +215,7 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
|
|||
}
|
||||
local := f[1]
|
||||
|
||||
s := ctxt.Syms.Lookup(local, 0)
|
||||
s := lookup(local, 0)
|
||||
s.Type = sym.SHOSTOBJ
|
||||
s.Size = 0
|
||||
continue
|
||||
|
|
@ -204,11 +236,11 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
|
|||
// functions. Link.loadlib will resolve any
|
||||
// ABI aliases we find here (since we may not
|
||||
// yet know it's an alias).
|
||||
s := ctxt.Syms.Lookup(local, 0)
|
||||
s := lookup(local, 0)
|
||||
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
|
||||
if s == ctxt.Syms.Lookup("main", 0) {
|
||||
if s == lookup("main", 0) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
@ -223,7 +255,6 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
|
|||
|
||||
if !s.Attr.CgoExport() {
|
||||
s.SetExtname(remote)
|
||||
dynexp = append(dynexp, s)
|
||||
} 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)
|
||||
nerrors++
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import (
|
|||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loadelf"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/loadmacho"
|
||||
"cmd/link/internal/loadpe"
|
||||
"cmd/link/internal/loadxcoff"
|
||||
|
|
@ -57,6 +58,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
|
@ -378,30 +380,25 @@ func (ctxt *Link) findLibPath(libname string) string {
|
|||
}
|
||||
|
||||
func (ctxt *Link) loadlib() {
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCShared, BuildModePlugin:
|
||||
s := ctxt.Syms.Lookup("runtime.islibrary", 0)
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
s.AddUint8(1)
|
||||
case BuildModeCArchive:
|
||||
s := ctxt.Syms.Lookup("runtime.isarchive", 0)
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
s.AddUint8(1)
|
||||
if *flagNewobj {
|
||||
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)
|
||||
}
|
||||
|
||||
loadinternal(ctxt, "runtime")
|
||||
if ctxt.Arch.Family == sys.ARM {
|
||||
loadinternal(ctxt, "math")
|
||||
}
|
||||
if *flagRace {
|
||||
loadinternal(ctxt, "runtime/race")
|
||||
}
|
||||
if *flagMsan {
|
||||
loadinternal(ctxt, "runtime/msan")
|
||||
}
|
||||
ctxt.cgo_export_static = make(map[string]bool)
|
||||
ctxt.cgo_export_dynamic = make(map[string]bool)
|
||||
|
||||
// ctxt.Library grows during the loop, so not a range loop.
|
||||
for i := 0; i < len(ctxt.Library); i++ {
|
||||
i := 0
|
||||
for ; i < len(ctxt.Library); i++ {
|
||||
lib := ctxt.Library[i]
|
||||
if lib.Shlib == "" {
|
||||
if ctxt.Debugvlog > 1 {
|
||||
|
|
@ -411,34 +408,35 @@ func (ctxt *Link) loadlib() {
|
|||
}
|
||||
}
|
||||
|
||||
for _, lib := range ctxt.Library {
|
||||
if lib.Shlib != "" {
|
||||
if ctxt.Debugvlog > 1 {
|
||||
ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
|
||||
}
|
||||
ldshlibsyms(ctxt, lib.Shlib)
|
||||
// load internal packages, if not already
|
||||
if ctxt.Arch.Family == sys.ARM {
|
||||
loadinternal(ctxt, "math")
|
||||
}
|
||||
if *flagRace {
|
||||
loadinternal(ctxt, "runtime/race")
|
||||
}
|
||||
if *flagMsan {
|
||||
loadinternal(ctxt, "runtime/msan")
|
||||
}
|
||||
loadinternal(ctxt, "runtime")
|
||||
for ; i < len(ctxt.Library); i++ {
|
||||
lib := ctxt.Library[i]
|
||||
if lib.Shlib == "" {
|
||||
loadobjfile(ctxt, lib)
|
||||
}
|
||||
}
|
||||
|
||||
iscgo = ctxt.Syms.ROLookup("x_cgo_init", 0) != nil
|
||||
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
|
||||
}
|
||||
|
||||
// We now have enough information to determine the link mode.
|
||||
determineLinkMode(ctxt)
|
||||
|
||||
// Recalculate pe parameters now that we have ctxt.LinkMode set.
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
Peinit(ctxt)
|
||||
}
|
||||
|
||||
if ctxt.HeadType == objabi.Hdarwin && ctxt.LinkMode == LinkExternal {
|
||||
*FlagTextAddr = 0
|
||||
}
|
||||
|
||||
if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
|
||||
toc := ctxt.Syms.Lookup(".TOC.", 0)
|
||||
toc.Type = sym.SDYNIMPORT
|
||||
}
|
||||
|
||||
if ctxt.LinkMode == LinkExternal && !iscgo && ctxt.LibraryByPkg["runtime/cgo"] == nil && !(objabi.GOOS == "darwin" && (ctxt.Arch.Family == sys.AMD64 || ctxt.Arch.Family == sys.I386)) {
|
||||
// This indicates a user requested -linkmode=external.
|
||||
// The startup code uses an import of runtime/cgo to decide
|
||||
|
|
@ -456,7 +454,29 @@ func (ctxt *Link) loadlib() {
|
|||
}
|
||||
}
|
||||
|
||||
if ctxt.LinkMode == LinkInternal {
|
||||
for _, lib := range ctxt.Library {
|
||||
if lib.Shlib != "" {
|
||||
if ctxt.Debugvlog > 1 {
|
||||
ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
|
||||
}
|
||||
ldshlibsyms(ctxt, lib.Shlib)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -474,6 +494,155 @@ func (ctxt *Link) loadlib() {
|
|||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
if any {
|
||||
if *flagLibGCC == "" {
|
||||
*flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
|
||||
}
|
||||
if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
|
||||
// On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
|
||||
// In this case we fail to load libgcc.a and can encounter link
|
||||
// errors - see if we can find libcompiler_rt.a instead.
|
||||
*flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
|
||||
}
|
||||
if *flagLibGCC != "none" {
|
||||
hostArchive(ctxt, *flagLibGCC)
|
||||
}
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
|
||||
hostArchive(ctxt, p)
|
||||
}
|
||||
if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
|
||||
hostArchive(ctxt, p)
|
||||
}
|
||||
// Link libmsvcrt.a to resolve '__acrt_iob_func' symbol
|
||||
// (see https://golang.org/issue/23649 for details).
|
||||
if p := ctxt.findLibPath("libmsvcrt.a"); p != "none" {
|
||||
hostArchive(ctxt, p)
|
||||
}
|
||||
// TODO: maybe do something similar to peimporteddlls to collect all lib names
|
||||
// and try link them all to final exe just like libmingwex.a and libmingw32.a:
|
||||
/*
|
||||
for:
|
||||
#cgo windows LDFLAGS: -lmsvcrt -lm
|
||||
import:
|
||||
libmsvcrt.a libm.a
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We've loaded all the code now.
|
||||
ctxt.Loaded = true
|
||||
|
||||
importcycles()
|
||||
|
||||
if *flagNewobj {
|
||||
strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
|
||||
}
|
||||
}
|
||||
|
||||
// Set up dynexp list.
|
||||
func setupdynexp(ctxt *Link) {
|
||||
dynexpMap := ctxt.cgo_export_dynamic
|
||||
if ctxt.LinkMode == LinkExternal {
|
||||
dynexpMap = ctxt.cgo_export_static
|
||||
}
|
||||
dynexp = make([]*sym.Symbol, 0, len(dynexpMap))
|
||||
for exp := range dynexpMap {
|
||||
s := ctxt.Syms.Lookup(exp, 0)
|
||||
dynexp = append(dynexp, s)
|
||||
}
|
||||
sort.Sort(byName(dynexp))
|
||||
|
||||
// Resolve ABI aliases in the list of cgo-exported functions.
|
||||
// This is necessary because we load the ABI0 symbol for all
|
||||
// cgo exports.
|
||||
for i, s := range dynexp {
|
||||
if s.Type != sym.SABIALIAS {
|
||||
continue
|
||||
}
|
||||
t := resolveABIAlias(s)
|
||||
t.Attr |= s.Attr
|
||||
t.SetExtname(s.Extname())
|
||||
dynexp[i] = t
|
||||
}
|
||||
|
||||
ctxt.cgo_export_static = nil
|
||||
ctxt.cgo_export_dynamic = nil
|
||||
}
|
||||
|
||||
// Set up flags and special symbols depending on the platform build mode.
|
||||
func (ctxt *Link) linksetup() {
|
||||
switch ctxt.BuildMode {
|
||||
case BuildModeCShared, BuildModePlugin:
|
||||
s := ctxt.Syms.Lookup("runtime.islibrary", 0)
|
||||
s.Type = sym.SNOPTRDATA
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
s.AddUint8(1)
|
||||
case BuildModeCArchive:
|
||||
s := ctxt.Syms.Lookup("runtime.isarchive", 0)
|
||||
s.Type = sym.SNOPTRDATA
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
s.AddUint8(1)
|
||||
}
|
||||
|
||||
// Recalculate pe parameters now that we have ctxt.LinkMode set.
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
Peinit(ctxt)
|
||||
}
|
||||
|
||||
if ctxt.HeadType == objabi.Hdarwin && ctxt.LinkMode == LinkExternal {
|
||||
*FlagTextAddr = 0
|
||||
}
|
||||
|
||||
// If there are no dynamic libraries needed, gcc disables dynamic linking.
|
||||
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
|
||||
// assumes that a dynamic binary always refers to at least one dynamic library.
|
||||
// Rather than be a source of test cases for glibc, disable dynamic linking
|
||||
// the same way that gcc would.
|
||||
//
|
||||
// Exception: on OS X, programs such as Shark only work with dynamic
|
||||
// binaries, so leave it enabled on OS X (Mach-O) binaries.
|
||||
// Also leave it enabled on Solaris which doesn't support
|
||||
// statically linked binaries.
|
||||
if ctxt.BuildMode == BuildModeExe {
|
||||
if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
|
||||
*FlagD = true
|
||||
}
|
||||
}
|
||||
|
||||
if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && objabi.GOOS != "aix" {
|
||||
toc := ctxt.Syms.Lookup(".TOC.", 0)
|
||||
toc.Type = sym.SDYNIMPORT
|
||||
}
|
||||
|
||||
// The Android Q linker started to complain about underalignment of the our TLS
|
||||
// section. We don't actually use the section on android, so dont't
|
||||
// generate it.
|
||||
|
|
@ -534,98 +703,6 @@ func (ctxt *Link) loadlib() {
|
|||
moduledata.Attr |= sym.AttrReachable
|
||||
ctxt.Moduledata = moduledata
|
||||
|
||||
// Now that we know the link mode, trim the dynexp list.
|
||||
x := sym.AttrCgoExportDynamic
|
||||
|
||||
if ctxt.LinkMode == LinkExternal {
|
||||
x = sym.AttrCgoExportStatic
|
||||
}
|
||||
w := 0
|
||||
for i := range dynexp {
|
||||
if dynexp[i].Attr&x != 0 {
|
||||
dynexp[w] = dynexp[i]
|
||||
w++
|
||||
}
|
||||
}
|
||||
dynexp = dynexp[:w]
|
||||
|
||||
// In internal link mode, read the host object files.
|
||||
if ctxt.LinkMode == LinkInternal {
|
||||
hostobjs(ctxt)
|
||||
|
||||
// If we have any undefined symbols in external
|
||||
// objects, try to read them from the libgcc file.
|
||||
any := false
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
for i := range s.R {
|
||||
r := &s.R[i] // Copying sym.Reloc has measurable impact on performance
|
||||
if r.Sym != nil && r.Sym.Type == sym.SXREF && r.Sym.Name != ".got" {
|
||||
any = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if any {
|
||||
if *flagLibGCC == "" {
|
||||
*flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
|
||||
}
|
||||
if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
|
||||
// On OpenBSD `clang --print-libgcc-file-name` returns "libgcc.a".
|
||||
// In this case we fail to load libgcc.a and can encounter link
|
||||
// errors - see if we can find libcompiler_rt.a instead.
|
||||
*flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
|
||||
}
|
||||
if *flagLibGCC != "none" {
|
||||
hostArchive(ctxt, *flagLibGCC)
|
||||
}
|
||||
if ctxt.HeadType == objabi.Hwindows {
|
||||
if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
|
||||
hostArchive(ctxt, p)
|
||||
}
|
||||
if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
|
||||
hostArchive(ctxt, p)
|
||||
}
|
||||
// Link libmsvcrt.a to resolve '__acrt_iob_func' symbol
|
||||
// (see https://golang.org/issue/23649 for details).
|
||||
if p := ctxt.findLibPath("libmsvcrt.a"); p != "none" {
|
||||
hostArchive(ctxt, p)
|
||||
}
|
||||
// TODO: maybe do something similar to peimporteddlls to collect all lib names
|
||||
// and try link them all to final exe just like libmingwex.a and libmingw32.a:
|
||||
/*
|
||||
for:
|
||||
#cgo windows LDFLAGS: -lmsvcrt -lm
|
||||
import:
|
||||
libmsvcrt.a libm.a
|
||||
*/
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hostlinksetup(ctxt)
|
||||
}
|
||||
|
||||
// We've loaded all the code now.
|
||||
ctxt.Loaded = true
|
||||
|
||||
// Record whether we can use plugins.
|
||||
ctxt.canUsePlugins = (ctxt.Syms.ROLookup("plugin.Open", sym.SymVerABIInternal) != nil)
|
||||
|
||||
// If there are no dynamic libraries needed, gcc disables dynamic linking.
|
||||
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
|
||||
// assumes that a dynamic binary always refers to at least one dynamic library.
|
||||
// Rather than be a source of test cases for glibc, disable dynamic linking
|
||||
// the same way that gcc would.
|
||||
//
|
||||
// Exception: on OS X, programs such as Shark only work with dynamic
|
||||
// binaries, so leave it enabled on OS X (Mach-O) binaries.
|
||||
// Also leave it enabled on Solaris which doesn't support
|
||||
// statically linked binaries.
|
||||
if ctxt.BuildMode == BuildModeExe {
|
||||
if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
|
||||
*FlagD = true
|
||||
}
|
||||
}
|
||||
|
||||
// If package versioning is required, generate a hash of the
|
||||
// packages used in the link.
|
||||
if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() {
|
||||
|
|
@ -643,59 +720,6 @@ func (ctxt *Link) loadlib() {
|
|||
got.Attr |= sym.AttrReachable
|
||||
}
|
||||
}
|
||||
|
||||
importcycles()
|
||||
|
||||
// put symbols into Textp
|
||||
// do it in postorder so that packages are laid down in dependency order
|
||||
// internal first, then everything else
|
||||
ctxt.Library = postorder(ctxt.Library)
|
||||
for _, doInternal := range [2]bool{true, false} {
|
||||
for _, lib := range ctxt.Library {
|
||||
if isRuntimeDepPkg(lib.Pkg) != doInternal {
|
||||
continue
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, lib.Textp...)
|
||||
for _, s := range lib.DupTextSyms {
|
||||
if !s.Attr.OnList() {
|
||||
ctxt.Textp = append(ctxt.Textp, s)
|
||||
s.Attr |= sym.AttrOnList
|
||||
// dupok symbols may be defined in multiple packages. its
|
||||
// associated package is chosen sort of arbitrarily (the
|
||||
// first containing package that the linker loads). canonicalize
|
||||
// it here to the package with which it will be laid down
|
||||
// in text.
|
||||
s.File = objabi.PathToPrefix(lib.Pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctxt.Shlibs) > 0 {
|
||||
// We might have overwritten some functions above (this tends to happen for the
|
||||
// autogenerated type equality/hashing functions) and we don't want to generated
|
||||
// pcln table entries for these any more so remove them from Textp.
|
||||
textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
|
||||
for _, s := range ctxt.Textp {
|
||||
if s.Type != sym.SDYNIMPORT {
|
||||
textp = append(textp, s)
|
||||
}
|
||||
}
|
||||
ctxt.Textp = textp
|
||||
}
|
||||
|
||||
// Resolve ABI aliases in the list of cgo-exported functions.
|
||||
// This is necessary because we load the ABI0 symbol for all
|
||||
// cgo exports.
|
||||
for i, s := range dynexp {
|
||||
if s.Type != sym.SABIALIAS {
|
||||
continue
|
||||
}
|
||||
t := resolveABIAlias(s)
|
||||
t.Attr |= s.Attr
|
||||
t.SetExtname(s.Extname())
|
||||
dynexp[i] = t
|
||||
}
|
||||
}
|
||||
|
||||
// mangleTypeSym shortens the names of symbols that represent Go types
|
||||
|
|
@ -991,6 +1015,9 @@ func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), headType obja
|
|||
}
|
||||
|
||||
func hostobjs(ctxt *Link) {
|
||||
if ctxt.LinkMode != LinkInternal {
|
||||
return
|
||||
}
|
||||
var h *Hostobj
|
||||
|
||||
for i := 0; i < len(hostobj); i++ {
|
||||
|
|
@ -1665,55 +1692,107 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
|||
|
||||
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
|
||||
if magic == 0x7f454c46 { // \x7F E L F
|
||||
ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
textp, flags, err := loadelf.Load(ctxt.Arch, ctxt.Syms, f, pkg, length, pn, ehdr.flags)
|
||||
if err != nil {
|
||||
Errorf(nil, "%v", err)
|
||||
return
|
||||
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...)
|
||||
}
|
||||
ehdr.flags = flags
|
||||
ctxt.Textp = append(ctxt.Textp, textp...)
|
||||
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)
|
||||
}
|
||||
return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
}
|
||||
|
||||
if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
|
||||
ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
textp, err := loadmacho.Load(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
|
||||
if err != nil {
|
||||
Errorf(nil, "%v", err)
|
||||
return
|
||||
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...)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, textp...)
|
||||
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)
|
||||
}
|
||||
return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
}
|
||||
|
||||
if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
|
||||
ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
textp, rsrc, err := loadpe.Load(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
|
||||
if err != nil {
|
||||
Errorf(nil, "%v", err)
|
||||
return
|
||||
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...)
|
||||
}
|
||||
if rsrc != nil {
|
||||
setpersrc(ctxt, rsrc)
|
||||
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...)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, textp...)
|
||||
return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
}
|
||||
return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
}
|
||||
|
||||
if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
|
||||
ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
textp, err := loadxcoff.Load(ctxt.Arch, ctxt.Syms, f, pkg, length, pn)
|
||||
if err != nil {
|
||||
Errorf(nil, "%v", err)
|
||||
return
|
||||
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...)
|
||||
}
|
||||
ctxt.Textp = append(ctxt.Textp, textp...)
|
||||
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)
|
||||
}
|
||||
return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
}
|
||||
|
||||
/* check the header */
|
||||
|
|
@ -1809,7 +1888,12 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
|||
default:
|
||||
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
|
||||
}
|
||||
c := objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, unit, eof-f.Offset(), pn, flags)
|
||||
var c int
|
||||
if *flagNewobj {
|
||||
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
|
||||
addImports(ctxt, lib, pn)
|
||||
return nil
|
||||
|
|
@ -1964,7 +2048,17 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
ver = sym.SymVerABIInternal
|
||||
}
|
||||
|
||||
lsym := ctxt.Syms.Lookup(elfsym.Name, ver)
|
||||
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
|
||||
|
|
@ -1993,7 +2087,17 @@ func ldshlibsyms(ctxt *Link, shlib string) {
|
|||
// mangle Go function names in the .so to include the
|
||||
// ABI.
|
||||
if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && ver == 0 {
|
||||
alias := ctxt.Syms.Lookup(elfsym.Name, sym.SymVerABIInternal)
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
|
|
@ -2388,6 +2492,9 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
|
|||
}
|
||||
|
||||
case sym.SHOSTOBJ:
|
||||
if !s.Attr.Reachable() {
|
||||
continue
|
||||
}
|
||||
if ctxt.HeadType == objabi.Hwindows || ctxt.IsELF {
|
||||
put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
|
||||
}
|
||||
|
|
@ -2584,3 +2691,49 @@ func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library
|
|||
mark[lib] = visited
|
||||
*order = append(*order, lib)
|
||||
}
|
||||
|
||||
func (ctxt *Link) loadlibfull() {
|
||||
// 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)
|
||||
}
|
||||
|
||||
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
|
||||
ctxt.cgodata = nil
|
||||
|
||||
addToTextp(ctxt)
|
||||
}
|
||||
|
||||
func (ctxt *Link) dumpsyms() {
|
||||
for _, s := range ctxt.Syms.Allsym {
|
||||
fmt.Printf("%s %s %p %v %v\n", s, s.Type, s, s.Attr.Reachable(), s.Attr.OnList())
|
||||
for i := range s.R {
|
||||
fmt.Println("\t", s.R[i].Type, s.R[i].Sym)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import (
|
|||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
|
|
@ -96,6 +97,18 @@ type Link struct {
|
|||
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
|
||||
|
||||
cgo_export_static map[string]bool
|
||||
cgo_export_dynamic map[string]bool
|
||||
}
|
||||
|
||||
type cgodata struct {
|
||||
file string
|
||||
pkg string
|
||||
directives [][]string
|
||||
}
|
||||
|
||||
type unresolvedSymKey struct {
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ var (
|
|||
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`")
|
||||
|
|
@ -208,8 +209,13 @@ func Main(arch *sys.Arch, theArch Arch) {
|
|||
}
|
||||
ctxt.loadlib()
|
||||
|
||||
ctxt.dostrdata()
|
||||
deadcode(ctxt)
|
||||
if *flagNewobj {
|
||||
ctxt.loadlibfull() // XXX do it here for now
|
||||
}
|
||||
ctxt.linksetup()
|
||||
ctxt.dostrdata()
|
||||
|
||||
dwarfGenerateDebugInfo(ctxt)
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
fieldtrack(ctxt)
|
||||
|
|
|
|||
|
|
@ -305,10 +305,10 @@ func (ctxt *Link) pclntab() {
|
|||
// appears in the Pcfile table. In that case, this assigns
|
||||
// the outer file a number.
|
||||
numberfile(ctxt, call.File)
|
||||
nameoff := nameToOffset(call.Func.Name)
|
||||
nameoff := nameToOffset(call.Func)
|
||||
|
||||
inlTreeSym.SetUint16(ctxt.Arch, int64(i*20+0), uint16(call.Parent))
|
||||
inlTreeSym.SetUint8(ctxt.Arch, int64(i*20+2), uint8(objabi.GetFuncID(call.Func.Name, call.Func.File)))
|
||||
inlTreeSym.SetUint8(ctxt.Arch, int64(i*20+2), uint8(objabi.GetFuncID(call.Func, "")))
|
||||
// byte 3 is unused
|
||||
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+4), uint32(call.File.Value))
|
||||
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+8), uint32(call.Line))
|
||||
|
|
|
|||
|
|
@ -694,7 +694,7 @@ func (ctxt *Link) symtab() {
|
|||
// creating the moduledata from scratch and it does not have a
|
||||
// compiler-provided size, so read it from the type data.
|
||||
moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0)
|
||||
moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype)
|
||||
moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype.P)
|
||||
moduledata.Grow(moduledata.Size)
|
||||
|
||||
lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
|
||||
|
|
|
|||
|
|
@ -88,3 +88,10 @@ func contains(s []string, v string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// implements sort.Interface, for sorting symbols by name.
|
||||
type byName []*sym.Symbol
|
||||
|
||||
func (s byName) Len() int { return len(s) }
|
||||
func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s byName) Less(i, j int) bool { return s[i].Name < s[j].Name }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
|
|
@ -451,7 +452,20 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
|
|||
return found, ehdrFlags, nil
|
||||
}
|
||||
|
||||
// Load loads the ELF file pn from f.
|
||||
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.LookupOrCreate(name, version, syms)
|
||||
}
|
||||
return load(arch, syms.IncVersion(), newSym, newSym, 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.
|
||||
//
|
||||
// On ARM systems, Load will attempt to determine what ELF header flags to
|
||||
|
|
@ -459,12 +473,11 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
|
|||
// 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, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
|
||||
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) {
|
||||
return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
|
||||
}
|
||||
|
||||
localSymVersion := syms.IncVersion()
|
||||
base := f.Offset()
|
||||
|
||||
var hdrbuf [64]uint8
|
||||
|
|
@ -715,7 +728,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
|||
}
|
||||
sectsymNames[name] = true
|
||||
|
||||
s := syms.Lookup(name, localSymVersion)
|
||||
s := lookup(name, localSymVersion)
|
||||
|
||||
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
|
||||
default:
|
||||
|
|
@ -754,7 +767,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
|||
|
||||
for i := 1; i < elfobj.nsymtab; i++ {
|
||||
var elfsym ElfSym
|
||||
if err := readelfsym(arch, syms, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
|
||||
if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
|
||||
return errorf("%s: malformed elf file: %v", pn, err)
|
||||
}
|
||||
symbols[i] = elfsym.sym
|
||||
|
|
@ -925,7 +938,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
|||
rp.Sym = nil
|
||||
} else {
|
||||
var elfsym ElfSym
|
||||
if err := readelfsym(arch, syms, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
|
||||
if err := readelfsym(newSym, lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
|
||||
return errorf("malformed elf file: %v", err)
|
||||
}
|
||||
elfsym.sym = symbols[info>>32]
|
||||
|
|
@ -1002,7 +1015,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
|
||||
func readelfsym(newSym, lookup lookupFunc, 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
|
||||
|
|
@ -1052,7 +1065,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
|
|||
switch elfsym.bind {
|
||||
case ElfSymBindGlobal:
|
||||
if needSym != 0 {
|
||||
s = syms.Lookup(elfsym.name, 0)
|
||||
s = lookup(elfsym.name, 0)
|
||||
|
||||
// for global scoped hidden symbols we should insert it into
|
||||
// symbol hash table, but mark them as hidden.
|
||||
|
|
@ -1077,7 +1090,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
|
|||
// We need to be able to look this up,
|
||||
// so put it in the hash table.
|
||||
if needSym != 0 {
|
||||
s = syms.Lookup(elfsym.name, localSymVersion)
|
||||
s = lookup(elfsym.name, localSymVersion)
|
||||
s.Attr |= sym.AttrVisibilityHidden
|
||||
}
|
||||
|
||||
|
|
@ -1088,14 +1101,14 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
|
|||
// local names and hidden global names are unique
|
||||
// and should only be referenced by their index, not name, so we
|
||||
// don't bother to add them into the hash table
|
||||
s = syms.Newsym(elfsym.name, localSymVersion)
|
||||
s = newSym(elfsym.name, localSymVersion)
|
||||
|
||||
s.Attr |= sym.AttrVisibilityHidden
|
||||
}
|
||||
|
||||
case ElfSymBindWeak:
|
||||
if needSym != 0 {
|
||||
s = syms.Lookup(elfsym.name, 0)
|
||||
s = lookup(elfsym.name, 0)
|
||||
if elfsym.other == 2 {
|
||||
s.Attr |= sym.AttrVisibilityHidden
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -10,6 +10,7 @@ import (
|
|||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
|
@ -423,14 +424,24 @@ func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
// Load loads the Mach-O file pn from f.
|
||||
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.
|
||||
// Symbols are written into syms, and a slice of the text symbols is returned.
|
||||
func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||
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) {
|
||||
return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...))
|
||||
}
|
||||
|
||||
localSymVersion := syms.IncVersion()
|
||||
base := f.Offset()
|
||||
|
||||
var hdr [7 * 4]uint8
|
||||
|
|
@ -562,7 +573,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
|||
continue
|
||||
}
|
||||
name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
|
||||
s := syms.Lookup(name, localSymVersion)
|
||||
s := lookup(name, localSymVersion)
|
||||
if s.Type != 0 {
|
||||
return errorf("duplicate %s/%s", sect.segname, sect.name)
|
||||
}
|
||||
|
|
@ -610,7 +621,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
|
|||
if machsym.type_&N_EXT == 0 {
|
||||
v = localSymVersion
|
||||
}
|
||||
s := syms.Lookup(name, v)
|
||||
s := lookup(name, v)
|
||||
if machsym.type_&N_EXT == 0 {
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"debug/pe"
|
||||
"encoding/binary"
|
||||
|
|
@ -144,12 +145,21 @@ func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
// Load loads the PE file pn from input.
|
||||
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)
|
||||
}
|
||||
return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn)
|
||||
}
|
||||
|
||||
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.
|
||||
// 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, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
|
||||
localSymVersion := syms.IncVersion()
|
||||
|
||||
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)
|
||||
sectdata := make(map[*pe.Section][]byte)
|
||||
|
||||
|
|
@ -181,7 +191,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
|
|||
}
|
||||
|
||||
name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
|
||||
s := syms.Lookup(name, localSymVersion)
|
||||
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
|
||||
|
|
@ -239,7 +249,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
|
|||
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))
|
||||
}
|
||||
pesym := &f.COFFSymbols[r.SymbolTableIndex]
|
||||
gosym, err := readpesym(arch, syms, f, pesym, sectsyms, localSymVersion)
|
||||
gosym, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -351,7 +361,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
|
|||
}
|
||||
}
|
||||
|
||||
s, err := readpesym(arch, syms, f, pesym, sectsyms, localSymVersion)
|
||||
s, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -435,7 +445,7 @@ func issect(s *pe.COFFSymbol) bool {
|
|||
return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
|
||||
}
|
||||
|
||||
func readpesym(arch *sys.Arch, syms *sym.Symbols, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
|
||||
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) {
|
||||
symname, err := pesym.FullName(f.StringTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -481,10 +491,10 @@ func readpesym(arch *sys.Arch, syms *sym.Symbols, f *pe.File, pesym *pe.COFFSymb
|
|||
case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
|
||||
switch pesym.StorageClass {
|
||||
case IMAGE_SYM_CLASS_EXTERNAL: //global
|
||||
s = syms.Lookup(name, 0)
|
||||
s = lookup(name, 0)
|
||||
|
||||
case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
|
||||
s = syms.Lookup(name, localSymVersion)
|
||||
s = lookup(name, localSymVersion)
|
||||
s.Attr |= sym.AttrDuplicateOK
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"cmd/internal/bio"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/loader"
|
||||
"cmd/link/internal/sym"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -38,13 +39,25 @@ func (f *xcoffBiobuf) ReadAt(p []byte, off int64) (int, error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
// Load loads the Xcoff file pn from f.
|
||||
// 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, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
|
||||
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) {
|
||||
return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...))
|
||||
}
|
||||
localSymVersion := syms.IncVersion()
|
||||
|
||||
var ldSections []*ldSection
|
||||
|
||||
|
|
@ -62,7 +75,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
|
|||
lds := new(ldSection)
|
||||
lds.Section = *sect
|
||||
name := fmt.Sprintf("%s(%s)", pkg, lds.Name)
|
||||
s := syms.Lookup(name, localSymVersion)
|
||||
s := lookup(name, localSymVersion)
|
||||
|
||||
switch lds.Type {
|
||||
default:
|
||||
|
|
@ -100,7 +113,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
|
|||
continue
|
||||
}
|
||||
|
||||
s := syms.Lookup(sx.Name, 0)
|
||||
s := lookup(sx.Name, 0)
|
||||
|
||||
// Text symbol
|
||||
if s.Type == sym.STEXT {
|
||||
|
|
@ -122,7 +135,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
|
|||
for i, rx := range sect.Relocs {
|
||||
r := &rs[i]
|
||||
|
||||
r.Sym = syms.Lookup(rx.Symbol.Name, 0)
|
||||
r.Sym = lookup(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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ overwrite:
|
|||
pc.InlTree[i].Parent = r.readInt32()
|
||||
pc.InlTree[i].File = r.readSymIndex()
|
||||
pc.InlTree[i].Line = r.readInt32()
|
||||
pc.InlTree[i].Func = r.readSymIndex()
|
||||
pc.InlTree[i].Func = r.readSymIndex().Name
|
||||
pc.InlTree[i].ParentPC = r.readInt32()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -550,7 +550,7 @@ func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
|
|||
const prefix = "TOC."
|
||||
var tarSym *sym.Symbol
|
||||
if strings.HasPrefix(r.Sym.Name, prefix) {
|
||||
tarSym = ctxt.Syms.ROLookup(strings.TrimPrefix(r.Sym.Name, prefix), 0)
|
||||
tarSym = r.Sym.R[0].Sym
|
||||
} else {
|
||||
ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@ type InlinedCall struct {
|
|||
Parent int32 // index of parent in InlTree
|
||||
File *Symbol // file of the inlined call
|
||||
Line int32 // line number of the inlined call
|
||||
Func *Symbol // function that was inlined
|
||||
Func string // name of the function that was inlined
|
||||
ParentPC int32 // PC of the instruction just before the inlined body (offset from function start)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,17 @@ 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))
|
||||
|
|
|
|||
|
|
@ -161,3 +161,8 @@ var RelROMap = map[SymKind]SymKind{
|
|||
SRODATA: SRODATARELRO,
|
||||
SFUNCTAB: SFUNCTABRELRO,
|
||||
}
|
||||
|
||||
// IsData returns true if the type is a data type.
|
||||
func (t SymKind) IsData() bool {
|
||||
return t == SDATA || t == SNOPTRDATA || t == SBSS || t == SNOPTRBSS
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,3 +376,68 @@ func TestIssue34788Android386TLSSequence(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const testStrictDupGoSrc = `
|
||||
package main
|
||||
func f()
|
||||
func main() { f() }
|
||||
`
|
||||
|
||||
const testStrictDupAsmSrc1 = `
|
||||
#include "textflag.h"
|
||||
TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
|
||||
RET
|
||||
`
|
||||
|
||||
const testStrictDupAsmSrc2 = `
|
||||
#include "textflag.h"
|
||||
TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
|
||||
JMP 0(PC)
|
||||
`
|
||||
|
||||
func TestStrictDup(t *testing.T) {
|
||||
// Check that -strictdups flag works.
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestStrictDup")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
src := filepath.Join(tmpdir, "x.go")
|
||||
err = ioutil.WriteFile(src, []byte(testStrictDupGoSrc), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src = filepath.Join(tmpdir, "a.s")
|
||||
err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src = filepath.Join(tmpdir, "b.s")
|
||||
err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=1")
|
||||
cmd.Dir = tmpdir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("linking with -strictdups=1 failed: %v", err)
|
||||
}
|
||||
if !bytes.Contains(out, []byte("mismatched payload")) {
|
||||
t.Errorf("unexpected output:\n%s", out)
|
||||
}
|
||||
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=2")
|
||||
cmd.Dir = tmpdir
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Errorf("linking with -strictdups=2 did not fail")
|
||||
}
|
||||
if !bytes.Contains(out, []byte("mismatched payload")) {
|
||||
t.Errorf("unexpected output:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ TEXT runtime∕internal∕atomic·Cas(SB),NOSPLIT|NOFRAME,$0
|
|||
CMP $7, R11
|
||||
BLT 2(PC)
|
||||
JMP ·armcas(SB)
|
||||
JMP ·kernelcas<>(SB)
|
||||
JMP kernelcas<>(SB)
|
||||
|
||||
TEXT runtime∕internal∕atomic·kernelcas<>(SB),NOSPLIT,$0
|
||||
TEXT kernelcas<>(SB),NOSPLIT,$0
|
||||
MOVW ptr+0(FP), R2
|
||||
// trigger potential paging fault here,
|
||||
// because we don't know how to traceback through __kuser_cmpxchg
|
||||
|
|
|
|||
|
|
@ -29,4 +29,10 @@ func main() {
|
|||
fmt.Println(overwrite)
|
||||
fmt.Println(overwritecopy)
|
||||
fmt.Println(arraycopy[1])
|
||||
|
||||
// Check non-string symbols are not overwritten.
|
||||
// This also make them used.
|
||||
if b || x != 0 {
|
||||
panic("b or x overwritten")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue