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 (
}
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()
}
}
if ok && !*flags.SymABIs {
+ ctxt.NumberSyms(true)
obj.WriteObjFile(ctxt, buf, "")
}
if !ok || diag {
"bufio"
"bytes"
"cmd/compile/internal/types"
+ "cmd/internal/obj"
"cmd/internal/src"
"encoding/binary"
"fmt"
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 {
w.string(s.Linkname)
}
+func (w *exportWriter) symIdx(s *types.Sym) {
+ if Ctxt.Flag_newobj {
+ lsym := s.Linksym()
+ if lsym.PkgIdx > obj.PkgIdxSelf || lsym.PkgIdx == obj.PkgIdxInvalid || s.Linkname != "" {
+ w.int64(-1)
+ } else {
+ w.int64(int64(lsym.SymIdx))
+ }
+ }
+}
+
// Inline bodies.
func (w *exportWriter) stmtList(list Nodes) {
import (
"cmd/compile/internal/types"
"cmd/internal/bio"
+ "cmd/internal/obj"
"cmd/internal/src"
"encoding/binary"
"fmt"
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 {
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)
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
// Write object data to disk.
timings.Start("be", "dumpobj")
dumpdata()
+ Ctxt.NumberSyms(false)
dumpobj()
if asmhdr != "" {
dumpasmhdr()
return sym.Pkg.Prefix + "." + sym.Name
}
-func (sym *Sym) Linksym() *obj.LSym {
+func (sym *Sym) Linksym() (r *obj.LSym) {
if sym == nil {
return nil
}
if sym.Func() {
// This is a function symbol. Mark it as "internal ABI".
- return Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
+ r = Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
+ } else {
+ r = Ctxt.Lookup(sym.LinksymName())
}
- return Ctxt.Lookup(sym.LinksymName())
+ if r.Pkg == "" {
+ if sym.Linkname != "" {
+ r.Pkg = "_"
+ } else {
+ r.Pkg = sym.Pkg.Prefix
+ }
+ }
+ return
}
// Less reports whether symbol a is ordered before symbol b.
R []Reloc
Func *FuncInfo
+
+ Pkg string
+ PkgIdx int32
+ SymIdx int32 // TODO: replace RefIdx
}
// A FuncInfo contains extra fields for STEXT symbols.
)
// Attribute is a set of symbol attributes.
-type Attribute uint16
+type Attribute uint32
const (
AttrDuplicateOK Attribute = 1 << iota
// 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.
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 {
{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.
P []byte
}
+// Package Index.
+const (
+ PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
+ PkgIdxBuiltin // Predefined symbols // TODO: not used for now, we could use it for compiler-generated symbols like runtime.newobject
+ PkgIdxSelf // Symbols defined in the current package
+ PkgIdxInvalid = 0
+ // The index of other referenced packages starts from 1.
+)
+
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
type Link struct {
Flag_dynlink 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
// 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{}) {
_64bit uintptr // size on 64bit platforms
}{
{Addr{}, 32, 48},
- {LSym{}, 56, 104},
+ //{LSym{}, 56, 104}, // TODO: re-enable
{Prog{}, 132, 200},
}
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
+ }
+
+ 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 asm || s.Pkg == "_" || s.DuplicateOK() {
+ s.PkgIdx = PkgIdxNone
+ s.SymIdx = nonpkgidx
+ if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
+ panic("bad index")
+ }
+ ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
+ nonpkgidx++
+ } else {
+ s.PkgIdx = 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 != PkgIdxInvalid {
+ return
+ }
+ pkg := rs.Pkg
+ if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
+ rs.PkgIdx = 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++
+ })
+}
+
+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)
+ }
+ }
+ }
+ }
+ }
+ }
+}