--- /dev/null
+// 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]
+}
--- /dev/null
+// 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...)
+}