]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/internal/obj: write object file in new format
authorCherry Zhang <cherryyz@google.com>
Thu, 22 Aug 2019 21:26:41 +0000 (17:26 -0400)
committerCherry Zhang <cherryyz@google.com>
Thu, 3 Oct 2019 18:49:41 +0000 (18:49 +0000)
If -newobj is set, write object file in new format, which uses
indices for symbol references instead of symbol names. The file
format is described at the beginning of
cmd/internal/goobj2/objfile.go.

A new package, cmd/internal/goobj2, is introduced for reading and
writing new object files. (The package name is temporary.) It is
written in a way that trys to make the encoding as regular as
possible, and the reader and writer as symmetric as possible.

This is incomplete, and currently nothing will consume the new
object file.

Change-Id: Ifefedbf6456d760d15a9f40a28af6486c93100fe
Reviewed-on: https://go-review.googlesource.com/c/go/+/196030
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/compile/internal/gc/iexport.go
src/cmd/dist/buildtool.go
src/cmd/internal/goobj2/funcinfo.go [new file with mode: 0644]
src/cmd/internal/goobj2/objfile.go [new file with mode: 0644]
src/cmd/internal/obj/link.go
src/cmd/internal/obj/objfile.go
src/cmd/internal/obj/objfile2.go [new file with mode: 0644]
src/cmd/internal/obj/sym.go

