Commit bbae923d authored by Cherry Zhang's avatar Cherry Zhang

cmd: merge branch 'dev.link' into master

In the dev.link branch we implemented the new object file format
and (part of) the linker improvements described in
https://golang.org/s/better-linker

The new object file is index-based and provides random access.
The linker maps the object files into read-only memory, and
access symbols on-demand using indices, as opposed to reading
all object files sequentially into the heap with the old format.

The linker carries symbol informations using indices (as opposed
to Symbol data structure). Symbols are created after the
reachability analysis, and only created for reachable symbols.
This reduces the linker's memory usage.

Linking cmd/compile, it creates ~25% fewer Symbols, and reduces
memory usage (inuse_space) by ~15%. (More results from Than.)

Currently, both the old and new object file formats are supported.
The old format is used by default. The new format can be turned
on by using the compiler/assembler/linker's -newobj flag. Note
that the flag needs to be specified consistently to all
compilations, i.e.

go build -gcflags=all=-newobj -asmflags=all=-newobj -ldflags=-newobj

Change-Id: Ia0e35306b5b9b5b19fdc7fa7c602d4ce36fa6abd
parents 7e71c9c3 9cf6c65c
...@@ -23,6 +23,7 @@ var ( ...@@ -23,6 +23,7 @@ var (
Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries") 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") 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") 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 ( var (
......
...@@ -40,18 +40,18 @@ func main() { ...@@ -40,18 +40,18 @@ func main() {
} }
ctxt.Flag_dynlink = *flags.Dynlink ctxt.Flag_dynlink = *flags.Dynlink
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
ctxt.Flag_newobj = *flags.Newobj
ctxt.Bso = bufio.NewWriter(os.Stdout) ctxt.Bso = bufio.NewWriter(os.Stdout)
defer ctxt.Bso.Flush() defer ctxt.Bso.Flush()
architecture.Init(ctxt) architecture.Init(ctxt)
// Create object file, write header. // Create object file, write header.
out, err := os.Create(*flags.OutputFile) buf, err := bio.Create(*flags.OutputFile)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer bio.MustClose(out) defer buf.Close()
buf := bufio.NewWriter(bio.MustWriter(out))
if !*flags.SymABIs { if !*flags.SymABIs {
fmt.Fprintf(buf, "go object %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version) fmt.Fprintf(buf, "go object %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version)
...@@ -83,6 +83,7 @@ func main() { ...@@ -83,6 +83,7 @@ func main() {
} }
} }
if ok && !*flags.SymABIs { if ok && !*flags.SymABIs {
ctxt.NumberSyms(true)
obj.WriteObjFile(ctxt, buf, "") obj.WriteObjFile(ctxt, buf, "")
} }
if !ok || diag { if !ok || diag {
...@@ -91,9 +92,8 @@ func main() { ...@@ -91,9 +92,8 @@ func main() {
} else { } else {
log.Print("assembly failed") log.Print("assembly failed")
} }
out.Close() buf.Close()
os.Remove(*flags.OutputFile) os.Remove(*flags.OutputFile)
os.Exit(1) os.Exit(1)
} }
buf.Flush()
} }
...@@ -203,6 +203,7 @@ import ( ...@@ -203,6 +203,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/goobj2"
"cmd/internal/src" "cmd/internal/src"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
...@@ -945,10 +946,12 @@ func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } ...@@ -945,10 +946,12 @@ func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
func (w *exportWriter) varExt(n *Node) { func (w *exportWriter) varExt(n *Node) {
w.linkname(n.Sym) w.linkname(n.Sym)
w.symIdx(n.Sym)
} }
func (w *exportWriter) funcExt(n *Node) { func (w *exportWriter) funcExt(n *Node) {
w.linkname(n.Sym) w.linkname(n.Sym)
w.symIdx(n.Sym)
// Escape analysis. // Escape analysis.
for _, fs := range types.RecvsParams { for _, fs := range types.RecvsParams {
...@@ -987,6 +990,22 @@ func (w *exportWriter) linkname(s *types.Sym) { ...@@ -987,6 +990,22 @@ func (w *exportWriter) linkname(s *types.Sym) {
w.string(s.Linkname) 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. // Inline bodies.
func (w *exportWriter) stmtList(list Nodes) { func (w *exportWriter) stmtList(list Nodes) {
......
...@@ -10,6 +10,7 @@ package gc ...@@ -10,6 +10,7 @@ package gc
import ( import (
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
...@@ -651,10 +652,12 @@ func (r *importReader) byte() byte { ...@@ -651,10 +652,12 @@ func (r *importReader) byte() byte {
func (r *importReader) varExt(n *Node) { func (r *importReader) varExt(n *Node) {
r.linkname(n.Sym) r.linkname(n.Sym)
r.symIdx(n.Sym)
} }
func (r *importReader) funcExt(n *Node) { func (r *importReader) funcExt(n *Node) {
r.linkname(n.Sym) r.linkname(n.Sym)
r.symIdx(n.Sym)
// Escape analysis. // Escape analysis.
for _, fs := range types.RecvsParams { for _, fs := range types.RecvsParams {
...@@ -683,6 +686,20 @@ func (r *importReader) linkname(s *types.Sym) { ...@@ -683,6 +686,20 @@ func (r *importReader) linkname(s *types.Sym) {
s.Linkname = r.string() 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) { func (r *importReader) doInline(n *Node) {
if len(n.Func.Inl.Body) != 0 { if len(n.Func.Inl.Body) != 0 {
Fatalf("%v already has inline body", n) Fatalf("%v already has inline body", n)
......
...@@ -260,6 +260,7 @@ func Main(archInit func(*Arch)) { ...@@ -260,6 +260,7 @@ func Main(archInit func(*Arch)) {
if supportsDynlink(thearch.LinkArch.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_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(&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(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`") flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
...@@ -274,12 +275,14 @@ func Main(archInit func(*Arch)) { ...@@ -274,12 +275,14 @@ func Main(archInit func(*Arch)) {
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`") flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects") 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.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) objabi.Flagparse(usage)
// Record flags that affect the build result. (And don't // Record flags that affect the build result. (And don't
// record flags that don't, since that would cause spurious // record flags that don't, since that would cause spurious
// changes in the binary.) // 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 { if smallFrames {
maxStackVarSize = 128 * 1024 maxStackVarSize = 128 * 1024
...@@ -746,6 +749,8 @@ func Main(archInit func(*Arch)) { ...@@ -746,6 +749,8 @@ func Main(archInit func(*Arch)) {
// Write object data to disk. // Write object data to disk.
timings.Start("be", "dumpobj") timings.Start("be", "dumpobj")
dumpdata()
Ctxt.NumberSyms(false)
dumpobj() dumpobj()
if asmhdr != "" { if asmhdr != "" {
dumpasmhdr() dumpasmhdr()
......
...@@ -111,21 +111,7 @@ func dumpCompilerObj(bout *bio.Writer) { ...@@ -111,21 +111,7 @@ func dumpCompilerObj(bout *bio.Writer) {
dumpexport(bout) dumpexport(bout)
} }
func dumpLinkerObj(bout *bio.Writer) { func dumpdata() {
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")
externs := len(externdcl) externs := len(externdcl)
dumpglobls() dumpglobls()
...@@ -163,8 +149,24 @@ func dumpLinkerObj(bout *bio.Writer) { ...@@ -163,8 +149,24 @@ func dumpLinkerObj(bout *bio.Writer) {
} }
addGCLocals() addGCLocals()
}
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.Writer, myimportpath) obj.WriteObjFile(Ctxt, bout, myimportpath)
} }
func addptabs() { func addptabs() {
......
...@@ -80,11 +80,18 @@ func (sym *Sym) Linksym() *obj.LSym { ...@@ -80,11 +80,18 @@ func (sym *Sym) Linksym() *obj.LSym {
if sym == nil { if sym == nil {
return nil return nil
} }
initPkg := func(r *obj.LSym) {
if sym.Linkname != "" {
r.Pkg = "_"
} else {
r.Pkg = sym.Pkg.Prefix
}
}
if sym.Func() { if sym.Func() {
// This is a function symbol. Mark it as "internal ABI". // 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. // Less reports whether symbol a is ordered before symbol b.
......
...@@ -54,6 +54,7 @@ var bootstrapDirs = []string{ ...@@ -54,6 +54,7 @@ var bootstrapDirs = []string{
"cmd/internal/gcprog", "cmd/internal/gcprog",
"cmd/internal/dwarf", "cmd/internal/dwarf",
"cmd/internal/edit", "cmd/internal/edit",
"cmd/internal/goobj2",
"cmd/internal/objabi", "cmd/internal/objabi",
"cmd/internal/obj", "cmd/internal/obj",
"cmd/internal/obj/arm", "cmd/internal/obj/arm",
...@@ -72,6 +73,7 @@ var bootstrapDirs = []string{ ...@@ -72,6 +73,7 @@ var bootstrapDirs = []string{
"cmd/link/internal/arm64", "cmd/link/internal/arm64",
"cmd/link/internal/ld", "cmd/link/internal/ld",
"cmd/link/internal/loadelf", "cmd/link/internal/loadelf",
"cmd/link/internal/loader",
"cmd/link/internal/loadmacho", "cmd/link/internal/loadmacho",
"cmd/link/internal/loadpe", "cmd/link/internal/loadpe",
"cmd/link/internal/loadxcoff", "cmd/link/internal/loadxcoff",
......
...@@ -585,7 +585,7 @@ func (t *tester) registerTests() { ...@@ -585,7 +585,7 @@ func (t *tester) registerTests() {
}, },
}) })
// Also test a cgo package. // Also test a cgo package.
if t.cgoEnabled { if t.cgoEnabled && t.internalLink() {
t.tests = append(t.tests, distTest{ t.tests = append(t.tests, distTest{
name: "pie_internal_cgo", name: "pie_internal_cgo",
heading: "internal linking of -buildmode=pie", heading: "internal linking of -buildmode=pie",
......
...@@ -145,8 +145,8 @@ ...@@ -145,8 +145,8 @@
// -ldflags '[pattern=]arg list' // -ldflags '[pattern=]arg list'
// arguments to pass on each go tool link invocation. // arguments to pass on each go tool link invocation.
// -linkshared // -linkshared
// link against shared libraries previously created with // build code that will be linked against shared libraries previously
// -buildmode=shared. // created with -buildmode=shared.
// -mod mode // -mod mode
// module download mode to use: readonly or vendor. // module download mode to use: readonly or vendor.
// See 'go help modules' for more. // See 'go help modules' for more.
......
...@@ -97,8 +97,8 @@ and test commands: ...@@ -97,8 +97,8 @@ and test commands:
-ldflags '[pattern=]arg list' -ldflags '[pattern=]arg list'
arguments to pass on each go tool link invocation. arguments to pass on each go tool link invocation.
-linkshared -linkshared
link against shared libraries previously created with build code that will be linked against shared libraries previously
-buildmode=shared. created with -buildmode=shared.
-mod mode -mod mode
module download mode to use: readonly or vendor. module download mode to use: readonly or vendor.
See 'go help modules' for more. See 'go help modules' for more.
......
...@@ -224,6 +224,7 @@ func buildModeInit() { ...@@ -224,6 +224,7 @@ func buildModeInit() {
base.Fatalf("-linkshared not supported on %s\n", platform) base.Fatalf("-linkshared not supported on %s\n", platform)
} }
codegenArg = "-dynlink" codegenArg = "-dynlink"
forcedGcflags = append(forcedGcflags, "-linkshared")
// TODO(mwhudson): remove -w when that gets fixed in linker. // TODO(mwhudson): remove -w when that gets fixed in linker.
forcedLdflags = append(forcedLdflags, "-linkshared", "-w") forcedLdflags = append(forcedLdflags, "-linkshared", "-w")
} }
......
...@@ -1372,7 +1372,13 @@ func PutDefaultFunc(ctxt Context, s *FnState) error { ...@@ -1372,7 +1372,13 @@ func PutDefaultFunc(ctxt Context, s *FnState) error {
abbrev := DW_ABRV_FUNCTION abbrev := DW_ABRV_FUNCTION
Uleb128put(ctxt, s.Info, int64(abbrev)) 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, 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_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}) 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 { ...@@ -502,6 +502,14 @@ func (r *objReader) parseObject(prefix []byte) error {
} }
// TODO: extract OS + build ID if/when we need it // 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]) r.readFull(r.tmp[:8])
if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) { if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) {
return r.error(errCorruptObject) return r.error(errCorruptObject)
......
// 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),
}
}
}
}
// 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
}
}
// 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},
}
// 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
}
// 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
}
This diff is collapsed.
...@@ -388,6 +388,10 @@ type LSym struct { ...@@ -388,6 +388,10 @@ type LSym struct {
R []Reloc R []Reloc
Func *FuncInfo Func *FuncInfo
Pkg string
PkgIdx int32
SymIdx int32 // TODO: replace RefIdx
} }
// A FuncInfo contains extra fields for STEXT symbols. // A FuncInfo contains extra fields for STEXT symbols.
...@@ -410,6 +414,8 @@ type FuncInfo struct { ...@@ -410,6 +414,8 @@ type FuncInfo struct {
GCRegs *LSym GCRegs *LSym
StackObjects *LSym StackObjects *LSym
OpenCodedDeferInfo *LSym OpenCodedDeferInfo *LSym
FuncInfoSym *LSym
} }
type InlMark struct { type InlMark struct {
...@@ -461,7 +467,7 @@ const ( ...@@ -461,7 +467,7 @@ const (
) )
// Attribute is a set of symbol attributes. // Attribute is a set of symbol attributes.
type Attribute uint16 type Attribute uint32
const ( const (
AttrDuplicateOK Attribute = 1 << iota AttrDuplicateOK Attribute = 1 << iota
...@@ -502,6 +508,10 @@ const ( ...@@ -502,6 +508,10 @@ const (
// keep unwinding beyond this frame. // keep unwinding beyond this frame.
AttrTopFrame 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 // attrABIBase is the value at which the ABI is encoded in
// Attribute. This must be last; all bits after this are // Attribute. This must be last; all bits after this are
// assumed to be an ABI value. // assumed to be an ABI value.
...@@ -525,6 +535,7 @@ func (a Attribute) NoFrame() bool { return a&AttrNoFrame != 0 } ...@@ -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) Static() bool { return a&AttrStatic != 0 }
func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 } func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 }
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 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) { func (a *Attribute) Set(flag Attribute, value bool) {
if value { if value {
...@@ -559,6 +570,7 @@ var textAttrStrings = [...]struct { ...@@ -559,6 +570,7 @@ var textAttrStrings = [...]struct {
{bit: AttrStatic, s: "STATIC"}, {bit: AttrStatic, s: "STATIC"},
{bit: AttrWasInlined, s: ""}, {bit: AttrWasInlined, s: ""},
{bit: AttrTopFrame, s: "TOPFRAME"}, {bit: AttrTopFrame, s: "TOPFRAME"},
{bit: AttrIndexed, s: ""},
} }
// TextAttrString formats a for printing in as part of a TEXT prog. // TextAttrString formats a for printing in as part of a TEXT prog.
...@@ -637,8 +649,10 @@ type Link struct { ...@@ -637,8 +649,10 @@ type Link struct {
Debugpcln string Debugpcln string
Flag_shared bool Flag_shared bool
Flag_dynlink bool Flag_dynlink bool
Flag_linkshared bool
Flag_optimize bool Flag_optimize bool
Flag_locationlists bool Flag_locationlists bool
Flag_newobj bool // use new object file format
Bso *bufio.Writer Bso *bufio.Writer
Pathname string Pathname string
hashmu sync.Mutex // protects hash, funchash hashmu sync.Mutex // protects hash, funchash
...@@ -672,6 +686,14 @@ type Link struct { ...@@ -672,6 +686,14 @@ type Link struct {
// TODO(austin): Replace this with ABI wrappers once the ABIs // TODO(austin): Replace this with ABI wrappers once the ABIs
// actually diverge. // actually diverge.
ABIAliases []*LSym 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{}) { func (ctxt *Link) Diag(format string, args ...interface{}) {
......
...@@ -8,6 +8,7 @@ package obj ...@@ -8,6 +8,7 @@ package obj
import ( import (
"bufio" "bufio"
"cmd/internal/bio"
"cmd/internal/dwarf" "cmd/internal/dwarf"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
...@@ -80,7 +81,13 @@ func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter { ...@@ -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) w := newObjWriter(ctxt, b, pkgpath)
// Magic header // Magic header
...@@ -221,8 +228,7 @@ func (w *objWriter) writeRefs(s *LSym) { ...@@ -221,8 +228,7 @@ func (w *objWriter) writeRefs(s *LSym) {
} }
} }
func (w *objWriter) writeSymDebug(s *LSym) { func (ctxt *Link) writeSymDebug(s *LSym) {
ctxt := w.ctxt
fmt.Fprintf(ctxt.Bso, "%s ", s.Name) fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
if s.Type != 0 { if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "%v ", s.Type) fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
...@@ -302,7 +308,7 @@ func (w *objWriter) writeSymDebug(s *LSym) { ...@@ -302,7 +308,7 @@ func (w *objWriter) writeSymDebug(s *LSym) {
func (w *objWriter) writeSym(s *LSym) { func (w *objWriter) writeSym(s *LSym) {
ctxt := w.ctxt ctxt := w.ctxt
if ctxt.Debugasm > 0 { if ctxt.Debugasm > 0 {
w.writeSymDebug(s) w.ctxt.writeSymDebug(s)
} }
w.wr.WriteByte(symPrefix) w.wr.WriteByte(symPrefix)
......
// 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) { ...@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Addr{}, 32, 48}, {Addr{}, 32, 48},
{LSym{}, 56, 104}, {LSym{}, 76, 128},
{Prog{}, 132, 200}, {Prog{}, 132, 200},
} }
......
...@@ -32,10 +32,12 @@ ...@@ -32,10 +32,12 @@
package obj package obj
import ( import (
"cmd/internal/goobj2"
"cmd/internal/objabi" "cmd/internal/objabi"
"fmt" "fmt"
"log" "log"
"math" "math"
"sort"
) )
func Linknew(arch *LinkArch) *Link { func Linknew(arch *LinkArch) *Link {
...@@ -78,6 +80,13 @@ func (ctxt *Link) LookupStatic(name string) *LSym { ...@@ -78,6 +80,13 @@ func (ctxt *Link) LookupStatic(name string) *LSym {
// LookupABI looks up a symbol with the given ABI. // LookupABI looks up a symbol with the given ABI.
// If it does not exist, it creates it. // If it does not exist, it creates it.
func (ctxt *Link) LookupABI(name string, abi ABI) *LSym { 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 var hash map[string]*LSym
switch abi { switch abi {
case ABI0: case ABI0:
...@@ -94,6 +103,9 @@ func (ctxt *Link) LookupABI(name string, abi ABI) *LSym { ...@@ -94,6 +103,9 @@ func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
s = &LSym{Name: name} s = &LSym{Name: name}
s.SetABI(abi) s.SetABI(abi)
hash[name] = s hash[name] = s
if init != nil {
init(s)
}
} }
ctxt.hashmu.Unlock() ctxt.hashmu.Unlock()
return s return s
...@@ -147,3 +159,167 @@ func (ctxt *Link) Int64Sym(i int64) *LSym { ...@@ -147,3 +159,167 @@ func (ctxt *Link) Int64Sym(i int64) *LSym {
s.Set(AttrLocal, true) 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) { ...@@ -402,7 +402,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
case objabi.R_ADDRCUOFF: case objabi.R_ADDRCUOFF:
// debug_range and debug_loc elements use this relocation type to get an // debug_range and debug_loc elements use this relocation type to get an
// offset from the start of the compile unit. // 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. // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL: case objabi.R_GOTPCREL:
...@@ -1086,13 +1086,13 @@ func (p *GCProg) AddSym(s *sym.Symbol) { ...@@ -1086,13 +1086,13 @@ func (p *GCProg) AddSym(s *sym.Symbol) {
} }
ptrsize := int64(p.ctxt.Arch.PtrSize) ptrsize := int64(p.ctxt.Arch.PtrSize)
nptr := decodetypePtrdata(p.ctxt.Arch, typ) / ptrsize nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / ptrsize
if debugGCProg { if debugGCProg {
fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr) 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. // Copy pointers from mask into program.
mask := decodetypeGcmask(p.ctxt, typ) mask := decodetypeGcmask(p.ctxt, typ)
for i := int64(0); i < nptr; i++ { for i := int64(0); i < nptr; i++ {
......
...@@ -46,6 +46,15 @@ import ( ...@@ -46,6 +46,15 @@ import (
// //
// Any unreached text symbols are removed from ctxt.Textp. // Any unreached text symbols are removed from ctxt.Textp.
func deadcode(ctxt *Link) { func deadcode(ctxt *Link) {
if ctxt.Debugvlog != 0 {
ctxt.Logf("deadcode\n")
}
if *flagNewobj {
deadcode2(ctxt)
return
}
d := &deadcodepass{ d := &deadcodepass{
ctxt: ctxt, ctxt: ctxt,
ifaceMethod: make(map[methodsig]bool), ifaceMethod: make(map[methodsig]bool),
...@@ -114,22 +123,70 @@ func deadcode(ctxt *Link) { ...@@ -114,22 +123,70 @@ func deadcode(ctxt *Link) {
} }
} }
for _, lib := range ctxt.Library { addToTextp(ctxt)
lib.Textp = lib.Textp[:0] }
}
func addToTextp(ctxt *Link) {
// Remove dead text but keep file information (z symbols). // 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 { for _, s := range ctxt.Textp {
if s.Attr.Reachable() { 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) 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 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 // methodref holds the relocations from a receiver type symbol to its
...@@ -274,7 +331,7 @@ func (d *deadcodepass) flood() { ...@@ -274,7 +331,7 @@ func (d *deadcodepass) flood() {
// later will give a better error than deadcode. // later will give a better error than deadcode.
continue 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) { for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) {
if d.ctxt.Debugvlog > 1 { if d.ctxt.Debugvlog > 1 {
d.ctxt.Logf("reached iface method: %s\n", sig) d.ctxt.Logf("reached iface method: %s\n", sig)
......
This diff is collapsed.
...@@ -65,28 +65,28 @@ func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize } // ru ...@@ -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 func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
// Type.commonType.kind // Type.commonType.kind
func decodetypeKind(arch *sys.Arch, s *sym.Symbol) uint8 { func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
return s.P[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f return p[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
} }
// Type.commonType.kind // Type.commonType.kind
func decodetypeUsegcprog(arch *sys.Arch, s *sym.Symbol) uint8 { func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
return s.P[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f return p[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
} }
// Type.commonType.size // Type.commonType.size
func decodetypeSize(arch *sys.Arch, s *sym.Symbol) int64 { func decodetypeSize(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, s.P, arch.PtrSize)) // 0x8 / 0x10 return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
} }
// Type.commonType.ptrdata // Type.commonType.ptrdata
func decodetypePtrdata(arch *sys.Arch, s *sym.Symbol) int64 { func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, s.P[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10 return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
} }
// Type.commonType.tflag // Type.commonType.tflag
func decodetypeHasUncommon(arch *sys.Arch, s *sym.Symbol) bool { func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
return s.P[2*arch.PtrSize+4]&tflagUncommon != 0 return p[2*arch.PtrSize+4]&tflagUncommon != 0
} }
// Find the elf.Section of a given shared library that contains a given address. // 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 { ...@@ -138,7 +138,7 @@ func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte { func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
if s.Type == sym.SDYNIMPORT { if s.Type == sym.SDYNIMPORT {
addr := decodetypeGcprogShlib(ctxt, s) addr := decodetypeGcprogShlib(ctxt, s)
ptrdata := decodetypePtrdata(ctxt.Arch, s) ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
sect := findShlibSection(ctxt, s.File, addr) sect := findShlibSection(ctxt, s.File, addr)
if sect != nil { if sect != nil {
r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize)) r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
...@@ -181,17 +181,17 @@ func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol { ...@@ -181,17 +181,17 @@ func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
} }
// Type.FuncType.dotdotdot // Type.FuncType.dotdotdot
func decodetypeFuncDotdotdot(arch *sys.Arch, s *sym.Symbol) bool { func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
return uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2))&(1<<15) != 0 return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
} }
// Type.FuncType.inCount // Type.FuncType.inCount
func decodetypeFuncInCount(arch *sys.Arch, s *sym.Symbol) int { func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
return int(decodeInuxi(arch, s.P[commonsize(arch):], 2)) return int(decodeInuxi(arch, p[commonsize(arch):], 2))
} }
func decodetypeFuncOutCount(arch *sys.Arch, s *sym.Symbol) int { func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
return int(uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2)) & (1<<15 - 1)) 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 { 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 { ...@@ -199,14 +199,14 @@ func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
if arch.PtrSize == 8 { if arch.PtrSize == 8 {
uadd += 4 uadd += 4
} }
if decodetypeHasUncommon(arch, s) { if decodetypeHasUncommon(arch, s.P) {
uadd += uncommonSize() uadd += uncommonSize()
} }
return decodeRelocSym(s, int32(uadd+i*arch.PtrSize)) return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
} }
func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol { 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 // Type.StructType.fields.Slice::length
...@@ -216,7 +216,7 @@ func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int { ...@@ -216,7 +216,7 @@ func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int { func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
off := commonsize(arch) + 4*arch.PtrSize off := commonsize(arch) + 4*arch.PtrSize
if decodetypeHasUncommon(arch, s) { if decodetypeHasUncommon(arch, s.P) {
off += uncommonSize() off += uncommonSize()
} }
off += i * structfieldSize(arch) off += i * structfieldSize(arch)
...@@ -264,8 +264,8 @@ func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 { ...@@ -264,8 +264,8 @@ func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
} }
// InterfaceType.methods.length // InterfaceType.methods.length
func decodetypeIfaceMethodCount(arch *sys.Arch, s *sym.Symbol) int64 { func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
} }
// methodsig is a fully qualified typed method signature, like // 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 ...@@ -299,7 +299,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth
mtypSym := decodeRelocSym(s, int32(off+4)) mtypSym := decodeRelocSym(s, int32(off+4))
buf.WriteRune('(') buf.WriteRune('(')
inCount := decodetypeFuncInCount(arch, mtypSym) inCount := decodetypeFuncInCount(arch, mtypSym.P)
for i := 0; i < inCount; i++ { for i := 0; i < inCount; i++ {
if i > 0 { if i > 0 {
buf.WriteString(", ") buf.WriteString(", ")
...@@ -307,7 +307,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth ...@@ -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(decodetypeFuncInType(arch, mtypSym, i).Name)
} }
buf.WriteString(") (") buf.WriteString(") (")
outCount := decodetypeFuncOutCount(arch, mtypSym) outCount := decodetypeFuncOutCount(arch, mtypSym.P)
for i := 0; i < outCount; i++ { for i := 0; i < outCount; i++ {
if i > 0 { if i > 0 {
buf.WriteString(", ") buf.WriteString(", ")
...@@ -324,7 +324,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth ...@@ -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 { 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)) panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
} }
r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize)) r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
...@@ -335,17 +335,17 @@ func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig { ...@@ -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)) panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
} }
off := int(r.Add) // array of reflect.imethod values off := int(r.Add) // array of reflect.imethod values
numMethods := int(decodetypeIfaceMethodCount(arch, s)) numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
sizeofIMethod := 4 + 4 sizeofIMethod := 4 + 4
return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods) return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
} }
func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig { 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)) panic(fmt.Sprintf("no methods on %q", s.Name))
} }
off := commonsize(arch) // reflect.rtype off := commonsize(arch) // reflect.rtype
switch decodetypeKind(arch, s) & kindMask { switch decodetypeKind(arch, s.P) & kindMask {
case kindStruct: // reflect.structType case kindStruct: // reflect.structType
off += 4 * arch.PtrSize off += 4 * arch.PtrSize
case kindPtr: // reflect.ptrType case kindPtr: // reflect.ptrType
......
...@@ -422,8 +422,8 @@ func defgotype(ctxt *Link, gotype *sym.Symbol) *sym.Symbol { ...@@ -422,8 +422,8 @@ func defgotype(ctxt *Link, gotype *sym.Symbol) *sym.Symbol {
func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie { func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
name := gotype.Name[5:] // could also decode from Type.string name := gotype.Name[5:] // could also decode from Type.string
kind := decodetypeKind(ctxt.Arch, gotype) kind := decodetypeKind(ctxt.Arch, gotype.P)
bytesize := decodetypeSize(ctxt.Arch, gotype) bytesize := decodetypeSize(ctxt.Arch, gotype.P)
var die, typedefdie *dwarf.DWDie var die, typedefdie *dwarf.DWDie
switch kind { switch kind {
...@@ -488,17 +488,17 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie { ...@@ -488,17 +488,17 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0) die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0) newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
typedefdie = dotypedef(ctxt, &dwtypes, name, die) typedefdie = dotypedef(ctxt, &dwtypes, name, die)
nfields := decodetypeFuncInCount(ctxt.Arch, gotype) nfields := decodetypeFuncInCount(ctxt.Arch, gotype.P)
for i := 0; i < nfields; i++ { for i := 0; i < nfields; i++ {
s := decodetypeFuncInType(ctxt.Arch, gotype, i) s := decodetypeFuncInType(ctxt.Arch, gotype, i)
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0) fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s)) 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) 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++ { for i := 0; i < nfields; i++ {
s := decodetypeFuncOutType(ctxt.Arch, gotype, i) s := decodetypeFuncOutType(ctxt.Arch, gotype, i)
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0) 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 { ...@@ -508,7 +508,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
case objabi.KindInterface: case objabi.KindInterface:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0) die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
typedefdie = dotypedef(ctxt, &dwtypes, name, die) typedefdie = dotypedef(ctxt, &dwtypes, name, die)
nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype)) nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype.P))
var s *sym.Symbol var s *sym.Symbol
if nfields == 0 { if nfields == 0 {
s = lookupOrDiag(ctxt, "type.runtime.eface") s = lookupOrDiag(ctxt, "type.runtime.eface")
...@@ -733,7 +733,7 @@ func synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) { ...@@ -733,7 +733,7 @@ func synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
gotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol) gotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol)
keytype := decodetypeMapKey(ctxt.Arch, gotype) keytype := decodetypeMapKey(ctxt.Arch, gotype)
valtype := decodetypeMapValue(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)) keytype, valtype = walksymtypedef(ctxt, defgotype(ctxt, keytype)), walksymtypedef(ctxt, defgotype(ctxt, valtype))
// compute size info like hashmap.c does. // 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 ...@@ -110,7 +110,6 @@ func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename s
return return
} }
p1 += p0 p1 += p0
loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1]) loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
} }
} }
...@@ -123,6 +122,39 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { ...@@ -123,6 +122,39 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
return 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 { for _, f := range directives {
switch f[0] { switch f[0] {
case "cgo_import_dynamic": case "cgo_import_dynamic":
...@@ -164,8 +196,8 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { ...@@ -164,8 +196,8 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
if i := strings.Index(remote, "#"); i >= 0 { if i := strings.Index(remote, "#"); i >= 0 {
remote, q = remote[:i], remote[i+1:] remote, q = remote[:i], remote[i+1:]
} }
s := ctxt.Syms.Lookup(local, 0) s := lookup(local, 0)
if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ { if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS || s.Type == sym.SHOSTOBJ {
s.SetDynimplib(lib) s.SetDynimplib(lib)
s.SetExtname(remote) s.SetExtname(remote)
s.SetDynimpvers(q) s.SetDynimpvers(q)
...@@ -183,7 +215,7 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { ...@@ -183,7 +215,7 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
} }
local := f[1] local := f[1]
s := ctxt.Syms.Lookup(local, 0) s := lookup(local, 0)
s.Type = sym.SHOSTOBJ s.Type = sym.SHOSTOBJ
s.Size = 0 s.Size = 0
continue continue
...@@ -204,11 +236,11 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { ...@@ -204,11 +236,11 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
// functions. Link.loadlib will resolve any // functions. Link.loadlib will resolve any
// ABI aliases we find here (since we may not // ABI aliases we find here (since we may not
// yet know it's an alias). // yet know it's an alias).
s := ctxt.Syms.Lookup(local, 0) s := lookup(local, 0)
switch ctxt.BuildMode { switch ctxt.BuildMode {
case BuildModeCShared, BuildModeCArchive, BuildModePlugin: case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
if s == ctxt.Syms.Lookup("main", 0) { if s == lookup("main", 0) {
continue continue
} }
} }
...@@ -223,7 +255,6 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { ...@@ -223,7 +255,6 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
if !s.Attr.CgoExport() { if !s.Attr.CgoExport() {
s.SetExtname(remote) s.SetExtname(remote)
dynexp = append(dynexp, s)
} else if s.Extname() != remote { } else if s.Extname() != remote {
fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote) fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote)
nerrors++ nerrors++
......
This diff is collapsed.
...@@ -35,6 +35,7 @@ import ( ...@@ -35,6 +35,7 @@ import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"debug/elf" "debug/elf"
"fmt" "fmt"
...@@ -96,6 +97,18 @@ type Link struct { ...@@ -96,6 +97,18 @@ type Link struct {
runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen. runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen.
relocbuf []byte // temporary buffer for applying relocations 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 { type unresolvedSymKey struct {
......
...@@ -87,6 +87,7 @@ var ( ...@@ -87,6 +87,7 @@ var (
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker") flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines") 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).") 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`") FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
FlagTextAddr = flag.Int64("T", -1, "set text segment `address`") FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
...@@ -208,8 +209,13 @@ func Main(arch *sys.Arch, theArch Arch) { ...@@ -208,8 +209,13 @@ func Main(arch *sys.Arch, theArch Arch) {
} }
ctxt.loadlib() ctxt.loadlib()
ctxt.dostrdata()
deadcode(ctxt) deadcode(ctxt)
if *flagNewobj {
ctxt.loadlibfull() // XXX do it here for now
}
ctxt.linksetup()
ctxt.dostrdata()
dwarfGenerateDebugInfo(ctxt) dwarfGenerateDebugInfo(ctxt)
if objabi.Fieldtrack_enabled != 0 { if objabi.Fieldtrack_enabled != 0 {
fieldtrack(ctxt) fieldtrack(ctxt)
......
...@@ -305,10 +305,10 @@ func (ctxt *Link) pclntab() { ...@@ -305,10 +305,10 @@ func (ctxt *Link) pclntab() {
// appears in the Pcfile table. In that case, this assigns // appears in the Pcfile table. In that case, this assigns
// the outer file a number. // the outer file a number.
numberfile(ctxt, call.File) 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.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 // byte 3 is unused
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+4), uint32(call.File.Value)) inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+4), uint32(call.File.Value))
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+8), uint32(call.Line)) inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+8), uint32(call.Line))
......
...@@ -694,7 +694,7 @@ func (ctxt *Link) symtab() { ...@@ -694,7 +694,7 @@ func (ctxt *Link) symtab() {
// creating the moduledata from scratch and it does not have a // creating the moduledata from scratch and it does not have a
// compiler-provided size, so read it from the type data. // compiler-provided size, so read it from the type data.
moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0) 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) moduledata.Grow(moduledata.Size)
lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0) lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
......
...@@ -88,3 +88,10 @@ func contains(s []string, v string) bool { ...@@ -88,3 +88,10 @@ func contains(s []string, v string) bool {
} }
return false 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 ( ...@@ -10,6 +10,7 @@ import (
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"debug/elf" "debug/elf"
"encoding/binary" "encoding/binary"
...@@ -451,7 +452,20 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags ...@@ -451,7 +452,20 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
return found, ehdrFlags, nil 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. // 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 // 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 ...@@ -459,12 +473,11 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
// parameter initEhdrFlags contains the current header flags for the output // parameter initEhdrFlags contains the current header flags for the output
// object, and the returned ehdrFlags contains what this Load function computes. // object, and the returned ehdrFlags contains what this Load function computes.
// TODO: find a better place for this logic. // 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) { errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) {
return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...)) return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
} }
localSymVersion := syms.IncVersion()
base := f.Offset() base := f.Offset()
var hdrbuf [64]uint8 var hdrbuf [64]uint8
...@@ -715,7 +728,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i ...@@ -715,7 +728,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
} }
sectsymNames[name] = true sectsymNames[name] = true
s := syms.Lookup(name, localSymVersion) s := lookup(name, localSymVersion)
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) { switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
default: default:
...@@ -754,7 +767,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i ...@@ -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++ { for i := 1; i < elfobj.nsymtab; i++ {
var elfsym ElfSym 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) return errorf("%s: malformed elf file: %v", pn, err)
} }
symbols[i] = elfsym.sym symbols[i] = elfsym.sym
...@@ -925,7 +938,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i ...@@ -925,7 +938,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
rp.Sym = nil rp.Sym = nil
} else { } else {
var elfsym ElfSym 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) return errorf("malformed elf file: %v", err)
} }
elfsym.sym = symbols[info>>32] elfsym.sym = symbols[info>>32]
...@@ -1002,7 +1015,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) { ...@@ -1002,7 +1015,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
return nil 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 { if i >= elfobj.nsymtab || i < 0 {
err = fmt.Errorf("invalid elf symbol index") err = fmt.Errorf("invalid elf symbol index")
return err return err
...@@ -1052,7 +1065,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym ...@@ -1052,7 +1065,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
switch elfsym.bind { switch elfsym.bind {
case ElfSymBindGlobal: case ElfSymBindGlobal:
if needSym != 0 { if needSym != 0 {
s = syms.Lookup(elfsym.name, 0) s = lookup(elfsym.name, 0)
// for global scoped hidden symbols we should insert it into // for global scoped hidden symbols we should insert it into
// symbol hash table, but mark them as hidden. // 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 ...@@ -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, // We need to be able to look this up,
// so put it in the hash table. // so put it in the hash table.
if needSym != 0 { if needSym != 0 {
s = syms.Lookup(elfsym.name, localSymVersion) s = lookup(elfsym.name, localSymVersion)
s.Attr |= sym.AttrVisibilityHidden s.Attr |= sym.AttrVisibilityHidden
} }
...@@ -1088,14 +1101,14 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym ...@@ -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 // local names and hidden global names are unique
// and should only be referenced by their index, not name, so we // and should only be referenced by their index, not name, so we
// don't bother to add them into the hash table // 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 s.Attr |= sym.AttrVisibilityHidden
} }
case ElfSymBindWeak: case ElfSymBindWeak:
if needSym != 0 { if needSym != 0 {
s = syms.Lookup(elfsym.name, 0) s = lookup(elfsym.name, 0)
if elfsym.other == 2 { if elfsym.other == 2 {
s.Attr |= sym.AttrVisibilityHidden s.Attr |= sym.AttrVisibilityHidden
} }
......
This diff is collapsed.
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
...@@ -423,14 +424,24 @@ func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int { ...@@ -423,14 +424,24 @@ func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
return 0 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. // 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) { errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...)) return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...))
} }
localSymVersion := syms.IncVersion()
base := f.Offset() base := f.Offset()
var hdr [7 * 4]uint8 var hdr [7 * 4]uint8
...@@ -562,7 +573,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i ...@@ -562,7 +573,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
continue continue
} }
name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name) name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
s := syms.Lookup(name, localSymVersion) s := lookup(name, localSymVersion)
if s.Type != 0 { if s.Type != 0 {
return errorf("duplicate %s/%s", sect.segname, sect.name) 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 ...@@ -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 { if machsym.type_&N_EXT == 0 {
v = localSymVersion v = localSymVersion
} }
s := syms.Lookup(name, v) s := lookup(name, v)
if machsym.type_&N_EXT == 0 { if machsym.type_&N_EXT == 0 {
s.Attr |= sym.AttrDuplicateOK s.Attr |= sym.AttrDuplicateOK
} }
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"debug/pe" "debug/pe"
"encoding/binary" "encoding/binary"
...@@ -144,12 +145,21 @@ func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) { ...@@ -144,12 +145,21 @@ func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
return n, nil 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. // 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. // 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) { 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) {
localSymVersion := syms.IncVersion()
sectsyms := make(map[*pe.Section]*sym.Symbol) sectsyms := make(map[*pe.Section]*sym.Symbol)
sectdata := make(map[*pe.Section][]byte) sectdata := make(map[*pe.Section][]byte)
...@@ -181,7 +191,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng ...@@ -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) 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) { 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 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 ...@@ -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)) 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] 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 { if err != nil {
return nil, nil, err return nil, nil, err
} }
...@@ -351,7 +361,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng ...@@ -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 { if err != nil {
return nil, nil, err return nil, nil, err
} }
...@@ -435,7 +445,7 @@ func issect(s *pe.COFFSymbol) bool { ...@@ -435,7 +445,7 @@ func issect(s *pe.COFFSymbol) bool {
return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.' 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) symname, err := pesym.FullName(f.StringTable)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -481,10 +491,10 @@ func readpesym(arch *sys.Arch, syms *sym.Symbols, f *pe.File, pesym *pe.COFFSymb ...@@ -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: case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
switch pesym.StorageClass { switch pesym.StorageClass {
case IMAGE_SYM_CLASS_EXTERNAL: //global 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: 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 s.Attr |= sym.AttrDuplicateOK
default: default:
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/sys" "cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym" "cmd/link/internal/sym"
"errors" "errors"
"fmt" "fmt"
...@@ -38,13 +39,25 @@ func (f *xcoffBiobuf) ReadAt(p []byte, off int64) (int, error) { ...@@ -38,13 +39,25 @@ func (f *xcoffBiobuf) ReadAt(p []byte, off int64) (int, error) {
return n, nil 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. // 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) { errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...)) return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...))
} }
localSymVersion := syms.IncVersion()
var ldSections []*ldSection var ldSections []*ldSection
...@@ -62,7 +75,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng ...@@ -62,7 +75,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
lds := new(ldSection) lds := new(ldSection)
lds.Section = *sect lds.Section = *sect
name := fmt.Sprintf("%s(%s)", pkg, lds.Name) name := fmt.Sprintf("%s(%s)", pkg, lds.Name)
s := syms.Lookup(name, localSymVersion) s := lookup(name, localSymVersion)
switch lds.Type { switch lds.Type {
default: default:
...@@ -100,7 +113,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng ...@@ -100,7 +113,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
continue continue
} }
s := syms.Lookup(sx.Name, 0) s := lookup(sx.Name, 0)
// Text symbol // Text symbol
if s.Type == sym.STEXT { if s.Type == sym.STEXT {
...@@ -122,7 +135,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng ...@@ -122,7 +135,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
for i, rx := range sect.Relocs { for i, rx := range sect.Relocs {
r := &rs[i] 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 { if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress {
return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress) return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress)
} }
......
...@@ -369,7 +369,7 @@ overwrite: ...@@ -369,7 +369,7 @@ overwrite:
pc.InlTree[i].Parent = r.readInt32() pc.InlTree[i].Parent = r.readInt32()
pc.InlTree[i].File = r.readSymIndex() pc.InlTree[i].File = r.readSymIndex()
pc.InlTree[i].Line = r.readInt32() 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() pc.InlTree[i].ParentPC = r.readInt32()
} }
......
...@@ -550,7 +550,7 @@ func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 { ...@@ -550,7 +550,7 @@ func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
const prefix = "TOC." const prefix = "TOC."
var tarSym *sym.Symbol var tarSym *sym.Symbol
if strings.HasPrefix(r.Sym.Name, prefix) { 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 { } else {
ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor") ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor")
} }
......
...@@ -534,7 +534,7 @@ type InlinedCall struct { ...@@ -534,7 +534,7 @@ type InlinedCall struct {
Parent int32 // index of parent in InlTree Parent int32 // index of parent in InlTree
File *Symbol // file of the inlined call File *Symbol // file of the inlined call
Line int32 // line number 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) 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 { ...@@ -86,6 +86,17 @@ func (syms *Symbols) ROLookup(name string, v int) *Symbol {
return syms.hash[v][name] 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). // Allocate a new version (i.e. symbol namespace).
func (syms *Symbols) IncVersion() int { func (syms *Symbols) IncVersion() int {
syms.hash = append(syms.hash, make(map[string]*Symbol)) syms.hash = append(syms.hash, make(map[string]*Symbol))
......
...@@ -161,3 +161,8 @@ var RelROMap = map[SymKind]SymKind{ ...@@ -161,3 +161,8 @@ var RelROMap = map[SymKind]SymKind{
SRODATA: SRODATARELRO, SRODATA: SRODATARELRO,
SFUNCTAB: SFUNCTABRELRO, 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) { ...@@ -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 ...@@ -29,9 +29,9 @@ TEXT runtime∕internal∕atomic·Cas(SB),NOSPLIT|NOFRAME,$0
CMP $7, R11 CMP $7, R11
BLT 2(PC) BLT 2(PC)
JMP ·armcas(SB) JMP ·armcas(SB)
JMP ·kernelcas<>(SB) JMP kernelcas<>(SB)
TEXT runtimeinternalatomic·kernelcas<>(SB),NOSPLIT,$0 TEXT kernelcas<>(SB),NOSPLIT,$0
MOVW ptr+0(FP), R2 MOVW ptr+0(FP), R2
// trigger potential paging fault here, // trigger potential paging fault here,
// because we don't know how to traceback through __kuser_cmpxchg // because we don't know how to traceback through __kuser_cmpxchg
......
...@@ -29,4 +29,10 @@ func main() { ...@@ -29,4 +29,10 @@ func main() {
fmt.Println(overwrite) fmt.Println(overwrite)
fmt.Println(overwritecopy) fmt.Println(overwritecopy)
fmt.Println(arraycopy[1]) 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")
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment