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 (
Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
Newobj = flag.Bool("newobj", false, "use new object file format")
)
var (
......
......@@ -40,18 +40,18 @@ func main() {
}
ctxt.Flag_dynlink = *flags.Dynlink
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
ctxt.Flag_newobj = *flags.Newobj
ctxt.Bso = bufio.NewWriter(os.Stdout)
defer ctxt.Bso.Flush()
architecture.Init(ctxt)
// Create object file, write header.
out, err := os.Create(*flags.OutputFile)
buf, err := bio.Create(*flags.OutputFile)
if err != nil {
log.Fatal(err)
}
defer bio.MustClose(out)
buf := bufio.NewWriter(bio.MustWriter(out))
defer buf.Close()
if !*flags.SymABIs {
fmt.Fprintf(buf, "go object %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version)
......@@ -83,6 +83,7 @@ func main() {
}
}
if ok && !*flags.SymABIs {
ctxt.NumberSyms(true)
obj.WriteObjFile(ctxt, buf, "")
}
if !ok || diag {
......@@ -91,9 +92,8 @@ func main() {
} else {
log.Print("assembly failed")
}
out.Close()
buf.Close()
os.Remove(*flags.OutputFile)
os.Exit(1)
}
buf.Flush()
}
......@@ -203,6 +203,7 @@ import (
"bufio"
"bytes"
"cmd/compile/internal/types"
"cmd/internal/goobj2"
"cmd/internal/src"
"encoding/binary"
"fmt"
......@@ -945,10 +946,12 @@ func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
func (w *exportWriter) varExt(n *Node) {
w.linkname(n.Sym)
w.symIdx(n.Sym)
}
func (w *exportWriter) funcExt(n *Node) {
w.linkname(n.Sym)
w.symIdx(n.Sym)
// Escape analysis.
for _, fs := range types.RecvsParams {
......@@ -987,6 +990,22 @@ func (w *exportWriter) linkname(s *types.Sym) {
w.string(s.Linkname)
}
func (w *exportWriter) symIdx(s *types.Sym) {
if Ctxt.Flag_newobj {
lsym := s.Linksym()
if lsym.PkgIdx > goobj2.PkgIdxSelf || (lsym.PkgIdx == goobj2.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
// Don't export index for non-package symbols, linkname'd symbols,
// and symbols without an index. They can only be referenced by
// name.
w.int64(-1)
} else {
// For a defined symbol, export its index.
// For re-exporting an imported symbol, pass its index through.
w.int64(int64(lsym.SymIdx))
}
}
}
// Inline bodies.
func (w *exportWriter) stmtList(list Nodes) {
......
......@@ -10,6 +10,7 @@ package gc
import (
"cmd/compile/internal/types"
"cmd/internal/bio"
"cmd/internal/obj"
"cmd/internal/src"
"encoding/binary"
"fmt"
......@@ -651,10 +652,12 @@ func (r *importReader) byte() byte {
func (r *importReader) varExt(n *Node) {
r.linkname(n.Sym)
r.symIdx(n.Sym)
}
func (r *importReader) funcExt(n *Node) {
r.linkname(n.Sym)
r.symIdx(n.Sym)
// Escape analysis.
for _, fs := range types.RecvsParams {
......@@ -683,6 +686,20 @@ func (r *importReader) linkname(s *types.Sym) {
s.Linkname = r.string()
}
func (r *importReader) symIdx(s *types.Sym) {
if Ctxt.Flag_newobj {
lsym := s.Linksym()
idx := int32(r.int64())
if idx != -1 {
if s.Linkname != "" {
Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
}
lsym.SymIdx = idx
lsym.Set(obj.AttrIndexed, true)
}
}
}
func (r *importReader) doInline(n *Node) {
if len(n.Func.Inl.Body) != 0 {
Fatalf("%v already has inline body", n)
......
......@@ -260,6 +260,7 @@ func Main(archInit func(*Arch)) {
if supportsDynlink(thearch.LinkArch.Arch) {
flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
flag.BoolVar(&Ctxt.Flag_linkshared, "linkshared", false, "generate code that will be linked against Go shared libraries")
}
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
......@@ -274,12 +275,14 @@ func Main(archInit func(*Arch)) {
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
flag.BoolVar(&Ctxt.Flag_newobj, "newobj", false, "use new object file format")
objabi.Flagparse(usage)
// Record flags that affect the build result. (And don't
// record flags that don't, since that would cause spurious
// changes in the binary.)
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes")
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "newobj")
if smallFrames {
maxStackVarSize = 128 * 1024
......@@ -746,6 +749,8 @@ func Main(archInit func(*Arch)) {
// Write object data to disk.
timings.Start("be", "dumpobj")
dumpdata()
Ctxt.NumberSyms(false)
dumpobj()
if asmhdr != "" {
dumpasmhdr()
......
......@@ -111,21 +111,7 @@ func dumpCompilerObj(bout *bio.Writer) {
dumpexport(bout)
}
func dumpLinkerObj(bout *bio.Writer) {
printObjHeader(bout)
if len(pragcgobuf) != 0 {
// write empty export section; must be before cgo section
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
fmt.Fprintf(bout, "\n$$ // cgo\n")
if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
Fatalf("serializing pragcgobuf: %v", err)
}
fmt.Fprintf(bout, "\n$$\n\n")
}
fmt.Fprintf(bout, "\n!\n")
func dumpdata() {
externs := len(externdcl)
dumpglobls()
......@@ -163,8 +149,24 @@ func dumpLinkerObj(bout *bio.Writer) {
}
addGCLocals()
}
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() {
......
......@@ -80,11 +80,18 @@ func (sym *Sym) Linksym() *obj.LSym {
if sym == nil {
return nil
}
initPkg := func(r *obj.LSym) {
if sym.Linkname != "" {
r.Pkg = "_"
} else {
r.Pkg = sym.Pkg.Prefix
}
}
if sym.Func() {
// This is a function symbol. Mark it as "internal ABI".
return Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
return Ctxt.LookupABIInit(sym.LinksymName(), obj.ABIInternal, initPkg)
}
return Ctxt.Lookup(sym.LinksymName())
return Ctxt.LookupInit(sym.LinksymName(), initPkg)
}
// Less reports whether symbol a is ordered before symbol b.
......
......@@ -54,6 +54,7 @@ var bootstrapDirs = []string{
"cmd/internal/gcprog",
"cmd/internal/dwarf",
"cmd/internal/edit",
"cmd/internal/goobj2",
"cmd/internal/objabi",
"cmd/internal/obj",
"cmd/internal/obj/arm",
......@@ -72,6 +73,7 @@ var bootstrapDirs = []string{
"cmd/link/internal/arm64",
"cmd/link/internal/ld",
"cmd/link/internal/loadelf",
"cmd/link/internal/loader",
"cmd/link/internal/loadmacho",
"cmd/link/internal/loadpe",
"cmd/link/internal/loadxcoff",
......
......@@ -585,7 +585,7 @@ func (t *tester) registerTests() {
},
})
// Also test a cgo package.
if t.cgoEnabled {
if t.cgoEnabled && t.internalLink() {
t.tests = append(t.tests, distTest{
name: "pie_internal_cgo",
heading: "internal linking of -buildmode=pie",
......
......@@ -145,8 +145,8 @@
// -ldflags '[pattern=]arg list'
// arguments to pass on each go tool link invocation.
// -linkshared
// link against shared libraries previously created with
// -buildmode=shared.
// build code that will be linked against shared libraries previously
// created with -buildmode=shared.
// -mod mode
// module download mode to use: readonly or vendor.
// See 'go help modules' for more.
......
......@@ -97,8 +97,8 @@ and test commands:
-ldflags '[pattern=]arg list'
arguments to pass on each go tool link invocation.
-linkshared
link against shared libraries previously created with
-buildmode=shared.
build code that will be linked against shared libraries previously
created with -buildmode=shared.
-mod mode
module download mode to use: readonly or vendor.
See 'go help modules' for more.
......
......@@ -224,6 +224,7 @@ func buildModeInit() {
base.Fatalf("-linkshared not supported on %s\n", platform)
}
codegenArg = "-dynlink"
forcedGcflags = append(forcedGcflags, "-linkshared")
// TODO(mwhudson): remove -w when that gets fixed in linker.
forcedLdflags = append(forcedLdflags, "-linkshared", "-w")
}
......
......@@ -1372,7 +1372,13 @@ func PutDefaultFunc(ctxt Context, s *FnState) error {
abbrev := DW_ABRV_FUNCTION
Uleb128put(ctxt, s.Info, int64(abbrev))
putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(s.Name)), s.Name)
// Expand '"".' to import path.
name := s.Name
if s.Importpath != "" {
name = strings.Replace(name, "\"\".", objabi.PathToPrefix(s.Importpath)+".", -1)
}
putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC)
putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC)
putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
......
......@@ -502,6 +502,14 @@ func (r *objReader) parseObject(prefix []byte) error {
}
// TODO: extract OS + build ID if/when we need it
p, err := r.peek(8)
if err != nil {
return err
}
if bytes.Equal(p, []byte("\x00go114LD")) {
r.readNew()
return nil
}
r.readFull(r.tmp[:8])
if !bytes.Equal(r.tmp[:8], []byte("\x00go114ld")) {
return r.error(errCorruptObject)
......
// 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 {
R []Reloc
Func *FuncInfo
Pkg string
PkgIdx int32
SymIdx int32 // TODO: replace RefIdx
}
// A FuncInfo contains extra fields for STEXT symbols.
......@@ -410,6 +414,8 @@ type FuncInfo struct {
GCRegs *LSym
StackObjects *LSym
OpenCodedDeferInfo *LSym
FuncInfoSym *LSym
}
type InlMark struct {
......@@ -461,7 +467,7 @@ const (
)
// Attribute is a set of symbol attributes.
type Attribute uint16
type Attribute uint32
const (
AttrDuplicateOK Attribute = 1 << iota
......@@ -502,6 +508,10 @@ const (
// keep unwinding beyond this frame.
AttrTopFrame
// Indexed indicates this symbol has been assigned with an index (when using the
// new object file format).
AttrIndexed
// attrABIBase is the value at which the ABI is encoded in
// Attribute. This must be last; all bits after this are
// assumed to be an ABI value.
......@@ -525,6 +535,7 @@ func (a Attribute) NoFrame() bool { return a&AttrNoFrame != 0 }
func (a Attribute) Static() bool { return a&AttrStatic != 0 }
func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 }
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 }
func (a Attribute) Indexed() bool { return a&AttrIndexed != 0 }
func (a *Attribute) Set(flag Attribute, value bool) {
if value {
......@@ -559,6 +570,7 @@ var textAttrStrings = [...]struct {
{bit: AttrStatic, s: "STATIC"},
{bit: AttrWasInlined, s: ""},
{bit: AttrTopFrame, s: "TOPFRAME"},
{bit: AttrIndexed, s: ""},
}
// TextAttrString formats a for printing in as part of a TEXT prog.
......@@ -637,8 +649,10 @@ type Link struct {
Debugpcln string
Flag_shared bool
Flag_dynlink bool
Flag_linkshared bool
Flag_optimize bool
Flag_locationlists bool
Flag_newobj bool // use new object file format
Bso *bufio.Writer
Pathname string
hashmu sync.Mutex // protects hash, funchash
......@@ -672,6 +686,14 @@ type Link struct {
// TODO(austin): Replace this with ABI wrappers once the ABIs
// actually diverge.
ABIAliases []*LSym
// pkgIdx maps package path to index. The index is used for
// symbol reference in the object file.
pkgIdx map[string]int32
defs []*LSym // list of defined symbols in the current package
nonpkgdefs []*LSym // list of defined non-package symbols
nonpkgrefs []*LSym // list of referenced non-package symbols
}
func (ctxt *Link) Diag(format string, args ...interface{}) {
......
......@@ -8,6 +8,7 @@ package obj
import (
"bufio"
"cmd/internal/bio"
"cmd/internal/dwarf"
"cmd/internal/objabi"
"cmd/internal/sys"
......@@ -80,7 +81,13 @@ func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter {
}
}
func WriteObjFile(ctxt *Link, b *bufio.Writer, pkgpath string) {
func WriteObjFile(ctxt *Link, bout *bio.Writer, pkgpath string) {
if ctxt.Flag_newobj {
WriteObjFile2(ctxt, bout, pkgpath)
return
}
b := bout.Writer
w := newObjWriter(ctxt, b, pkgpath)
// Magic header
......@@ -221,8 +228,7 @@ func (w *objWriter) writeRefs(s *LSym) {
}
}
func (w *objWriter) writeSymDebug(s *LSym) {
ctxt := w.ctxt
func (ctxt *Link) writeSymDebug(s *LSym) {
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
......@@ -302,7 +308,7 @@ func (w *objWriter) writeSymDebug(s *LSym) {
func (w *objWriter) writeSym(s *LSym) {
ctxt := w.ctxt
if ctxt.Debugasm > 0 {
w.writeSymDebug(s)
w.ctxt.writeSymDebug(s)
}
w.wr.WriteByte(symPrefix)
......
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Writing Go object files.
package obj
import (
"bytes"
"cmd/internal/bio"
"cmd/internal/goobj2"
"cmd/internal/objabi"
"fmt"
"path/filepath"
"strings"
)
// Entry point of writing new object file.
func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
if ctxt.Debugasm > 0 {
ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
}
genFuncInfoSyms(ctxt)
w := writer{
Writer: goobj2.NewWriter(b),
ctxt: ctxt,
pkgpath: objabi.PathToPrefix(pkgpath),
}
start := b.Offset()
w.init()
// Header
// We just reserve the space. We'll fill in the offsets later.
flags := uint32(0)
if ctxt.Flag_shared {
flags |= goobj2.ObjFlagShared
}
h := goobj2.Header{Magic: goobj2.Magic, Flags: flags}
h.Write(w.Writer)
// String table
w.StringTable()
// Autolib
h.Offsets[goobj2.BlkAutolib] = w.Offset()
for _, pkg := range ctxt.Imports {
w.StringRef(pkg)
}
// Package references
h.Offsets[goobj2.BlkPkgIdx] = w.Offset()
for _, pkg := range w.pkglist {
w.StringRef(pkg)
}
// DWARF file table
h.Offsets[goobj2.BlkDwarfFile] = w.Offset()
for _, f := range ctxt.PosTable.DebugLinesFileTable() {
w.StringRef(f)
}
// Symbol definitions
h.Offsets[goobj2.BlkSymdef] = w.Offset()
for _, s := range ctxt.defs {
w.Sym(s)
}
// Non-pkg symbol definitions
h.Offsets[goobj2.BlkNonpkgdef] = w.Offset()
for _, s := range ctxt.nonpkgdefs {
w.Sym(s)
}
// Non-pkg symbol references
h.Offsets[goobj2.BlkNonpkgref] = w.Offset()
for _, s := range ctxt.nonpkgrefs {
w.Sym(s)
}
// Reloc indexes
h.Offsets[goobj2.BlkRelocIdx] = w.Offset()
nreloc := uint32(0)
lists := [][]*LSym{ctxt.defs, ctxt.nonpkgdefs}
for _, list := range lists {
for _, s := range list {
w.Uint32(nreloc)
nreloc += uint32(len(s.R))
}
}
w.Uint32(nreloc)
// Symbol Info indexes
h.Offsets[goobj2.BlkAuxIdx] = w.Offset()
naux := uint32(0)
for _, list := range lists {
for _, s := range list {
w.Uint32(naux)
naux += uint32(nAuxSym(s))
}
}
w.Uint32(naux)
// Data indexes
h.Offsets[goobj2.BlkDataIdx] = w.Offset()
dataOff := uint32(0)
for _, list := range lists {
for _, s := range list {
w.Uint32(dataOff)
dataOff += uint32(len(s.P))
}
}
w.Uint32(dataOff)
// Relocs
h.Offsets[goobj2.BlkReloc] = w.Offset()
for _, list := range lists {
for _, s := range list {
for i := range s.R {
w.Reloc(&s.R[i])
}
}
}
// Aux symbol info
h.Offsets[goobj2.BlkAux] = w.Offset()
for _, list := range lists {
for _, s := range list {
w.Aux(s)
}
}
// Data
h.Offsets[goobj2.BlkData] = w.Offset()
for _, list := range lists {
for _, s := range list {
w.Bytes(s.P)
}
}
// Pcdata
h.Offsets[goobj2.BlkPcdata] = w.Offset()
for _, s := range ctxt.Text { // iteration order must match genFuncInfoSyms
if s.Func != nil {
pc := &s.Func.Pcln
w.Bytes(pc.Pcsp.P)
w.Bytes(pc.Pcfile.P)
w.Bytes(pc.Pcline.P)
w.Bytes(pc.Pcinline.P)
for i := range pc.Pcdata {
w.Bytes(pc.Pcdata[i].P)
}
}
}
// Fix up block offsets in the header
end := start + int64(w.Offset())
b.MustSeek(start, 0)
h.Write(w.Writer)
b.MustSeek(end, 0)
}
type writer struct {
*goobj2.Writer
ctxt *Link
pkgpath string // the package import path (escaped), "" if unknown
pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
}
// prepare package index list
func (w *writer) init() {
w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
w.pkglist[0] = "" // dummy invalid package for index 0
for pkg, i := range w.ctxt.pkgIdx {
w.pkglist[i] = pkg
}
}
func (w *writer) StringTable() {
w.AddString("")
for _, pkg := range w.ctxt.Imports {
w.AddString(pkg)
}
for _, pkg := range w.pkglist {
w.AddString(pkg)
}
w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
if w.pkgpath != "" {
s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
}
w.AddString(s.Name)
})
w.ctxt.traverseSyms(traverseDefs, func(s *LSym) {
if s.Type != objabi.STEXT {
return
}
pc := &s.Func.Pcln
for _, f := range pc.File {
w.AddString(filepath.ToSlash(f))
}
for _, call := range pc.InlTree.nodes {
f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
w.AddString(filepath.ToSlash(f))
}
})
for _, f := range w.ctxt.PosTable.DebugLinesFileTable() {
w.AddString(f)
}
}
func (w *writer) Sym(s *LSym) {
abi := uint16(s.ABI())
if s.Static() {
abi = goobj2.SymABIstatic
}
flag := uint8(0)
if s.DuplicateOK() {
flag |= goobj2.SymFlagDupok
}
if s.Local() {
flag |= goobj2.SymFlagLocal
}
if s.MakeTypelink() {
flag |= goobj2.SymFlagTypelink
}
if s.Leaf() {
flag |= goobj2.SymFlagLeaf
}
if s.CFunc() {
flag |= goobj2.SymFlagCFunc
}
if s.ReflectMethod() {
flag |= goobj2.SymFlagReflectMethod
}
if s.TopFrame() {
flag |= goobj2.SymFlagTopFrame
}
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
flag |= goobj2.SymFlagGoType
}
name := s.Name
if strings.HasPrefix(name, "gofile..") {
name = filepath.ToSlash(name)
}
o := goobj2.Sym{
Name: name,
ABI: abi,
Type: uint8(s.Type),
Flag: flag,
Siz: uint32(s.Size),
}
o.Write(w.Writer)
}
func makeSymRef(s *LSym) goobj2.SymRef {
if s == nil {
return goobj2.SymRef{}
}
if s.PkgIdx == 0 || !s.Indexed() {
fmt.Printf("unindexed symbol reference: %v\n", s)
panic("unindexed symbol reference")
}
return goobj2.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
}
func (w *writer) Reloc(r *Reloc) {
o := goobj2.Reloc{
Off: r.Off,
Siz: r.Siz,
Type: uint8(r.Type),
Add: r.Add,
Sym: makeSymRef(r.Sym),
}
o.Write(w.Writer)
}
func (w *writer) Aux(s *LSym) {
if s.Gotype != nil {
o := goobj2.Aux{
Type: goobj2.AuxGotype,
Sym: makeSymRef(s.Gotype),
}
o.Write(w.Writer)
}
if s.Func != nil {
o := goobj2.Aux{
Type: goobj2.AuxFuncInfo,
Sym: makeSymRef(s.Func.FuncInfoSym),
}
o.Write(w.Writer)
for _, d := range s.Func.Pcln.Funcdata {
o := goobj2.Aux{
Type: goobj2.AuxFuncdata,
Sym: makeSymRef(d),
}
o.Write(w.Writer)
}
if s.Func.dwarfInfoSym != nil {
o := goobj2.Aux{
Type: goobj2.AuxDwarfInfo,
Sym: makeSymRef(s.Func.dwarfInfoSym),
}
o.Write(w.Writer)
}
if s.Func.dwarfLocSym != nil {
o := goobj2.Aux{
Type: goobj2.AuxDwarfLoc,
Sym: makeSymRef(s.Func.dwarfLocSym),
}
o.Write(w.Writer)
}
if s.Func.dwarfRangesSym != nil {
o := goobj2.Aux{
Type: goobj2.AuxDwarfRanges,
Sym: makeSymRef(s.Func.dwarfRangesSym),
}
o.Write(w.Writer)
}
if s.Func.dwarfDebugLinesSym != nil {
o := goobj2.Aux{
Type: goobj2.AuxDwarfLines,
Sym: makeSymRef(s.Func.dwarfDebugLinesSym),
}
o.Write(w.Writer)
}
}
}
// return the number of aux symbols s have.
func nAuxSym(s *LSym) int {
n := 0
if s.Gotype != nil {
n++
}
if s.Func != nil {
// FuncInfo is an aux symbol, each Funcdata is an aux symbol
n += 1 + len(s.Func.Pcln.Funcdata)
if s.Func.dwarfInfoSym != nil {
n++
}
if s.Func.dwarfLocSym != nil {
n++
}
if s.Func.dwarfRangesSym != nil {
n++
}
if s.Func.dwarfDebugLinesSym != nil {
n++
}
}
return n
}
// generate symbols for FuncInfo.
func genFuncInfoSyms(ctxt *Link) {
infosyms := make([]*LSym, 0, len(ctxt.Text))
var pcdataoff uint32
var b bytes.Buffer
symidx := int32(len(ctxt.defs))
for _, s := range ctxt.Text {
if s.Func == nil {
continue
}
nosplit := uint8(0)
if s.NoSplit() {
nosplit = 1
}
o := goobj2.FuncInfo{
NoSplit: nosplit,
Args: uint32(s.Func.Args),
Locals: uint32(s.Func.Locals),
}
pc := &s.Func.Pcln
o.Pcsp = pcdataoff
pcdataoff += uint32(len(pc.Pcsp.P))
o.Pcfile = pcdataoff
pcdataoff += uint32(len(pc.Pcfile.P))
o.Pcline = pcdataoff
pcdataoff += uint32(len(pc.Pcline.P))
o.Pcinline = pcdataoff
pcdataoff += uint32(len(pc.Pcinline.P))
o.Pcdata = make([]uint32, len(pc.Pcdata))
for i, pcd := range pc.Pcdata {
o.Pcdata[i] = pcdataoff
pcdataoff += uint32(len(pcd.P))
}
o.PcdataEnd = pcdataoff
o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
for i, x := range pc.Funcdataoff {
o.Funcdataoff[i] = uint32(x)
}
o.File = make([]goobj2.SymRef, len(pc.File))
for i, f := range pc.File {
fsym := ctxt.Lookup(f)
o.File[i] = makeSymRef(fsym)
}
o.InlTree = make([]goobj2.InlTreeNode, len(pc.InlTree.nodes))
for i, inl := range pc.InlTree.nodes {
f, l := linkgetlineFromPos(ctxt, inl.Pos)
fsym := ctxt.Lookup(f)
o.InlTree[i] = goobj2.InlTreeNode{
Parent: int32(inl.Parent),
File: makeSymRef(fsym),
Line: l,
Func: makeSymRef(inl.Func),
ParentPC: inl.ParentPC,
}
}
o.Write(&b)
isym := &LSym{
Type: objabi.SDATA, // for now, I don't think it matters
PkgIdx: goobj2.PkgIdxSelf,
SymIdx: symidx,
P: append([]byte(nil), b.Bytes()...),
}
isym.Set(AttrIndexed, true)
symidx++
infosyms = append(infosyms, isym)
s.Func.FuncInfoSym = isym
b.Reset()
}
ctxt.defs = append(ctxt.defs, infosyms...)
}
......@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_64bit uintptr // size on 64bit platforms
}{
{Addr{}, 32, 48},
{LSym{}, 56, 104},
{LSym{}, 76, 128},
{Prog{}, 132, 200},
}
......
......@@ -32,10 +32,12 @@
package obj
import (
"cmd/internal/goobj2"
"cmd/internal/objabi"
"fmt"
"log"
"math"
"sort"
)
func Linknew(arch *LinkArch) *Link {
......@@ -78,6 +80,13 @@ func (ctxt *Link) LookupStatic(name string) *LSym {
// LookupABI looks up a symbol with the given ABI.
// If it does not exist, it creates it.
func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
return ctxt.LookupABIInit(name, abi, nil)
}
// LookupABI looks up a symbol with the given ABI.
// If it does not exist, it creates it and
// passes it to init for one-time initialization.
func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
var hash map[string]*LSym
switch abi {
case ABI0:
......@@ -94,6 +103,9 @@ func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
s = &LSym{Name: name}
s.SetABI(abi)
hash[name] = s
if init != nil {
init(s)
}
}
ctxt.hashmu.Unlock()
return s
......@@ -147,3 +159,167 @@ func (ctxt *Link) Int64Sym(i int64) *LSym {
s.Set(AttrLocal, true)
})
}
// Assign index to symbols.
// asm is set to true if this is called by the assembler (i.e. not the compiler),
// in which case all the symbols are non-package (for now).
func (ctxt *Link) NumberSyms(asm bool) {
if !ctxt.Flag_newobj {
return
}
if ctxt.Headtype == objabi.Haix {
// Data must be sorted to keep a constant order in TOC symbols.
// As they are created during Progedit, two symbols can be switched between
// two different compilations. Therefore, BuildID will be different.
// TODO: find a better place and optimize to only sort TOC symbols
sort.Slice(ctxt.Data, func(i, j int) bool {
return ctxt.Data[i].Name < ctxt.Data[j].Name
})
}
ctxt.pkgIdx = make(map[string]int32)
ctxt.defs = []*LSym{}
ctxt.nonpkgdefs = []*LSym{}
var idx, nonpkgidx int32 = 0, 0
ctxt.traverseSyms(traverseDefs, func(s *LSym) {
if isNonPkgSym(ctxt, asm, s) {
s.PkgIdx = goobj2.PkgIdxNone
s.SymIdx = nonpkgidx
if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
panic("bad index")
}
ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
nonpkgidx++
} else {
s.PkgIdx = goobj2.PkgIdxSelf
s.SymIdx = idx
if idx != int32(len(ctxt.defs)) {
panic("bad index")
}
ctxt.defs = append(ctxt.defs, s)
idx++
}
s.Set(AttrIndexed, true)
})
ipkg := int32(1) // 0 is invalid index
nonpkgdef := nonpkgidx
ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
if rs.PkgIdx != goobj2.PkgIdxInvalid {
return
}
if !ctxt.Flag_linkshared {
// Assign special index for builtin symbols.
// Don't do it when linking against shared libraries, as the runtime
// may be in a different library.
if i := goobj2.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
rs.PkgIdx = goobj2.PkgIdxBuiltin
rs.SymIdx = int32(i)
rs.Set(AttrIndexed, true)
return
}
}
pkg := rs.Pkg
if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
rs.PkgIdx = goobj2.PkgIdxNone
rs.SymIdx = nonpkgidx
rs.Set(AttrIndexed, true)
if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
panic("bad index")
}
ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
nonpkgidx++
return
}
if k, ok := ctxt.pkgIdx[pkg]; ok {
rs.PkgIdx = k
return
}
rs.PkgIdx = ipkg
ctxt.pkgIdx[pkg] = ipkg
ipkg++
})
}
// Returns whether s is a non-package symbol, which needs to be referenced
// by name instead of by index.
func isNonPkgSym(ctxt *Link, asm bool, s *LSym) bool {
if asm && !s.Static() {
// asm symbols are referenced by name only, except static symbols
// which are file-local and can be referenced by index.
return true
}
if ctxt.Flag_linkshared {
// The referenced symbol may be in a different shared library so
// the linker cannot see its index.
return true
}
if s.Pkg == "_" {
// The frontend uses package "_" to mark symbols that should not
// be referenced by index, e.g. linkname'd symbols.
return true
}
if s.DuplicateOK() {
// Dupok symbol needs to be dedup'd by name.
return true
}
return false
}
type traverseFlag uint32
const (
traverseDefs traverseFlag = 1 << iota
traverseRefs
traverseAux
traverseAll = traverseDefs | traverseRefs | traverseAux
)
// Traverse symbols based on flag, call fn for each symbol.
func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
lists := [][]*LSym{ctxt.Text, ctxt.Data, ctxt.ABIAliases}
for _, list := range lists {
for _, s := range list {
if flag&traverseDefs != 0 {
fn(s)
}
if flag&traverseRefs != 0 {
for _, r := range s.R {
if r.Sym != nil {
fn(r.Sym)
}
}
}
if flag&traverseAux != 0 {
if s.Gotype != nil {
fn(s.Gotype)
}
if s.Type == objabi.STEXT {
pc := &s.Func.Pcln
for _, d := range pc.Funcdata {
if d != nil {
fn(d)
}
}
for _, f := range pc.File {
if fsym := ctxt.Lookup(f); fsym != nil {
fn(fsym)
}
}
for _, call := range pc.InlTree.nodes {
if call.Func != nil {
fn(call.Func)
}
f, _ := linkgetlineFromPos(ctxt, call.Pos)
if fsym := ctxt.Lookup(f); fsym != nil {
fn(fsym)
}
}
}
}
}
}
}
......@@ -402,7 +402,7 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
case objabi.R_ADDRCUOFF:
// debug_range and debug_loc elements use this relocation type to get an
// offset from the start of the compile unit.
o = Symaddr(r.Sym) + r.Add - Symaddr(r.Sym.Unit.Lib.Textp[0])
o = Symaddr(r.Sym) + r.Add - Symaddr(r.Sym.Unit.Textp[0])
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
case objabi.R_GOTPCREL:
......@@ -1086,13 +1086,13 @@ func (p *GCProg) AddSym(s *sym.Symbol) {
}
ptrsize := int64(p.ctxt.Arch.PtrSize)
nptr := decodetypePtrdata(p.ctxt.Arch, typ) / ptrsize
nptr := decodetypePtrdata(p.ctxt.Arch, typ.P) / ptrsize
if debugGCProg {
fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
}
if decodetypeUsegcprog(p.ctxt.Arch, typ) == 0 {
if decodetypeUsegcprog(p.ctxt.Arch, typ.P) == 0 {
// Copy pointers from mask into program.
mask := decodetypeGcmask(p.ctxt, typ)
for i := int64(0); i < nptr; i++ {
......
......@@ -46,6 +46,15 @@ import (
//
// Any unreached text symbols are removed from ctxt.Textp.
func deadcode(ctxt *Link) {
if ctxt.Debugvlog != 0 {
ctxt.Logf("deadcode\n")
}
if *flagNewobj {
deadcode2(ctxt)
return
}
d := &deadcodepass{
ctxt: ctxt,
ifaceMethod: make(map[methodsig]bool),
......@@ -114,22 +123,70 @@ func deadcode(ctxt *Link) {
}
}
for _, lib := range ctxt.Library {
lib.Textp = lib.Textp[:0]
}
addToTextp(ctxt)
}
func addToTextp(ctxt *Link) {
// Remove dead text but keep file information (z symbols).
textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
textp := []*sym.Symbol{}
for _, s := range ctxt.Textp {
if s.Attr.Reachable() {
if s.Unit != nil {
s.Unit.Lib.Textp = append(s.Unit.Lib.Textp, s)
s.Unit.Textp = append(s.Unit.Textp, s)
}
textp = append(textp, s)
}
}
// Put reachable text symbols into Textp.
// do it in postorder so that packages are laid down in dependency order
// internal first, then everything else
ctxt.Library = postorder(ctxt.Library)
for _, doInternal := range [2]bool{true, false} {
for _, lib := range ctxt.Library {
if isRuntimeDepPkg(lib.Pkg) != doInternal {
continue
}
libtextp := lib.Textp[:0]
for _, s := range lib.Textp {
if s.Attr.Reachable() {
textp = append(textp, s)
libtextp = append(libtextp, s)
if s.Unit != nil {
s.Unit.Textp = append(s.Unit.Textp, s)
}
}
}
for _, s := range lib.DupTextSyms {
if s.Attr.Reachable() && !s.Attr.OnList() {
textp = append(textp, s)
libtextp = append(libtextp, s)
if s.Unit != nil {
s.Unit.Textp = append(s.Unit.Textp, s)
}
s.Attr |= sym.AttrOnList
// dupok symbols may be defined in multiple packages. its
// associated package is chosen sort of arbitrarily (the
// first containing package that the linker loads). canonicalize
// it here to the package with which it will be laid down
// in text.
s.File = objabi.PathToPrefix(lib.Pkg)
}
}
lib.Textp = libtextp
}
}
ctxt.Textp = textp
if len(ctxt.Shlibs) > 0 {
// We might have overwritten some functions above (this tends to happen for the
// autogenerated type equality/hashing functions) and we don't want to generated
// pcln table entries for these any more so remove them from Textp.
textp := make([]*sym.Symbol, 0, len(ctxt.Textp))
for _, s := range ctxt.Textp {
if s.Type != sym.SDYNIMPORT {
textp = append(textp, s)
}
}
ctxt.Textp = textp
}
}
// methodref holds the relocations from a receiver type symbol to its
......@@ -274,7 +331,7 @@ func (d *deadcodepass) flood() {
// later will give a better error than deadcode.
continue
}
if decodetypeKind(d.ctxt.Arch, s)&kindMask == kindInterface {
if decodetypeKind(d.ctxt.Arch, s.P)&kindMask == kindInterface {
for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) {
if d.ctxt.Debugvlog > 1 {
d.ctxt.Logf("reached iface method: %s\n", sig)
......
This diff is collapsed.
......@@ -65,28 +65,28 @@ func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize } // ru
func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
// Type.commonType.kind
func decodetypeKind(arch *sys.Arch, s *sym.Symbol) uint8 {
return s.P[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
return p[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f
}
// Type.commonType.kind
func decodetypeUsegcprog(arch *sys.Arch, s *sym.Symbol) uint8 {
return s.P[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
return p[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f
}
// Type.commonType.size
func decodetypeSize(arch *sys.Arch, s *sym.Symbol) int64 {
return int64(decodeInuxi(arch, s.P, arch.PtrSize)) // 0x8 / 0x10
func decodetypeSize(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.ptrdata
func decodetypePtrdata(arch *sys.Arch, s *sym.Symbol) int64 {
return int64(decodeInuxi(arch, s.P[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.tflag
func decodetypeHasUncommon(arch *sys.Arch, s *sym.Symbol) bool {
return s.P[2*arch.PtrSize+4]&tflagUncommon != 0
func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
return p[2*arch.PtrSize+4]&tflagUncommon != 0
}
// Find the elf.Section of a given shared library that contains a given address.
......@@ -138,7 +138,7 @@ func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
if s.Type == sym.SDYNIMPORT {
addr := decodetypeGcprogShlib(ctxt, s)
ptrdata := decodetypePtrdata(ctxt.Arch, s)
ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
sect := findShlibSection(ctxt, s.File, addr)
if sect != nil {
r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
......@@ -181,17 +181,17 @@ func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
}
// Type.FuncType.dotdotdot
func decodetypeFuncDotdotdot(arch *sys.Arch, s *sym.Symbol) bool {
return uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2))&(1<<15) != 0
func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
}
// Type.FuncType.inCount
func decodetypeFuncInCount(arch *sys.Arch, s *sym.Symbol) int {
return int(decodeInuxi(arch, s.P[commonsize(arch):], 2))
func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
return int(decodeInuxi(arch, p[commonsize(arch):], 2))
}
func decodetypeFuncOutCount(arch *sys.Arch, s *sym.Symbol) int {
return int(uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2)) & (1<<15 - 1))
func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
}
func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
......@@ -199,14 +199,14 @@ func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
if arch.PtrSize == 8 {
uadd += 4
}
if decodetypeHasUncommon(arch, s) {
if decodetypeHasUncommon(arch, s.P) {
uadd += uncommonSize()
}
return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
}
func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s))
return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
}
// Type.StructType.fields.Slice::length
......@@ -216,7 +216,7 @@ func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
off := commonsize(arch) + 4*arch.PtrSize
if decodetypeHasUncommon(arch, s) {
if decodetypeHasUncommon(arch, s.P) {
off += uncommonSize()
}
off += i * structfieldSize(arch)
......@@ -264,8 +264,8 @@ func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
}
// InterfaceType.methods.length
func decodetypeIfaceMethodCount(arch *sys.Arch, s *sym.Symbol) int64 {
return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
}
// methodsig is a fully qualified typed method signature, like
......@@ -299,7 +299,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth
mtypSym := decodeRelocSym(s, int32(off+4))
buf.WriteRune('(')
inCount := decodetypeFuncInCount(arch, mtypSym)
inCount := decodetypeFuncInCount(arch, mtypSym.P)
for i := 0; i < inCount; i++ {
if i > 0 {
buf.WriteString(", ")
......@@ -307,7 +307,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth
buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
}
buf.WriteString(") (")
outCount := decodetypeFuncOutCount(arch, mtypSym)
outCount := decodetypeFuncOutCount(arch, mtypSym.P)
for i := 0; i < outCount; i++ {
if i > 0 {
buf.WriteString(", ")
......@@ -324,7 +324,7 @@ func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []meth
}
func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
if decodetypeKind(arch, s)&kindMask != kindInterface {
if decodetypeKind(arch, s.P)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
}
r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
......@@ -335,17 +335,17 @@ func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
}
off := int(r.Add) // array of reflect.imethod values
numMethods := int(decodetypeIfaceMethodCount(arch, s))
numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
sizeofIMethod := 4 + 4
return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
}
func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
if !decodetypeHasUncommon(arch, s) {
if !decodetypeHasUncommon(arch, s.P) {
panic(fmt.Sprintf("no methods on %q", s.Name))
}
off := commonsize(arch) // reflect.rtype
switch decodetypeKind(arch, s) & kindMask {
switch decodetypeKind(arch, s.P) & kindMask {
case kindStruct: // reflect.structType
off += 4 * arch.PtrSize
case kindPtr: // reflect.ptrType
......
......@@ -422,8 +422,8 @@ func defgotype(ctxt *Link, gotype *sym.Symbol) *sym.Symbol {
func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
name := gotype.Name[5:] // could also decode from Type.string
kind := decodetypeKind(ctxt.Arch, gotype)
bytesize := decodetypeSize(ctxt.Arch, gotype)
kind := decodetypeKind(ctxt.Arch, gotype.P)
bytesize := decodetypeSize(ctxt.Arch, gotype.P)
var die, typedefdie *dwarf.DWDie
switch kind {
......@@ -488,17 +488,17 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
typedefdie = dotypedef(ctxt, &dwtypes, name, die)
nfields := decodetypeFuncInCount(ctxt.Arch, gotype)
nfields := decodetypeFuncInCount(ctxt.Arch, gotype.P)
for i := 0; i < nfields; i++ {
s := decodetypeFuncInType(ctxt.Arch, gotype, i)
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
}
if decodetypeFuncDotdotdot(ctxt.Arch, gotype) {
if decodetypeFuncDotdotdot(ctxt.Arch, gotype.P) {
newdie(ctxt, die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
}
nfields = decodetypeFuncOutCount(ctxt.Arch, gotype)
nfields = decodetypeFuncOutCount(ctxt.Arch, gotype.P)
for i := 0; i < nfields; i++ {
s := decodetypeFuncOutType(ctxt.Arch, gotype, i)
fld := newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
......@@ -508,7 +508,7 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie {
case objabi.KindInterface:
die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
typedefdie = dotypedef(ctxt, &dwtypes, name, die)
nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype))
nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype.P))
var s *sym.Symbol
if nfields == 0 {
s = lookupOrDiag(ctxt, "type.runtime.eface")
......@@ -733,7 +733,7 @@ func synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
gotype := getattr(die, dwarf.DW_AT_type).Data.(*sym.Symbol)
keytype := decodetypeMapKey(ctxt.Arch, gotype)
valtype := decodetypeMapValue(ctxt.Arch, gotype)
keysize, valsize := decodetypeSize(ctxt.Arch, keytype), decodetypeSize(ctxt.Arch, valtype)
keysize, valsize := decodetypeSize(ctxt.Arch, keytype.P), decodetypeSize(ctxt.Arch, valtype.P)
keytype, valtype = walksymtypedef(ctxt, defgotype(ctxt, keytype)), walksymtypedef(ctxt, defgotype(ctxt, valtype))
// compute size info like hashmap.c does.
......
......@@ -110,7 +110,6 @@ func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename s
return
}
p1 += p0
loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
}
}
......@@ -123,6 +122,39 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
return
}
// Find cgo_export symbols. They are roots in the deadcode pass.
for _, f := range directives {
switch f[0] {
case "cgo_export_static", "cgo_export_dynamic":
if len(f) < 2 || len(f) > 3 {
continue
}
local := f[1]
switch ctxt.BuildMode {
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
if local == "main" {
continue
}
}
local = expandpkg(local, pkg)
if f[0] == "cgo_export_static" {
ctxt.cgo_export_static[local] = true
} else {
ctxt.cgo_export_dynamic[local] = true
}
}
}
if *flagNewobj {
// Record the directives. We'll process them later after Symbols are created.
ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
} else {
setCgoAttr(ctxt, ctxt.Syms.Lookup, file, pkg, directives)
}
}
// Set symbol attributes or flags based on cgo directives.
func setCgoAttr(ctxt *Link, lookup func(string, int) *sym.Symbol, file string, pkg string, directives [][]string) {
for _, f := range directives {
switch f[0] {
case "cgo_import_dynamic":
......@@ -164,8 +196,8 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
if i := strings.Index(remote, "#"); i >= 0 {
remote, q = remote[:i], remote[i+1:]
}
s := ctxt.Syms.Lookup(local, 0)
if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ {
s := lookup(local, 0)
if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS || s.Type == sym.SHOSTOBJ {
s.SetDynimplib(lib)
s.SetExtname(remote)
s.SetDynimpvers(q)
......@@ -183,7 +215,7 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
}
local := f[1]
s := ctxt.Syms.Lookup(local, 0)
s := lookup(local, 0)
s.Type = sym.SHOSTOBJ
s.Size = 0
continue
......@@ -204,11 +236,11 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
// functions. Link.loadlib will resolve any
// ABI aliases we find here (since we may not
// yet know it's an alias).
s := ctxt.Syms.Lookup(local, 0)
s := lookup(local, 0)
switch ctxt.BuildMode {
case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
if s == ctxt.Syms.Lookup("main", 0) {
if s == lookup("main", 0) {
continue
}
}
......@@ -223,7 +255,6 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) {
if !s.Attr.CgoExport() {
s.SetExtname(remote)
dynexp = append(dynexp, s)
} else if s.Extname() != remote {
fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote)
nerrors++
......
This diff is collapsed.
......@@ -35,6 +35,7 @@ import (
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"fmt"
......@@ -96,6 +97,18 @@ type Link struct {
runtimeCU *sym.CompilationUnit // One of the runtime CUs, the last one seen.
relocbuf []byte // temporary buffer for applying relocations
loader *loader.Loader
cgodata []cgodata // cgo directives to load, three strings are args for loadcgo
cgo_export_static map[string]bool
cgo_export_dynamic map[string]bool
}
type cgodata struct {
file string
pkg string
directives [][]string
}
type unresolvedSymKey struct {
......
......@@ -87,6 +87,7 @@ var (
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
flagNewobj = flag.Bool("newobj", false, "use new object file format")
FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
......@@ -208,8 +209,13 @@ func Main(arch *sys.Arch, theArch Arch) {
}
ctxt.loadlib()
ctxt.dostrdata()
deadcode(ctxt)
if *flagNewobj {
ctxt.loadlibfull() // XXX do it here for now
}
ctxt.linksetup()
ctxt.dostrdata()
dwarfGenerateDebugInfo(ctxt)
if objabi.Fieldtrack_enabled != 0 {
fieldtrack(ctxt)
......
......@@ -305,10 +305,10 @@ func (ctxt *Link) pclntab() {
// appears in the Pcfile table. In that case, this assigns
// the outer file a number.
numberfile(ctxt, call.File)
nameoff := nameToOffset(call.Func.Name)
nameoff := nameToOffset(call.Func)
inlTreeSym.SetUint16(ctxt.Arch, int64(i*20+0), uint16(call.Parent))
inlTreeSym.SetUint8(ctxt.Arch, int64(i*20+2), uint8(objabi.GetFuncID(call.Func.Name, call.Func.File)))
inlTreeSym.SetUint8(ctxt.Arch, int64(i*20+2), uint8(objabi.GetFuncID(call.Func, "")))
// byte 3 is unused
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+4), uint32(call.File.Value))
inlTreeSym.SetUint32(ctxt.Arch, int64(i*20+8), uint32(call.Line))
......
......@@ -694,7 +694,7 @@ func (ctxt *Link) symtab() {
// creating the moduledata from scratch and it does not have a
// compiler-provided size, so read it from the type data.
moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0)
moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype)
moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype.P)
moduledata.Grow(moduledata.Size)
lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
......
......@@ -88,3 +88,10 @@ func contains(s []string, v string) bool {
}
return false
}
// implements sort.Interface, for sorting symbols by name.
type byName []*sym.Symbol
func (s byName) Len() int { return len(s) }
func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byName) Less(i, j int) bool { return s[i].Name < s[j].Name }
......@@ -10,6 +10,7 @@ import (
"cmd/internal/bio"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
"encoding/binary"
......@@ -451,7 +452,20 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
return found, ehdrFlags, nil
}
// Load loads the ELF file pn from f.
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
newSym := func(name string, version int) *sym.Symbol {
return l.LookupOrCreate(name, version, syms)
}
return load(arch, syms.IncVersion(), newSym, newSym, f, pkg, length, pn, flags)
}
func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, flags uint32) ([]*sym.Symbol, uint32, error) {
return load(arch, syms.IncVersion(), syms.Newsym, syms.Lookup, f, pkg, length, pn, flags)
}
type lookupFunc func(string, int) *sym.Symbol
// load loads the ELF file pn from f.
// Symbols are written into syms, and a slice of the text symbols is returned.
//
// On ARM systems, Load will attempt to determine what ELF header flags to
......@@ -459,12 +473,11 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) (found bool, ehdrFlags
// parameter initEhdrFlags contains the current header flags for the output
// object, and the returned ehdrFlags contains what this Load function computes.
// TODO: find a better place for this logic.
func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
func load(arch *sys.Arch, localSymVersion int, newSym, lookup lookupFunc, f *bio.Reader, pkg string, length int64, pn string, initEhdrFlags uint32) (textp []*sym.Symbol, ehdrFlags uint32, err error) {
errorf := func(str string, args ...interface{}) ([]*sym.Symbol, uint32, error) {
return nil, 0, fmt.Errorf("loadelf: %s: %v", pn, fmt.Sprintf(str, args...))
}
localSymVersion := syms.IncVersion()
base := f.Offset()
var hdrbuf [64]uint8
......@@ -715,7 +728,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
}
sectsymNames[name] = true
s := syms.Lookup(name, localSymVersion)
s := lookup(name, localSymVersion)
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
default:
......@@ -754,7 +767,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
for i := 1; i < elfobj.nsymtab; i++ {
var elfsym ElfSym
if err := readelfsym(arch, syms, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
if err := readelfsym(newSym, lookup, arch, elfobj, i, &elfsym, 1, localSymVersion); err != nil {
return errorf("%s: malformed elf file: %v", pn, err)
}
symbols[i] = elfsym.sym
......@@ -925,7 +938,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
rp.Sym = nil
} else {
var elfsym ElfSym
if err := readelfsym(arch, syms, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
if err := readelfsym(newSym, lookup, arch, elfobj, int(info>>32), &elfsym, 0, 0); err != nil {
return errorf("malformed elf file: %v", err)
}
elfsym.sym = symbols[info>>32]
......@@ -1002,7 +1015,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
return nil
}
func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
func readelfsym(newSym, lookup lookupFunc, arch *sys.Arch, elfobj *ElfObj, i int, elfsym *ElfSym, needSym int, localSymVersion int) (err error) {
if i >= elfobj.nsymtab || i < 0 {
err = fmt.Errorf("invalid elf symbol index")
return err
......@@ -1052,7 +1065,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
switch elfsym.bind {
case ElfSymBindGlobal:
if needSym != 0 {
s = syms.Lookup(elfsym.name, 0)
s = lookup(elfsym.name, 0)
// for global scoped hidden symbols we should insert it into
// symbol hash table, but mark them as hidden.
......@@ -1077,7 +1090,7 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
// We need to be able to look this up,
// so put it in the hash table.
if needSym != 0 {
s = syms.Lookup(elfsym.name, localSymVersion)
s = lookup(elfsym.name, localSymVersion)
s.Attr |= sym.AttrVisibilityHidden
}
......@@ -1088,14 +1101,14 @@ func readelfsym(arch *sys.Arch, syms *sym.Symbols, elfobj *ElfObj, i int, elfsym
// local names and hidden global names are unique
// and should only be referenced by their index, not name, so we
// don't bother to add them into the hash table
s = syms.Newsym(elfsym.name, localSymVersion)
s = newSym(elfsym.name, localSymVersion)
s.Attr |= sym.AttrVisibilityHidden
}
case ElfSymBindWeak:
if needSym != 0 {
s = syms.Lookup(elfsym.name, 0)
s = lookup(elfsym.name, 0)
if elfsym.other == 2 {
s.Attr |= sym.AttrVisibilityHidden
}
......
This diff is collapsed.
......@@ -10,6 +10,7 @@ import (
"cmd/internal/bio"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"encoding/binary"
"fmt"
......@@ -423,14 +424,24 @@ func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
return 0
}
// Load loads the Mach-O file pn from f.
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) ([]*sym.Symbol, error) {
newSym := func(name string, version int) *sym.Symbol {
return l.LookupOrCreate(name, version, syms)
}
return load(arch, syms.IncVersion(), newSym, f, pkg, length, pn)
}
func LoadOld(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
return load(arch, syms.IncVersion(), syms.Lookup, f, pkg, length, pn)
}
// load the Mach-O file pn from f.
// Symbols are written into syms, and a slice of the text symbols is returned.
func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
func load(arch *sys.Arch, localSymVersion int, lookup func(string, int) *sym.Symbol, f *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
return nil, fmt.Errorf("loadmacho: %v: %v", pn, fmt.Sprintf(str, args...))
}
localSymVersion := syms.IncVersion()
base := f.Offset()
var hdr [7 * 4]uint8
......@@ -562,7 +573,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
continue
}
name := fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
s := syms.Lookup(name, localSymVersion)
s := lookup(name, localSymVersion)
if s.Type != 0 {
return errorf("duplicate %s/%s", sect.segname, sect.name)
}
......@@ -610,7 +621,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i
if machsym.type_&N_EXT == 0 {
v = localSymVersion
}
s := syms.Lookup(name, v)
s := lookup(name, v)
if machsym.type_&N_EXT == 0 {
s.Attr |= sym.AttrDuplicateOK
}
......
......@@ -9,6 +9,7 @@ import (
"cmd/internal/bio"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/pe"
"encoding/binary"
......@@ -144,12 +145,21 @@ func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
return n, nil
}
// Load loads the PE file pn from input.
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
lookup := func(name string, version int) *sym.Symbol {
return l.LookupOrCreate(name, version, syms)
}
return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn)
}
func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn)
}
// load loads the PE file pn from input.
// Symbols are written into syms, and a slice of the text symbols is returned.
// If an .rsrc section is found, its symbol is returned as rsrc.
func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
localSymVersion := syms.IncVersion()
func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
sectsyms := make(map[*pe.Section]*sym.Symbol)
sectdata := make(map[*pe.Section][]byte)
......@@ -181,7 +191,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
}
name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
s := syms.Lookup(name, localSymVersion)
s := lookup(name, localSymVersion)
switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
......@@ -239,7 +249,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
}
pesym := &f.COFFSymbols[r.SymbolTableIndex]
gosym, err := readpesym(arch, syms, f, pesym, sectsyms, localSymVersion)
gosym, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
if err != nil {
return nil, nil, err
}
......@@ -351,7 +361,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
}
}
s, err := readpesym(arch, syms, f, pesym, sectsyms, localSymVersion)
s, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
if err != nil {
return nil, nil, err
}
......@@ -435,7 +445,7 @@ func issect(s *pe.COFFSymbol) bool {
return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
}
func readpesym(arch *sys.Arch, syms *sym.Symbols, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
symname, err := pesym.FullName(f.StringTable)
if err != nil {
return nil, err
......@@ -481,10 +491,10 @@ func readpesym(arch *sys.Arch, syms *sym.Symbols, f *pe.File, pesym *pe.COFFSymb
case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
switch pesym.StorageClass {
case IMAGE_SYM_CLASS_EXTERNAL: //global
s = syms.Lookup(name, 0)
s = lookup(name, 0)
case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
s = syms.Lookup(name, localSymVersion)
s = lookup(name, localSymVersion)
s.Attr |= sym.AttrDuplicateOK
default:
......
......@@ -9,6 +9,7 @@ import (
"cmd/internal/bio"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"errors"
"fmt"
......@@ -38,13 +39,25 @@ func (f *xcoffBiobuf) ReadAt(p []byte, off int64) (int, error) {
return n, nil
}
// Load loads the Xcoff file pn from f.
// Load loads xcoff files with the indexed object files.
func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
lookup := func(name string, version int) *sym.Symbol {
return l.LookupOrCreate(name, version, syms)
}
return load(arch, lookup, syms.IncVersion(), input, pkg, length, pn)
}
// LoadOld uses the old version of object loading.
func LoadOld(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
return load(arch, syms.Lookup, syms.IncVersion(), input, pkg, length, pn)
}
// loads the Xcoff file pn from f.
// Symbols are written into syms, and a slice of the text symbols is returned.
func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
func load(arch *sys.Arch, lookup func(string, int) *sym.Symbol, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, err error) {
errorf := func(str string, args ...interface{}) ([]*sym.Symbol, error) {
return nil, fmt.Errorf("loadxcoff: %v: %v", pn, fmt.Sprintf(str, args...))
}
localSymVersion := syms.IncVersion()
var ldSections []*ldSection
......@@ -62,7 +75,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
lds := new(ldSection)
lds.Section = *sect
name := fmt.Sprintf("%s(%s)", pkg, lds.Name)
s := syms.Lookup(name, localSymVersion)
s := lookup(name, localSymVersion)
switch lds.Type {
default:
......@@ -100,7 +113,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
continue
}
s := syms.Lookup(sx.Name, 0)
s := lookup(sx.Name, 0)
// Text symbol
if s.Type == sym.STEXT {
......@@ -122,7 +135,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
for i, rx := range sect.Relocs {
r := &rs[i]
r.Sym = syms.Lookup(rx.Symbol.Name, 0)
r.Sym = lookup(rx.Symbol.Name, 0)
if uint64(int32(rx.VirtualAddress)) != rx.VirtualAddress {
return errorf("virtual address of a relocation is too big: 0x%x", rx.VirtualAddress)
}
......
......@@ -369,7 +369,7 @@ overwrite:
pc.InlTree[i].Parent = r.readInt32()
pc.InlTree[i].File = r.readSymIndex()
pc.InlTree[i].Line = r.readInt32()
pc.InlTree[i].Func = r.readSymIndex()
pc.InlTree[i].Func = r.readSymIndex().Name
pc.InlTree[i].ParentPC = r.readInt32()
}
......
......@@ -550,7 +550,7 @@ func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
const prefix = "TOC."
var tarSym *sym.Symbol
if strings.HasPrefix(r.Sym.Name, prefix) {
tarSym = ctxt.Syms.ROLookup(strings.TrimPrefix(r.Sym.Name, prefix), 0)
tarSym = r.Sym.R[0].Sym
} else {
ld.Errorf(s, "archreloctoc called for a symbol without TOC anchor")
}
......
......@@ -534,7 +534,7 @@ type InlinedCall struct {
Parent int32 // index of parent in InlTree
File *Symbol // file of the inlined call
Line int32 // line number of the inlined call
Func *Symbol // function that was inlined
Func string // name of the function that was inlined
ParentPC int32 // PC of the instruction just before the inlined body (offset from function start)
}
......
......@@ -86,6 +86,17 @@ func (syms *Symbols) ROLookup(name string, v int) *Symbol {
return syms.hash[v][name]
}
// Add an existing symbol to the symbol table.
func (syms *Symbols) Add(s *Symbol) {
name := s.Name
v := int(s.Version)
m := syms.hash[v]
if _, ok := m[name]; ok {
panic(name + " already added")
}
m[name] = s
}
// Allocate a new version (i.e. symbol namespace).
func (syms *Symbols) IncVersion() int {
syms.hash = append(syms.hash, make(map[string]*Symbol))
......
......@@ -161,3 +161,8 @@ var RelROMap = map[SymKind]SymKind{
SRODATA: SRODATARELRO,
SFUNCTAB: SFUNCTABRELRO,
}
// IsData returns true if the type is a data type.
func (t SymKind) IsData() bool {
return t == SDATA || t == SNOPTRDATA || t == SBSS || t == SNOPTRBSS
}
......@@ -376,3 +376,68 @@ func TestIssue34788Android386TLSSequence(t *testing.T) {
}
}
}
const testStrictDupGoSrc = `
package main
func f()
func main() { f() }
`
const testStrictDupAsmSrc1 = `
#include "textflag.h"
TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
RET
`
const testStrictDupAsmSrc2 = `
#include "textflag.h"
TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
JMP 0(PC)
`
func TestStrictDup(t *testing.T) {
// Check that -strictdups flag works.
testenv.MustHaveGoBuild(t)
tmpdir, err := ioutil.TempDir("", "TestStrictDup")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "x.go")
err = ioutil.WriteFile(src, []byte(testStrictDupGoSrc), 0666)
if err != nil {
t.Fatal(err)
}
src = filepath.Join(tmpdir, "a.s")
err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666)
if err != nil {
t.Fatal(err)
}
src = filepath.Join(tmpdir, "b.s")
err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666)
if err != nil {
t.Fatal(err)
}
cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=1")
cmd.Dir = tmpdir
out, err := cmd.CombinedOutput()
if err != nil {
t.Errorf("linking with -strictdups=1 failed: %v", err)
}
if !bytes.Contains(out, []byte("mismatched payload")) {
t.Errorf("unexpected output:\n%s", out)
}
cmd = exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=2")
cmd.Dir = tmpdir
out, err = cmd.CombinedOutput()
if err == nil {
t.Errorf("linking with -strictdups=2 did not fail")
}
if !bytes.Contains(out, []byte("mismatched payload")) {
t.Errorf("unexpected output:\n%s", out)
}
}
......@@ -29,9 +29,9 @@ TEXT runtime∕internal∕atomic·Cas(SB),NOSPLIT|NOFRAME,$0
CMP $7, R11
BLT 2(PC)
JMP ·armcas(SB)
JMP ·kernelcas<>(SB)
JMP kernelcas<>(SB)
TEXT runtimeinternalatomic·kernelcas<>(SB),NOSPLIT,$0
TEXT kernelcas<>(SB),NOSPLIT,$0
MOVW ptr+0(FP), R2
// trigger potential paging fault here,
// because we don't know how to traceback through __kuser_cmpxchg
......
......@@ -29,4 +29,10 @@ func main() {
fmt.Println(overwrite)
fmt.Println(overwritecopy)
fmt.Println(arraycopy[1])
// Check non-string symbols are not overwritten.
// This also make them used.
if b || x != 0 {
panic("b or x overwritten")
}
}
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