index da81331b825eb2f0272be0b84a501ef0b2f4381f..39f777013629e5dbda5b0b5525d8fefabbaca9d1 100644 (file)
@@ -202,7 +202,7 @@ import (
        "bufio"
        "bytes"
        "cmd/compile/internal/types"
-       "cmd/internal/obj"
+       "cmd/internal/goobj2"
        "cmd/internal/src"
        "encoding/binary"
        "fmt"
@@ -980,7 +980,7 @@ func (w *exportWriter) linkname(s *types.Sym) {
 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 != "" {
+               if lsym.PkgIdx > goobj2.PkgIdxSelf || lsym.PkgIdx == goobj2.PkgIdxInvalid || s.Linkname != "" {
                        w.int64(-1)
                } else {
                        w.int64(int64(lsym.SymIdx))
index f27ea17230a290b5281575406cd13203d58f9915..e85dd9a6601dc6102075dcbbc6bb4de382497ed7 100644 (file)
@@ -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",
diff --git a/src/cmd/internal/goobj2/funcinfo.go b/src/cmd/internal/goobj2/funcinfo.go
new file mode 100644 (file)
index 0000000..5938b5f
--- /dev/null
@@ -0,0 +1,114 @@
+// 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
+       Flags   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?
+
+       // TODO: InlTree
+}
+
+const (
+       FuncFlagLeaf = 1 << iota
+       FuncFlagCFunc
+       FuncFlagReflectMethod
+       FuncFlagShared // This is really silly
+       FuncFlagTopFrame
+)
+
+func (a *FuncInfo) Write(w *bytes.Buffer) {
+       w.WriteByte(a.NoSplit)
+       w.WriteByte(a.Flags)
+
+       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)
+       }
+
+       // TODO: InlTree
+}
+
+func (a *FuncInfo) Read(b []byte) {
+       a.NoSplit = b[0]
+       a.Flags = b[1]
+       b = b[2:]
+
+       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()}
+       }
+
+       // TODO: InlTree
+}
diff --git a/src/cmd/internal/goobj2/objfile.go b/src/cmd/internal/goobj2/objfile.go
new file mode 100644 (file)
index 0000000..eb9290a
--- /dev/null
@@ -0,0 +1,513 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go new object file format, reading and writing.
+
+package goobj2 // TODO: replace the goobj package?
+
+import (
+       "cmd/internal/bio"
+       "encoding/binary"
+       "errors"
+       "fmt"
+       "io"
+)
+
+// New object file format.
+//
+//    Header struct {
+//       Magic   [...]byte   // "\x00go114LD"
+//       // TODO: Fingerprint
+//       Offsets [...]uint32 // byte offset of each block below
+//    }
+//
+//    Strings [...]struct {
+//       Len  uint32
+//       Data [...]byte
+//    }
+//
+//    PkgIndex [...]stringOff // TODO: add fingerprints
+//
+//    SymbolDefs [...]struct {
+//       Name stringOff
+//       ABI  uint16
+//       Type uint8
+//       Flag uint8
+//       Size uint32
+//    }
+//    NonPkgDefs [...]struct { // non-pkg symbol definitions
+//       ... // same as SymbolDefs
+//    }
+//    NonPkgRefs [...]struct { // non-pkg symbol references
+//       ... // same as SymbolDefs
+//    }
+//
+//    RelocIndex [...]uint32 // index to Relocs
+//    AuxIndex   [...]uint32 // index to Aux
+//    DataIndex  [...]uint32 // offset to Data
+//
+//    Relocs [...]struct {
+//       Off  int32
+//       Size uint8
+//       Type uint8
+//       Add  int64
+//       Sym  symRef
+//    }
+//
+//    Aux [...]struct {
+//       Type uint8
+//       Sym  symRef
+//    }
+//
+//    Data   [...]byte
+//    Pcdata [...]byte
+//
+// stringOff is a uint32 (?) offset that points to the corresponding
+// string, which is a uint32 length followed by that number of bytes.
+//
+// symRef is struct { PkgIdx, SymIdx uint32 }.
+//
+// Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
+// followed by that number of elements.
+//
+// The types below correspond to the encoded data structure in the
+// object file.
+
+// Symbol indexing.
+//
+// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
+// as the symRef struct above.
+//
+// PkgIdx is either a predeclared index (see PkgIdxNone below) or
+// an index of an imported package. For the latter case, PkgIdx is the
+// index of the package in the PkgIndex array. 0 is an invalid index.
+//
+// SymIdx is the index of the symbol in the given package.
+// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
+//   SymbolDefs array.
+// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
+//   NonPkgDefs array (could natually overflow to NonPkgRefs array).
+// - Otherwise, SymIdx is the index of the symbol in some other package's
+//   SymbolDefs array.
+//
+// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
+//
+// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
+// Relocs/Aux/Data blocks, one element per symbol, first for all the
+// defined symbols, then all the defined non-package symbols, in the
+// same order of SymbolDefs/NonPkgDefs arrays. For N total defined
+// symbols, the array is of length N+1. The last element is the total
+// number of relocations (aux symbols, data blocks, etc.).
+//
+// They can be accessed by index. For the i-th symbol, its relocations
+// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
+// elements in the Relocs array. Aux/Data are likewise. (The index is
+// 0-based.)
+
+// Auxiliary symbols.
+//
+// Each symbol may (or may not) be associated with a number of auxiliary
+// symbols. They are described in the Aux block. See Aux struct below.
+// Currently a symbol's Gotype and FuncInfo are auxiliary symbols. We
+// may make use of aux symbols in more cases, e.g. DWARF symbols.
+
+// Package Index.
+const (
+       PkgIdxNone    = (1<<31 - 1) - iota // Non-package symbols
+       PkgIdxBuiltin                      // Predefined symbols // TODO: not used for now, we could use it for compiler-generated symbols like runtime.newobject
+       PkgIdxSelf                         // Symbols defined in the current package
+       PkgIdxInvalid = 0
+       // The index of other referenced packages starts from 1.
+)
+
+// Blocks
+const (
+       BlkPkgIdx = iota
+       BlkSymdef
+       BlkNonpkgdef
+       BlkNonpkgref
+       BlkRelocIdx
+       BlkAuxIdx
+       BlkDataIdx
+       BlkReloc
+       BlkAux
+       BlkData
+       BlkPcdata
+       NBlk
+)
+
+// File header.
+// TODO: probably no need to export this.
+type Header struct {
+       Magic   string
+       Offsets [NBlk]uint32
+}
+
+const Magic = "\x00go114LD"
+
+func (h *Header) Write(w *Writer) {
+       w.RawString(h.Magic)
+       for _, x := range h.Offsets {
+               w.Uint32(x)
+       }
+}
+
+func (h *Header) Read(r *Reader) error {
+       b := r.BytesAt(0, len(Magic))
+       h.Magic = string(b)
+       if h.Magic != Magic {
+               return errors.New("wrong magic, not a Go object file")
+       }
+       off := uint32(len(h.Magic))
+       for i := range h.Offsets {
+               h.Offsets[i] = r.uint32At(off)
+               off += 4
+       }
+       return nil
+}
+
+func (h *Header) Size() int {
+       return len(h.Magic) + 4*len(h.Offsets)
+}
+
+// Symbol definition.
+type Sym struct {
+       Name string
+       ABI  uint16
+       Type uint8
+       Flag uint8
+       Siz  uint32
+}
+
+const SymABIstatic = ^uint16(0)
+
+const (
+       SymFlagDupok = 1 << iota
+       SymFlagLocal
+       SymFlagTypelink
+)
+
+func (s *Sym) Write(w *Writer) {
+       w.StringRef(s.Name)
+       w.Uint16(s.ABI)
+       w.Uint8(s.Type)
+       w.Uint8(s.Flag)
+       w.Uint32(s.Siz)
+}
+
+func (s *Sym) Read(r *Reader, off uint32) {
+       s.Name = r.StringRef(off)
+       s.ABI = r.uint16At(off + 4)
+       s.Type = r.uint8At(off + 6)
+       s.Flag = r.uint8At(off + 7)
+       s.Siz = r.uint32At(off + 8)
+}
+
+func (s *Sym) Size() int {
+       return 4 + 2 + 1 + 1 + 4
+}
+
+// Symbol reference.
+type SymRef struct {
+       PkgIdx uint32
+       SymIdx uint32
+}
+
+func (s *SymRef) Write(w *Writer) {
+       w.Uint32(s.PkgIdx)
+       w.Uint32(s.SymIdx)
+}
+
+func (s *SymRef) Read(r *Reader, off uint32) {
+       s.PkgIdx = r.uint32At(off)
+       s.SymIdx = r.uint32At(off + 4)
+}
+
+func (s *SymRef) Size() int {
+       return 4 + 4
+}
+
+// Relocation.
+type Reloc struct {
+       Off  int32
+       Siz  uint8
+       Type uint8
+       Add  int64
+       Sym  SymRef
+}
+
+func (r *Reloc) Write(w *Writer) {
+       w.Uint32(uint32(r.Off))
+       w.Uint8(r.Siz)
+       w.Uint8(r.Type)
+       w.Uint64(uint64(r.Add))
+       r.Sym.Write(w)
+}
+
+func (o *Reloc) Read(r *Reader, off uint32) {
+       o.Off = r.int32At(off)
+       o.Siz = r.uint8At(off + 4)
+       o.Type = r.uint8At(off + 5)
+       o.Add = r.int64At(off + 6)
+       o.Sym.Read(r, off+14)
+}
+
+func (r *Reloc) Size() int {
+       return 4 + 1 + 1 + 8 + r.Sym.Size()
+}
+
+// Aux symbol info.
+type Aux struct {
+       Type uint8
+       Sym  SymRef
+}
+
+// Aux Type
+const (
+       AuxGotype = iota
+       AuxFuncInfo
+       AuxFuncdata
+
+       // TODO: more. DWARF? Pcdata?
+)
+
+func (a *Aux) Write(w *Writer) {
+       w.Uint8(a.Type)
+       a.Sym.Write(w)
+}
+
+func (a *Aux) Read(r *Reader, off uint32) {
+       a.Type = r.uint8At(off)
+       a.Sym.Read(r, off+1)
+}
+
+func (a *Aux) Size() int {
+       return 1 + a.Sym.Size()
+}
+
+type Writer struct {
+       wr        *bio.Writer
+       stringMap map[string]uint32
+       off       uint32 // running offset
+}
+
+func NewWriter(wr *bio.Writer) *Writer {
+       return &Writer{wr: wr, stringMap: make(map[string]uint32)}
+}
+
+func (w *Writer) AddString(s string) {
+       if _, ok := w.stringMap[s]; ok {
+               return
+       }
+       w.stringMap[s] = w.off
+       w.Uint32(uint32(len(s)))
+       w.RawString(s)
+}
+
+func (w *Writer) StringRef(s string) {
+       off, ok := w.stringMap[s]
+       if !ok {
+               panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
+       }
+       w.Uint32(off)
+}
+
+func (w *Writer) RawString(s string) {
+       w.wr.WriteString(s)
+       w.off += uint32(len(s))
+}
+
+func (w *Writer) Bytes(s []byte) {
+       w.wr.Write(s)
+       w.off += uint32(len(s))
+}
+
+func (w *Writer) Uint64(x uint64) {
+       var b [8]byte
+       binary.LittleEndian.PutUint64(b[:], x)
+       w.wr.Write(b[:])
+       w.off += 8
+}
+
+func (w *Writer) Uint32(x uint32) {
+       var b [4]byte
+       binary.LittleEndian.PutUint32(b[:], x)
+       w.wr.Write(b[:])
+       w.off += 4
+}
+
+func (w *Writer) Uint16(x uint16) {
+       var b [2]byte
+       binary.LittleEndian.PutUint16(b[:], x)
+       w.wr.Write(b[:])
+       w.off += 2
+}
+
+func (w *Writer) Uint8(x uint8) {
+       w.wr.WriteByte(x)
+       w.off++
+}
+
+func (w *Writer) Offset() uint32 {
+       return w.off
+}
+
+type Reader struct {
+       rd    io.ReaderAt
+       start uint32
+       h     Header // keep block offsets
+}
+
+func NewReader(rd io.ReaderAt, off uint32) *Reader {
+       r := &Reader{rd: rd, start: off}
+       err := r.h.Read(r)
+       if err != nil {
+               return nil
+       }
+       return r
+}
+
+func (r *Reader) BytesAt(off uint32, len int) []byte {
+       // TODO: read from mapped memory
+       b := make([]byte, len)
+       _, err := r.rd.ReadAt(b[:], int64(r.start+off))
+       if err != nil {
+               panic("corrupted input")
+       }
+       return b
+}
+
+func (r *Reader) uint64At(off uint32) uint64 {
+       var b [8]byte
+       n, err := r.rd.ReadAt(b[:], int64(r.start+off))
+       if n != 8 || err != nil {
+               panic("corrupted input")
+       }
+       return binary.LittleEndian.Uint64(b[:])
+}
+
+func (r *Reader) int64At(off uint32) int64 {
+       return int64(r.uint64At(off))
+}
+
+func (r *Reader) uint32At(off uint32) uint32 {
+       var b [4]byte
+       n, err := r.rd.ReadAt(b[:], int64(r.start+off))
+       if n != 4 || err != nil {
+               panic("corrupted input")
+       }
+       return binary.LittleEndian.Uint32(b[:])
+}
+
+func (r *Reader) int32At(off uint32) int32 {
+       return int32(r.uint32At(off))
+}
+
+func (r *Reader) uint16At(off uint32) uint16 {
+       var b [2]byte
+       n, err := r.rd.ReadAt(b[:], int64(r.start+off))
+       if n != 2 || err != nil {
+               panic("corrupted input")
+       }
+       return binary.LittleEndian.Uint16(b[:])
+}
+
+func (r *Reader) uint8At(off uint32) uint8 {
+       var b [1]byte
+       n, err := r.rd.ReadAt(b[:], int64(r.start+off))
+       if n != 1 || err != nil {
+               panic("corrupted input")
+       }
+       return b[0]
+}
+
+func (r *Reader) StringAt(off uint32) string {
+       // TODO: have some way to construct a string without copy
+       l := r.uint32At(off)
+       b := make([]byte, l)
+       n, err := r.rd.ReadAt(b, int64(r.start+off+4))
+       if n != int(l) || err != nil {
+               panic("corrupted input")
+       }
+       return string(b)
+}
+
+func (r *Reader) StringRef(off uint32) string {
+       return r.StringAt(r.uint32At(off))
+}
+
+func (r *Reader) Pkglist() []string {
+       n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / 4
+       s := make([]string, n)
+       for i := range s {
+               off := r.h.Offsets[BlkPkgIdx] + uint32(i)*4
+               s[i] = r.StringRef(off)
+       }
+       return s
+}
+
+func (r *Reader) NSym() int {
+       symsiz := (&Sym{}).Size()
+       return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / symsiz
+}
+
+func (r *Reader) NNonpkgdef() int {
+       symsiz := (&Sym{}).Size()
+       return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / symsiz
+}
+
+func (r *Reader) NNonpkgref() int {
+       symsiz := (&Sym{}).Size()
+       return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / symsiz
+}
+
+// SymOff returns the offset of the i-th symbol.
+func (r *Reader) SymOff(i int) uint32 {
+       symsiz := (&Sym{}).Size()
+       return r.h.Offsets[BlkSymdef] + uint32(i*symsiz)
+}
+
+// NReloc returns the number of relocations of the i-th symbol.
+func (r *Reader) NReloc(i int) int {
+       relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
+       return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
+}
+
+// RelocOff returns the offset of the j-th relocation of the i-th symbol.
+func (r *Reader) RelocOff(i int, j int) uint32 {
+       relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
+       relocIdx := r.uint32At(relocIdxOff)
+       relocsiz := (&Reloc{}).Size()
+       return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(relocsiz)
+}
+
+// NAux returns the number of aux symbols of the i-th symbol.
+func (r *Reader) NAux(i int) int {
+       auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
+       return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
+}
+
+// AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
+func (r *Reader) AuxOff(i int, j int) uint32 {
+       auxIdxOff := r.h.Offsets[BlkAuxIdx] + uint32(i*4)
+       auxIdx := r.uint32At(auxIdxOff)
+       auxsiz := (&Aux{}).Size()
+       return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(auxsiz)
+}
+
+// DataOff returns the offset of the i-th symbol's data.
+func (r *Reader) DataOff(i int) uint32 {
+       dataIdxOff := r.h.Offsets[BlkDataIdx] + uint32(i*4)
+       return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
+}
+
+// DataSize returns the size of the i-th symbol's data.
+func (r *Reader) DataSize(i int) int {
+       return int(r.DataOff(i+1) - r.DataOff(i))
+}
+
+// AuxDataBase returns the base offset of the aux data block.
+func (r *Reader) PcdataBase() uint32 {
+       return r.h.Offsets[BlkPcdata]
+}
index f1cf342d3de92726f8d7cd8fcb89480f3068c8c8..2c106bab30d9a73ef5b4b2d843a7291b3a052cc0 100644 (file)
@@ -413,6 +413,8 @@ type FuncInfo struct {
        GCLocals     *LSym
        GCRegs       *LSym
        StackObjects *LSym
+
+       FuncInfoSym *LSym
 }
 
 type InlMark struct {
@@ -636,15 +638,6 @@ type Pcdata struct {
        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 {
index c51a11c51f8b80641999dcba70c826222a3c5eec..a27004a389970ca1521e8ca188b5da7f005c01b9 100644 (file)
@@ -82,6 +82,11 @@ func newObjWriter(ctxt *Link, b *bufio.Writer, pkgpath string) *objWriter {
 }
 
 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)
 
diff --git a/src/cmd/internal/obj/objfile2.go b/src/cmd/internal/obj/objfile2.go
new file mode 100644 (file)
index 0000000..42f050a
--- /dev/null
@@ -0,0 +1,350 @@
+// 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"
+       "strings"
+)
+
+// Entry point of writing new object file.
+func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
+       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.
+       h := goobj2.Header{Magic: goobj2.Magic}
+       h.Write(w.Writer)
+
+       // String table
+       w.StringTable()
+
+       // Package references
+       h.Offsets[goobj2.BlkPkgIdx] = w.Offset()
+       for _, pkg := range w.pkglist {
+               w.StringRef(pkg)
+       }
+
+       // 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)
+                       if s.Gotype != nil {
+                               naux++
+                       }
+                       if s.Func != nil {
+                               // FuncInfo is an aux symbol, each Funcdata is an aux symbol
+                               naux += 1 + uint32(len(s.Func.Pcln.Funcdata))
+                       }
+               }
+       }
+       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
+       }
+
+       // Also make sure imported packages appear in the list (even if no symbol is referenced).
+       for _, pkg := range w.ctxt.Imports {
+               if _, ok := w.ctxt.pkgIdx[pkg]; !ok {
+                       w.pkglist = append(w.pkglist, 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(f)
+               }
+               for _, call := range pc.InlTree.nodes {
+                       f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
+                       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
+       }
+       o := goobj2.Sym{
+               Name: s.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)
+               }
+       }
+}
+
+// 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
+               }
+               flags := uint8(0)
+               if s.Leaf() {
+                       flags |= goobj2.FuncFlagLeaf
+               }
+               if s.CFunc() {
+                       flags |= goobj2.FuncFlagCFunc
+               }
+               if s.ReflectMethod() {
+                       flags |= goobj2.FuncFlagReflectMethod
+               }
+               if ctxt.Flag_shared { // This is really silly
+                       flags |= goobj2.FuncFlagShared
+               }
+               if s.TopFrame() {
+                       flags |= goobj2.FuncFlagTopFrame
+               }
+               o := goobj2.FuncInfo{
+                       NoSplit: nosplit,
+                       Flags:   flags,
+                       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.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...)
+}
index e47c511ddc753479f070bbb3cb158f49ca7ebe4e..e72ec3e701ae17e475b5ef39e33bb9da591638d2 100644 (file)
@@ -32,6 +32,7 @@
 package obj
 
 import (
+       "cmd/internal/goobj2"
        "cmd/internal/objabi"
        "fmt"
        "log"
@@ -173,7 +174,7 @@ func (ctxt *Link) NumberSyms(asm bool) {
        var idx, nonpkgidx int32 = 0, 0
        ctxt.traverseSyms(traverseDefs, func(s *LSym) {
                if asm || s.Pkg == "_" || s.DuplicateOK() {
-                       s.PkgIdx = PkgIdxNone
+                       s.PkgIdx = goobj2.PkgIdxNone
                        s.SymIdx = nonpkgidx
                        if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
                                panic("bad index")
@@ -181,7 +182,7 @@ func (ctxt *Link) NumberSyms(asm bool) {
                        ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
                        nonpkgidx++
                } else {
-                       s.PkgIdx = PkgIdxSelf
+                       s.PkgIdx = goobj2.PkgIdxSelf
                        s.SymIdx = idx
                        if idx != int32(len(ctxt.defs)) {
                                panic("bad index")
@@ -195,12 +196,12 @@ func (ctxt *Link) NumberSyms(asm bool) {
        ipkg := int32(1) // 0 is invalid index
        nonpkgdef := nonpkgidx
        ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
-               if rs.PkgIdx != PkgIdxInvalid {
+               if rs.PkgIdx != goobj2.PkgIdxInvalid {
                        return
                }
                pkg := rs.Pkg
                if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
-                       rs.PkgIdx = PkgIdxNone
+                       rs.PkgIdx = goobj2.PkgIdxNone
                        rs.SymIdx = nonpkgidx
                        rs.Set(AttrIndexed, true)
                        if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {