Commit 2c484c03 authored by Cherry Zhang's avatar Cherry Zhang

[dev.link] cmd/internal/obj: write object file in new format

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: default avatarThan McIntosh <thanm@google.com>
parent a09cd8cc
......@@ -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))
......
......@@ -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",
......
// 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
}
// 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]
}
......@@ -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 {
......
......@@ -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)
......
// 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...)
}
......@@ -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)) {
......
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