diff options
Diffstat (limited to 'vendor/github.com/twitchyliquid64/golang-asm/goobj')
4 files changed, 1394 insertions, 0 deletions
| diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtin.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtin.go new file mode 100644 index 000000000..e7d612aeb --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtin.go @@ -0,0 +1,45 @@ +// 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 + +// 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 +	} +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtinlist.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtinlist.go new file mode 100644 index 000000000..0cca75233 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/builtinlist.go @@ -0,0 +1,245 @@ +// Code generated by mkbuiltin.go. DO NOT EDIT. + +package goobj + +var builtins = [...]struct { +	name string +	abi  int +}{ +	{"runtime.newobject", 1}, +	{"runtime.mallocgc", 1}, +	{"runtime.panicdivide", 1}, +	{"runtime.panicshift", 1}, +	{"runtime.panicmakeslicelen", 1}, +	{"runtime.panicmakeslicecap", 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.makeslicecopy", 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.libfuzzerTraceCmp1", 1}, +	{"runtime.libfuzzerTraceCmp2", 1}, +	{"runtime.libfuzzerTraceCmp4", 1}, +	{"runtime.libfuzzerTraceCmp8", 1}, +	{"runtime.libfuzzerTraceConstCmp1", 1}, +	{"runtime.libfuzzerTraceConstCmp2", 1}, +	{"runtime.libfuzzerTraceConstCmp4", 1}, +	{"runtime.libfuzzerTraceConstCmp8", 1}, +	{"runtime.x86HasPOPCNT", 0}, +	{"runtime.x86HasSSE41", 0}, +	{"runtime.x86HasFMA", 0}, +	{"runtime.armHasVFPv4", 0}, +	{"runtime.arm64HasATOMICS", 0}, +	{"runtime.deferproc", 1}, +	{"runtime.deferprocStack", 1}, +	{"runtime.deferreturn", 1}, +	{"runtime.newproc", 1}, +	{"runtime.panicoverflow", 1}, +	{"runtime.sigpanic", 1}, +	{"runtime.gcWriteBarrier", 0}, +	{"runtime.morestack", 0}, +	{"runtime.morestackc", 0}, +	{"runtime.morestack_noctxt", 0}, +	{"type.int8", 0}, +	{"type.*int8", 0}, +	{"type.uint8", 0}, +	{"type.*uint8", 0}, +	{"type.int16", 0}, +	{"type.*int16", 0}, +	{"type.uint16", 0}, +	{"type.*uint16", 0}, +	{"type.int32", 0}, +	{"type.*int32", 0}, +	{"type.uint32", 0}, +	{"type.*uint32", 0}, +	{"type.int64", 0}, +	{"type.*int64", 0}, +	{"type.uint64", 0}, +	{"type.*uint64", 0}, +	{"type.float32", 0}, +	{"type.*float32", 0}, +	{"type.float64", 0}, +	{"type.*float64", 0}, +	{"type.complex64", 0}, +	{"type.*complex64", 0}, +	{"type.complex128", 0}, +	{"type.*complex128", 0}, +	{"type.unsafe.Pointer", 0}, +	{"type.*unsafe.Pointer", 0}, +	{"type.uintptr", 0}, +	{"type.*uintptr", 0}, +	{"type.bool", 0}, +	{"type.*bool", 0}, +	{"type.string", 0}, +	{"type.*string", 0}, +	{"type.error", 0}, +	{"type.*error", 0}, +	{"type.func(error) string", 0}, +	{"type.*func(error) string", 0}, +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/funcinfo.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/funcinfo.go new file mode 100644 index 000000000..9e192330d --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/funcinfo.go @@ -0,0 +1,233 @@ +// 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 ( +	"bytes" +	"github.com/twitchyliquid64/golang-asm/objabi" +	"encoding/binary" +) + +// CUFileIndex is used to index the filenames that are stored in the +// per-package/per-CU FileList. +type CUFileIndex uint32 + +// 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 { +	Args   uint32 +	Locals uint32 +	FuncID objabi.FuncID + +	Pcsp        uint32 +	Pcfile      uint32 +	Pcline      uint32 +	Pcinline    uint32 +	Pcdata      []uint32 +	PcdataEnd   uint32 +	Funcdataoff []uint32 +	File        []CUFileIndex + +	InlTree []InlTreeNode +} + +func (a *FuncInfo) Write(w *bytes.Buffer) { +	var b [4]byte +	writeUint32 := func(x uint32) { +		binary.LittleEndian.PutUint32(b[:], x) +		w.Write(b[:]) +	} + +	writeUint32(a.Args) +	writeUint32(a.Locals) +	writeUint32(uint32(a.FuncID)) + +	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(uint32(f)) +	} +	writeUint32(uint32(len(a.InlTree))) +	for i := range a.InlTree { +		a.InlTree[i].Write(w) +	} +} + +func (a *FuncInfo) Read(b []byte) { +	readUint32 := func() uint32 { +		x := binary.LittleEndian.Uint32(b) +		b = b[4:] +		return x +	} + +	a.Args = readUint32() +	a.Locals = readUint32() +	a.FuncID = objabi.FuncID(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([]CUFileIndex, filelen) +	for i := range a.File { +		a.File[i] = CUFileIndex(readUint32()) +	} +	inltreelen := readUint32() +	a.InlTree = make([]InlTreeNode, inltreelen) +	for i := range a.InlTree { +		b = a.InlTree[i].Read(b) +	} +} + +// FuncInfoLengths is a cache containing a roadmap of offsets and +// lengths for things within a serialized FuncInfo. Each length field +// stores the number of items (e.g. files, inltree nodes, etc), and the +// corresponding "off" field stores the byte offset of the start of +// the items in question. +type FuncInfoLengths struct { +	NumPcdata      uint32 +	PcdataOff      uint32 +	NumFuncdataoff uint32 +	FuncdataoffOff uint32 +	NumFile        uint32 +	FileOff        uint32 +	NumInlTree     uint32 +	InlTreeOff     uint32 +	Initialized    bool +} + +func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths { +	var result FuncInfoLengths + +	const numpcdataOff = 28 +	result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:]) +	result.PcdataOff = numpcdataOff + 4 + +	numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1) +	result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:]) +	result.FuncdataoffOff = numfuncdataoffOff + 4 + +	numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff +	result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:]) +	result.FileOff = numfileOff + 4 + +	numinltreeOff := result.FileOff + 4*result.NumFile +	result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:]) +	result.InlTreeOff = numinltreeOff + 4 + +	result.Initialized = true + +	return result +} + +func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } + +func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) } + +func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) } + +// return start and end offsets. +func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) { +	return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) { +	return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) { +	return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) { +	return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:]) +} + +// return start and end offsets. +func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) { +	return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:]) +} + +func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 { +	return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:])) +} + +func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex { +	return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:])) +} + +func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode { +	const inlTreeNodeSize = 4 * 6 +	var result InlTreeNode +	result.Read(b[inltreeoff+k*inlTreeNodeSize:]) +	return result +} + +// InlTreeNode is the serialized form of FileInfo.InlTree. +type InlTreeNode struct { +	Parent   int32 +	File     CUFileIndex +	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(uint32(inl.File)) +	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 = CUFileIndex(readUint32()) +	inl.Line = int32(readUint32()) +	inl.Func = SymRef{readUint32(), readUint32()} +	inl.ParentPC = int32(readUint32()) +	return b +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/goobj/objfile.go b/vendor/github.com/twitchyliquid64/golang-asm/goobj/objfile.go new file mode 100644 index 000000000..3303549aa --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/goobj/objfile.go @@ -0,0 +1,871 @@ +// 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. + +// This package defines the Go object file format, and provide "low-level" functions +// for reading and writing object files. + +// The object file is understood by the compiler, assembler, linker, and tools. They +// have "high level" code that operates on object files, handling application-specific +// logics, and use this package for the actual reading and writing. Specifically, the +// code below: +// +// - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile) +// - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump) +// - cmd/link/internal/loader package (used by cmd/link) +// +// If the object file format changes, they may (or may not) need to change. + +package goobj + +import ( +	"bytes" +	"github.com/twitchyliquid64/golang-asm/bio" +	"crypto/sha1" +	"encoding/binary" +	"errors" +	"fmt" +	"github.com/twitchyliquid64/golang-asm/unsafeheader" +	"io" +	"unsafe" +) + +// New object file format. +// +//    Header struct { +//       Magic       [...]byte   // "\x00go116ld" +//       Fingerprint [8]byte +//       Flags       uint32 +//       Offsets     [...]uint32 // byte offset of each block below +//    } +// +//    Strings [...]struct { +//       Data [...]byte +//    } +// +//    Autolib  [...]struct { // imported packages (for file loading) +//       Pkg         string +//       Fingerprint [8]byte +//    } +// +//    PkgIndex [...]string // referenced packages by index +// +//    Files [...]string +// +//    SymbolDefs [...]struct { +//       Name  string +//       ABI   uint16 +//       Type  uint8 +//       Flag  uint8 +//       Flag2 uint8 +//       Size  uint32 +//    } +//    Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions +//       ... // same as SymbolDefs +//    } +//    HashedDefs [...]struct { // hashed (content-addressable) symbol definitions +//       ... // same as SymbolDefs +//    } +//    NonPkgDefs [...]struct { // non-pkg symbol definitions +//       ... // same as SymbolDefs +//    } +//    NonPkgRefs [...]struct { // non-pkg symbol references +//       ... // same as SymbolDefs +//    } +// +//    RefFlags [...]struct { // referenced symbol flags +//       Sym   symRef +//       Flag  uint8 +//       Flag2 uint8 +//    } +// +//    Hash64 [...][8]byte +//    Hash   [...][N]byte +// +//    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 +// +//    // blocks only used by tools (objdump, nm) +// +//    RefNames [...]struct { // referenced symbol names +//       Sym  symRef +//       Name string +//       // TODO: include ABI version as well? +//    } +// +// string is encoded as is a uint32 length followed by a uint32 offset +// that points to the corresponding string 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 PkgIdxHashed64, SymIdx is the index of the symbol in the +//   Hashed64Defs array. +// - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the +//   HashedDefs 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. +// +// Hash contains the content hashes of content-addressable symbols, of +// which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array. +// Hash64 is similar, for PkgIdxHashed64 symbols. +// +// 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 hashed and non-package symbols, +// in the same order of SymbolDefs/Hashed64Defs/HashedDefs/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, FuncInfo, and associated DWARF symbols +// are auxiliary symbols. + +const stringRefSize = 8 // two uint32s + +type FingerprintType [8]byte + +func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} } + +// Package Index. +const ( +	PkgIdxNone     = (1<<31 - 1) - iota // Non-package symbols +	PkgIdxHashed64                      // Short hashed (content-addressable) symbols +	PkgIdxHashed                        // Hashed (content-addressable) symbols +	PkgIdxBuiltin                       // Predefined runtime symbols (ex: runtime.newobject) +	PkgIdxSelf                          // Symbols defined in the current package +	PkgIdxInvalid  = 0 +	// The index of other referenced packages starts from 1. +) + +// Blocks +const ( +	BlkAutolib = iota +	BlkPkgIdx +	BlkFile +	BlkSymdef +	BlkHashed64def +	BlkHasheddef +	BlkNonpkgdef +	BlkNonpkgref +	BlkRefFlags +	BlkHash64 +	BlkHash +	BlkRelocIdx +	BlkAuxIdx +	BlkDataIdx +	BlkReloc +	BlkAux +	BlkData +	BlkPcdata +	BlkRefName +	BlkEnd +	NBlk +) + +// File header. +// TODO: probably no need to export this. +type Header struct { +	Magic       string +	Fingerprint FingerprintType +	Flags       uint32 +	Offsets     [NBlk]uint32 +} + +const Magic = "\x00go116ld" + +func (h *Header) Write(w *Writer) { +	w.RawString(h.Magic) +	w.Bytes(h.Fingerprint[:]) +	w.Uint32(h.Flags) +	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)) +	copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint))) +	off += 8 +	h.Flags = r.uint32At(off) +	off += 4 +	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 + 4*len(h.Offsets) +} + +// Autolib +type ImportedPkg struct { +	Pkg         string +	Fingerprint FingerprintType +} + +const importedPkgSize = stringRefSize + 8 + +func (p *ImportedPkg) Write(w *Writer) { +	w.StringRef(p.Pkg) +	w.Bytes(p.Fingerprint[:]) +} + +// Symbol definition. +// +// Serialized format: +// Sym struct { +//    Name  string +//    ABI   uint16 +//    Type  uint8 +//    Flag  uint8 +//    Flag2 uint8 +//    Siz   uint32 +//    Align uint32 +// } +type Sym [SymSize]byte + +const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4 + +const SymABIstatic = ^uint16(0) + +const ( +	ObjFlagShared            = 1 << iota // this object is built with -shared +	ObjFlagNeedNameExpansion             // the linker needs to expand `"".` to package path in symbol names +	ObjFlagFromAssembly                  // object is from asm src, not go +) + +// Sym.Flag +const ( +	SymFlagDupok = 1 << iota +	SymFlagLocal +	SymFlagTypelink +	SymFlagLeaf +	SymFlagNoSplit +	SymFlagReflectMethod +	SymFlagGoType +	SymFlagTopFrame +) + +// Sym.Flag2 +const ( +	SymFlagUsedInIface = 1 << iota +	SymFlagItab +) + +// Returns the length of the name of the symbol. +func (s *Sym) NameLen(r *Reader) int { +	return int(binary.LittleEndian.Uint32(s[:])) +} + +func (s *Sym) Name(r *Reader) string { +	len := binary.LittleEndian.Uint32(s[:]) +	off := binary.LittleEndian.Uint32(s[4:]) +	return r.StringAt(off, len) +} + +func (s *Sym) ABI() uint16   { return binary.LittleEndian.Uint16(s[8:]) } +func (s *Sym) Type() uint8   { return s[10] } +func (s *Sym) Flag() uint8   { return s[11] } +func (s *Sym) Flag2() uint8  { return s[12] } +func (s *Sym) Siz() uint32   { return binary.LittleEndian.Uint32(s[13:]) } +func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) } + +func (s *Sym) Dupok() bool         { return s.Flag()&SymFlagDupok != 0 } +func (s *Sym) Local() bool         { return s.Flag()&SymFlagLocal != 0 } +func (s *Sym) Typelink() bool      { return s.Flag()&SymFlagTypelink != 0 } +func (s *Sym) Leaf() bool          { return s.Flag()&SymFlagLeaf != 0 } +func (s *Sym) NoSplit() bool       { return s.Flag()&SymFlagNoSplit != 0 } +func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 } +func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 } +func (s *Sym) TopFrame() bool      { return s.Flag()&SymFlagTopFrame != 0 } +func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 } +func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 } + +func (s *Sym) SetName(x string, w *Writer) { +	binary.LittleEndian.PutUint32(s[:], uint32(len(x))) +	binary.LittleEndian.PutUint32(s[4:], w.stringOff(x)) +} + +func (s *Sym) SetABI(x uint16)   { binary.LittleEndian.PutUint16(s[8:], x) } +func (s *Sym) SetType(x uint8)   { s[10] = x } +func (s *Sym) SetFlag(x uint8)   { s[11] = x } +func (s *Sym) SetFlag2(x uint8)  { s[12] = x } +func (s *Sym) SetSiz(x uint32)   { binary.LittleEndian.PutUint32(s[13:], x) } +func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) } + +func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) } + +// for testing +func (s *Sym) fromBytes(b []byte) { copy(s[:], b) } + +// Symbol reference. +type SymRef struct { +	PkgIdx uint32 +	SymIdx uint32 +} + +// Hash64 +type Hash64Type [Hash64Size]byte + +const Hash64Size = 8 + +// Hash +type HashType [HashSize]byte + +const HashSize = sha1.Size + +// Relocation. +// +// Serialized format: +// Reloc struct { +//    Off  int32 +//    Siz  uint8 +//    Type uint8 +//    Add  int64 +//    Sym  SymRef +// } +type Reloc [RelocSize]byte + +const RelocSize = 4 + 1 + 1 + 8 + 8 + +func (r *Reloc) Off() int32  { return int32(binary.LittleEndian.Uint32(r[:])) } +func (r *Reloc) Siz() uint8  { return r[4] } +func (r *Reloc) Type() uint8 { return r[5] } +func (r *Reloc) Add() int64  { return int64(binary.LittleEndian.Uint64(r[6:])) } +func (r *Reloc) Sym() SymRef { +	return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])} +} + +func (r *Reloc) SetOff(x int32)  { binary.LittleEndian.PutUint32(r[:], uint32(x)) } +func (r *Reloc) SetSiz(x uint8)  { r[4] = x } +func (r *Reloc) SetType(x uint8) { r[5] = x } +func (r *Reloc) SetAdd(x int64)  { binary.LittleEndian.PutUint64(r[6:], uint64(x)) } +func (r *Reloc) SetSym(x SymRef) { +	binary.LittleEndian.PutUint32(r[14:], x.PkgIdx) +	binary.LittleEndian.PutUint32(r[18:], x.SymIdx) +} + +func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) { +	r.SetOff(off) +	r.SetSiz(size) +	r.SetType(typ) +	r.SetAdd(add) +	r.SetSym(sym) +} + +func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) } + +// for testing +func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) } + +// Aux symbol info. +// +// Serialized format: +// Aux struct { +//    Type uint8 +//    Sym  SymRef +// } +type Aux [AuxSize]byte + +const AuxSize = 1 + 8 + +// Aux Type +const ( +	AuxGotype = iota +	AuxFuncInfo +	AuxFuncdata +	AuxDwarfInfo +	AuxDwarfLoc +	AuxDwarfRanges +	AuxDwarfLines + +	// TODO: more. Pcdata? +) + +func (a *Aux) Type() uint8 { return a[0] } +func (a *Aux) Sym() SymRef { +	return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])} +} + +func (a *Aux) SetType(x uint8) { a[0] = x } +func (a *Aux) SetSym(x SymRef) { +	binary.LittleEndian.PutUint32(a[1:], x.PkgIdx) +	binary.LittleEndian.PutUint32(a[5:], x.SymIdx) +} + +func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) } + +// for testing +func (a *Aux) fromBytes(b []byte) { copy(a[:], b) } + +// Referenced symbol flags. +// +// Serialized format: +// RefFlags struct { +//    Sym   symRef +//    Flag  uint8 +//    Flag2 uint8 +// } +type RefFlags [RefFlagsSize]byte + +const RefFlagsSize = 8 + 1 + 1 + +func (r *RefFlags) Sym() SymRef { +	return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])} +} +func (r *RefFlags) Flag() uint8  { return r[8] } +func (r *RefFlags) Flag2() uint8 { return r[9] } + +func (r *RefFlags) SetSym(x SymRef) { +	binary.LittleEndian.PutUint32(r[:], x.PkgIdx) +	binary.LittleEndian.PutUint32(r[4:], x.SymIdx) +} +func (r *RefFlags) SetFlag(x uint8)  { r[8] = x } +func (r *RefFlags) SetFlag2(x uint8) { r[9] = x } + +func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) } + +// Referenced symbol name. +// +// Serialized format: +// RefName struct { +//    Sym  symRef +//    Name string +// } +type RefName [RefNameSize]byte + +const RefNameSize = 8 + stringRefSize + +func (n *RefName) Sym() SymRef { +	return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])} +} +func (n *RefName) Name(r *Reader) string { +	len := binary.LittleEndian.Uint32(n[8:]) +	off := binary.LittleEndian.Uint32(n[12:]) +	return r.StringAt(off, len) +} + +func (n *RefName) SetSym(x SymRef) { +	binary.LittleEndian.PutUint32(n[:], x.PkgIdx) +	binary.LittleEndian.PutUint32(n[4:], x.SymIdx) +} +func (n *RefName) SetName(x string, w *Writer) { +	binary.LittleEndian.PutUint32(n[8:], uint32(len(x))) +	binary.LittleEndian.PutUint32(n[12:], w.stringOff(x)) +} + +func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) } + +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.RawString(s) +} + +func (w *Writer) stringOff(s string) uint32 { +	off, ok := w.stringMap[s] +	if !ok { +		panic(fmt.Sprintf("writeStringRef: string not added: %q", s)) +	} +	return off +} + +func (w *Writer) StringRef(s string) { +	w.Uint32(uint32(len(s))) +	w.Uint32(w.stringOff(s)) +} + +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 { +	b        []byte // mmapped bytes, if not nil +	readonly bool   // whether b is backed with read-only memory + +	rd    io.ReaderAt +	start uint32 +	h     Header // keep block offsets +} + +func NewReaderFromBytes(b []byte, readonly bool) *Reader { +	r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0} +	err := r.h.Read(r) +	if err != nil { +		return nil +	} +	return r +} + +func (r *Reader) BytesAt(off uint32, len int) []byte { +	if len == 0 { +		return nil +	} +	end := int(off) + len +	return r.b[int(off):end:end] +} + +func (r *Reader) uint64At(off uint32) uint64 { +	b := r.BytesAt(off, 8) +	return binary.LittleEndian.Uint64(b) +} + +func (r *Reader) int64At(off uint32) int64 { +	return int64(r.uint64At(off)) +} + +func (r *Reader) uint32At(off uint32) uint32 { +	b := r.BytesAt(off, 4) +	return binary.LittleEndian.Uint32(b) +} + +func (r *Reader) int32At(off uint32) int32 { +	return int32(r.uint32At(off)) +} + +func (r *Reader) uint16At(off uint32) uint16 { +	b := r.BytesAt(off, 2) +	return binary.LittleEndian.Uint16(b) +} + +func (r *Reader) uint8At(off uint32) uint8 { +	b := r.BytesAt(off, 1) +	return b[0] +} + +func (r *Reader) StringAt(off uint32, len uint32) string { +	b := r.b[off : off+len] +	if r.readonly { +		return toString(b) // backed by RO memory, ok to make unsafe string +	} +	return string(b) +} + +func toString(b []byte) string { +	if len(b) == 0 { +		return "" +	} + +	var s string +	hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) +	hdr.Data = unsafe.Pointer(&b[0]) +	hdr.Len = len(b) + +	return s +} + +func (r *Reader) StringRef(off uint32) string { +	l := r.uint32At(off) +	return r.StringAt(r.uint32At(off+4), l) +} + +func (r *Reader) Fingerprint() FingerprintType { +	return r.h.Fingerprint +} + +func (r *Reader) Autolib() []ImportedPkg { +	n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize +	s := make([]ImportedPkg, n) +	off := r.h.Offsets[BlkAutolib] +	for i := range s { +		s[i].Pkg = r.StringRef(off) +		copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint))) +		off += importedPkgSize +	} +	return s +} + +func (r *Reader) Pkglist() []string { +	n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize +	s := make([]string, n) +	off := r.h.Offsets[BlkPkgIdx] +	for i := range s { +		s[i] = r.StringRef(off) +		off += stringRefSize +	} +	return s +} + +func (r *Reader) NPkg() int { +	return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize +} + +func (r *Reader) Pkg(i int) string { +	off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize +	return r.StringRef(off) +} + +func (r *Reader) NFile() int { +	return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize +} + +func (r *Reader) File(i int) string { +	off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize +	return r.StringRef(off) +} + +func (r *Reader) NSym() int { +	return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize +} + +func (r *Reader) NHashed64def() int { +	return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize +} + +func (r *Reader) NHasheddef() int { +	return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize +} + +func (r *Reader) NNonpkgdef() int { +	return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize +} + +func (r *Reader) NNonpkgref() int { +	return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize +} + +// SymOff returns the offset of the i-th symbol. +func (r *Reader) SymOff(i uint32) uint32 { +	return r.h.Offsets[BlkSymdef] + uint32(i*SymSize) +} + +// Sym returns a pointer to the i-th symbol. +func (r *Reader) Sym(i uint32) *Sym { +	off := r.SymOff(i) +	return (*Sym)(unsafe.Pointer(&r.b[off])) +} + +// NRefFlags returns the number of referenced symbol flags. +func (r *Reader) NRefFlags() int { +	return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize +} + +// RefFlags returns a pointer to the i-th referenced symbol flags. +// Note: here i is not a local symbol index, just a counter. +func (r *Reader) RefFlags(i int) *RefFlags { +	off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize) +	return (*RefFlags)(unsafe.Pointer(&r.b[off])) +} + +// Hash64 returns the i-th short hashed symbol's hash. +// Note: here i is the index of short hashed symbols, not all symbols +// (unlike other accessors). +func (r *Reader) Hash64(i uint32) uint64 { +	off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size) +	return r.uint64At(off) +} + +// Hash returns a pointer to the i-th hashed symbol's hash. +// Note: here i is the index of hashed symbols, not all symbols +// (unlike other accessors). +func (r *Reader) Hash(i uint32) *HashType { +	off := r.h.Offsets[BlkHash] + uint32(i*HashSize) +	return (*HashType)(unsafe.Pointer(&r.b[off])) +} + +// NReloc returns the number of relocations of the i-th symbol. +func (r *Reader) NReloc(i uint32) 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 uint32, j int) uint32 { +	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) +	relocIdx := r.uint32At(relocIdxOff) +	return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize) +} + +// Reloc returns a pointer to the j-th relocation of the i-th symbol. +func (r *Reader) Reloc(i uint32, j int) *Reloc { +	off := r.RelocOff(i, j) +	return (*Reloc)(unsafe.Pointer(&r.b[off])) +} + +// Relocs returns a pointer to the relocations of the i-th symbol. +func (r *Reader) Relocs(i uint32) []Reloc { +	off := r.RelocOff(i, 0) +	n := r.NReloc(i) +	return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] +} + +// NAux returns the number of aux symbols of the i-th symbol. +func (r *Reader) NAux(i uint32) int { +	auxIdxOff := r.h.Offsets[BlkAuxIdx] + 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 uint32, j int) uint32 { +	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 +	auxIdx := r.uint32At(auxIdxOff) +	return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize) +} + +// Aux returns a pointer to the j-th aux symbol of the i-th symbol. +func (r *Reader) Aux(i uint32, j int) *Aux { +	off := r.AuxOff(i, j) +	return (*Aux)(unsafe.Pointer(&r.b[off])) +} + +// Auxs returns the aux symbols of the i-th symbol. +func (r *Reader) Auxs(i uint32) []Aux { +	off := r.AuxOff(i, 0) +	n := r.NAux(i) +	return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n] +} + +// DataOff returns the offset of the i-th symbol's data. +func (r *Reader) DataOff(i uint32) uint32 { +	dataIdxOff := r.h.Offsets[BlkDataIdx] + 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 uint32) int { +	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 +	return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff)) +} + +// Data returns the i-th symbol's data. +func (r *Reader) Data(i uint32) []byte { +	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 +	base := r.h.Offsets[BlkData] +	off := r.uint32At(dataIdxOff) +	end := r.uint32At(dataIdxOff + 4) +	return r.BytesAt(base+off, int(end-off)) +} + +// AuxDataBase returns the base offset of the aux data block. +func (r *Reader) PcdataBase() uint32 { +	return r.h.Offsets[BlkPcdata] +} + +// NRefName returns the number of referenced symbol names. +func (r *Reader) NRefName() int { +	return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize +} + +// RefName returns a pointer to the i-th referenced symbol name. +// Note: here i is not a local symbol index, just a counter. +func (r *Reader) RefName(i int) *RefName { +	off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize) +	return (*RefName)(unsafe.Pointer(&r.b[off])) +} + +// ReadOnly returns whether r.BytesAt returns read-only bytes. +func (r *Reader) ReadOnly() bool { +	return r.readonly +} + +// Flags returns the flag bits read from the object file header. +func (r *Reader) Flags() uint32 { +	return r.h.Flags +} + +func (r *Reader) Shared() bool            { return r.Flags()&ObjFlagShared != 0 } +func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 } +func (r *Reader) FromAssembly() bool      { return r.Flags()&ObjFlagFromAssembly != 0 } | 
