Commit bababde7 authored by Gerrit Code Review's avatar Gerrit Code Review

Merge "cmd: merge branch 'dev.link' into master"

parents 7a5e0fec bbae923d
...@@ -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