1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This package defines the Go object file format, and provide "low-level" functions
6// for reading and writing object files.
7
8// The object file is understood by the compiler, assembler, linker, and tools. They
9// have "high level" code that operates on object files, handling application-specific
10// logics, and use this package for the actual reading and writing. Specifically, the
11// code below:
12//
13// - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile)
14// - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump)
15// - cmd/link/internal/loader package (used by cmd/link)
16//
17// If the object file format changes, they may (or may not) need to change.
18
19package goobj
20
21import (
22	"cmd/internal/bio"
23	"encoding/binary"
24	"errors"
25	"fmt"
26	"unsafe"
27)
28
29// New object file format.
30//
31//    Header struct {
32//       Magic       [...]byte   // "\x00go120ld"
33//       Fingerprint [8]byte
34//       Flags       uint32
35//       Offsets     [...]uint32 // byte offset of each block below
36//    }
37//
38//    Strings [...]struct {
39//       Data [...]byte
40//    }
41//
42//    Autolib  [...]struct { // imported packages (for file loading)
43//       Pkg         string
44//       Fingerprint [8]byte
45//    }
46//
47//    PkgIndex [...]string // referenced packages by index
48//
49//    Files [...]string
50//
51//    SymbolDefs [...]struct {
52//       Name  string
53//       ABI   uint16
54//       Type  uint8
55//       Flag  uint8
56//       Flag2 uint8
57//       Size  uint32
58//    }
59//    Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions
60//       ... // same as SymbolDefs
61//    }
62//    HashedDefs [...]struct { // hashed (content-addressable) symbol definitions
63//       ... // same as SymbolDefs
64//    }
65//    NonPkgDefs [...]struct { // non-pkg symbol definitions
66//       ... // same as SymbolDefs
67//    }
68//    NonPkgRefs [...]struct { // non-pkg symbol references
69//       ... // same as SymbolDefs
70//    }
71//
72//    RefFlags [...]struct { // referenced symbol flags
73//       Sym   symRef
74//       Flag  uint8
75//       Flag2 uint8
76//    }
77//
78//    Hash64 [...][8]byte
79//    Hash   [...][N]byte
80//
81//    RelocIndex [...]uint32 // index to Relocs
82//    AuxIndex   [...]uint32 // index to Aux
83//    DataIndex  [...]uint32 // offset to Data
84//
85//    Relocs [...]struct {
86//       Off  int32
87//       Size uint8
88//       Type uint16
89//       Add  int64
90//       Sym  symRef
91//    }
92//
93//    Aux [...]struct {
94//       Type uint8
95//       Sym  symRef
96//    }
97//
98//    Data   [...]byte
99//
100//    // blocks only used by tools (objdump, nm)
101//
102//    RefNames [...]struct { // referenced symbol names
103//       Sym  symRef
104//       Name string
105//       // TODO: include ABI version as well?
106//    }
107//
108// string is encoded as is a uint32 length followed by a uint32 offset
109// that points to the corresponding string bytes.
110//
111// symRef is struct { PkgIdx, SymIdx uint32 }.
112//
113// Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
114// followed by that number of elements.
115//
116// The types below correspond to the encoded data structure in the
117// object file.
118
119// Symbol indexing.
120//
121// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
122// as the symRef struct above.
123//
124// PkgIdx is either a predeclared index (see PkgIdxNone below) or
125// an index of an imported package. For the latter case, PkgIdx is the
126// index of the package in the PkgIndex array. 0 is an invalid index.
127//
128// SymIdx is the index of the symbol in the given package.
129// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
130//   SymbolDefs array.
131// - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the
132//   Hashed64Defs array.
133// - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the
134//   HashedDefs array.
135// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
136//   NonPkgDefs array (could naturally overflow to NonPkgRefs array).
137// - Otherwise, SymIdx is the index of the symbol in some other package's
138//   SymbolDefs array.
139//
140// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
141//
142// Hash contains the content hashes of content-addressable symbols, of
143// which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array.
144// Hash64 is similar, for PkgIdxHashed64 symbols.
145//
146// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
147// Relocs/Aux/Data blocks, one element per symbol, first for all the
148// defined symbols, then all the defined hashed and non-package symbols,
149// in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs
150// arrays. For N total defined symbols, the array is of length N+1. The
151// last element is the total number of relocations (aux symbols, data
152// blocks, etc.).
153//
154// They can be accessed by index. For the i-th symbol, its relocations
155// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
156// elements in the Relocs array. Aux/Data are likewise. (The index is
157// 0-based.)
158
159// Auxiliary symbols.
160//
161// Each symbol may (or may not) be associated with a number of auxiliary
162// symbols. They are described in the Aux block. See Aux struct below.
163// Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols
164// are auxiliary symbols.
165
166const stringRefSize = 8 // two uint32s
167
168type FingerprintType [8]byte
169
170func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
171
172// Package Index.
173const (
174	PkgIdxNone     = (1<<31 - 1) - iota // Non-package symbols
175	PkgIdxHashed64                      // Short hashed (content-addressable) symbols
176	PkgIdxHashed                        // Hashed (content-addressable) symbols
177	PkgIdxBuiltin                       // Predefined runtime symbols (ex: runtime.newobject)
178	PkgIdxSelf                          // Symbols defined in the current package
179	PkgIdxSpecial  = PkgIdxSelf         // Indices above it has special meanings
180	PkgIdxInvalid  = 0
181	// The index of other referenced packages starts from 1.
182)
183
184// Blocks
185const (
186	BlkAutolib = iota
187	BlkPkgIdx
188	BlkFile
189	BlkSymdef
190	BlkHashed64def
191	BlkHasheddef
192	BlkNonpkgdef
193	BlkNonpkgref
194	BlkRefFlags
195	BlkHash64
196	BlkHash
197	BlkRelocIdx
198	BlkAuxIdx
199	BlkDataIdx
200	BlkReloc
201	BlkAux
202	BlkData
203	BlkRefName
204	BlkEnd
205	NBlk
206)
207
208// File header.
209// TODO: probably no need to export this.
210type Header struct {
211	Magic       string
212	Fingerprint FingerprintType
213	Flags       uint32
214	Offsets     [NBlk]uint32
215}
216
217const Magic = "\x00go120ld"
218
219func (h *Header) Write(w *Writer) {
220	w.RawString(h.Magic)
221	w.Bytes(h.Fingerprint[:])
222	w.Uint32(h.Flags)
223	for _, x := range h.Offsets {
224		w.Uint32(x)
225	}
226}
227
228func (h *Header) Read(r *Reader) error {
229	b := r.BytesAt(0, len(Magic))
230	h.Magic = string(b)
231	if h.Magic != Magic {
232		return errors.New("wrong magic, not a Go object file")
233	}
234	off := uint32(len(h.Magic))
235	copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
236	off += 8
237	h.Flags = r.uint32At(off)
238	off += 4
239	for i := range h.Offsets {
240		h.Offsets[i] = r.uint32At(off)
241		off += 4
242	}
243	return nil
244}
245
246func (h *Header) Size() int {
247	return len(h.Magic) + len(h.Fingerprint) + 4 + 4*len(h.Offsets)
248}
249
250// Autolib
251type ImportedPkg struct {
252	Pkg         string
253	Fingerprint FingerprintType
254}
255
256const importedPkgSize = stringRefSize + 8
257
258func (p *ImportedPkg) Write(w *Writer) {
259	w.StringRef(p.Pkg)
260	w.Bytes(p.Fingerprint[:])
261}
262
263// Symbol definition.
264//
265// Serialized format:
266//
267//	Sym struct {
268//	   Name  string
269//	   ABI   uint16
270//	   Type  uint8
271//	   Flag  uint8
272//	   Flag2 uint8
273//	   Siz   uint32
274//	   Align uint32
275//	}
276type Sym [SymSize]byte
277
278const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4
279
280const SymABIstatic = ^uint16(0)
281
282const (
283	ObjFlagShared       = 1 << iota // this object is built with -shared
284	_                               // was ObjFlagNeedNameExpansion
285	ObjFlagFromAssembly             // object is from asm src, not go
286	ObjFlagUnlinkable               // unlinkable package (linker will emit an error)
287	ObjFlagStd                      // standard library package
288)
289
290// Sym.Flag
291const (
292	SymFlagDupok = 1 << iota
293	SymFlagLocal
294	SymFlagTypelink
295	SymFlagLeaf
296	SymFlagNoSplit
297	SymFlagReflectMethod
298	SymFlagGoType
299)
300
301// Sym.Flag2
302const (
303	SymFlagUsedInIface = 1 << iota
304	SymFlagItab
305	SymFlagDict
306	SymFlagPkgInit
307	SymFlagLinkname
308	SymFlagABIWrapper
309)
310
311// Returns the length of the name of the symbol.
312func (s *Sym) NameLen(r *Reader) int {
313	return int(binary.LittleEndian.Uint32(s[:]))
314}
315
316func (s *Sym) Name(r *Reader) string {
317	len := binary.LittleEndian.Uint32(s[:])
318	off := binary.LittleEndian.Uint32(s[4:])
319	return r.StringAt(off, len)
320}
321
322func (s *Sym) ABI() uint16   { return binary.LittleEndian.Uint16(s[8:]) }
323func (s *Sym) Type() uint8   { return s[10] }
324func (s *Sym) Flag() uint8   { return s[11] }
325func (s *Sym) Flag2() uint8  { return s[12] }
326func (s *Sym) Siz() uint32   { return binary.LittleEndian.Uint32(s[13:]) }
327func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
328
329func (s *Sym) Dupok() bool         { return s.Flag()&SymFlagDupok != 0 }
330func (s *Sym) Local() bool         { return s.Flag()&SymFlagLocal != 0 }
331func (s *Sym) Typelink() bool      { return s.Flag()&SymFlagTypelink != 0 }
332func (s *Sym) Leaf() bool          { return s.Flag()&SymFlagLeaf != 0 }
333func (s *Sym) NoSplit() bool       { return s.Flag()&SymFlagNoSplit != 0 }
334func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
335func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 }
336func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 }
337func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 }
338func (s *Sym) IsDict() bool        { return s.Flag2()&SymFlagDict != 0 }
339func (s *Sym) IsPkgInit() bool     { return s.Flag2()&SymFlagPkgInit != 0 }
340func (s *Sym) IsLinkname() bool    { return s.Flag2()&SymFlagLinkname != 0 }
341func (s *Sym) ABIWrapper() bool    { return s.Flag2()&SymFlagABIWrapper != 0 }
342
343func (s *Sym) SetName(x string, w *Writer) {
344	binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
345	binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
346}
347
348func (s *Sym) SetABI(x uint16)   { binary.LittleEndian.PutUint16(s[8:], x) }
349func (s *Sym) SetType(x uint8)   { s[10] = x }
350func (s *Sym) SetFlag(x uint8)   { s[11] = x }
351func (s *Sym) SetFlag2(x uint8)  { s[12] = x }
352func (s *Sym) SetSiz(x uint32)   { binary.LittleEndian.PutUint32(s[13:], x) }
353func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
354
355func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
356
357// for testing
358func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
359
360// Symbol reference.
361type SymRef struct {
362	PkgIdx uint32
363	SymIdx uint32
364}
365
366func (s SymRef) IsZero() bool { return s == SymRef{} }
367
368// Hash64
369type Hash64Type [Hash64Size]byte
370
371const Hash64Size = 8
372
373// Hash
374type HashType [HashSize]byte
375
376const HashSize = 16 // truncated SHA256
377
378// Relocation.
379//
380// Serialized format:
381//
382//	Reloc struct {
383//	   Off  int32
384//	   Siz  uint8
385//	   Type uint16
386//	   Add  int64
387//	   Sym  SymRef
388//	}
389type Reloc [RelocSize]byte
390
391const RelocSize = 4 + 1 + 2 + 8 + 8
392
393func (r *Reloc) Off() int32   { return int32(binary.LittleEndian.Uint32(r[:])) }
394func (r *Reloc) Siz() uint8   { return r[4] }
395func (r *Reloc) Type() uint16 { return binary.LittleEndian.Uint16(r[5:]) }
396func (r *Reloc) Add() int64   { return int64(binary.LittleEndian.Uint64(r[7:])) }
397func (r *Reloc) Sym() SymRef {
398	return SymRef{binary.LittleEndian.Uint32(r[15:]), binary.LittleEndian.Uint32(r[19:])}
399}
400
401func (r *Reloc) SetOff(x int32)   { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
402func (r *Reloc) SetSiz(x uint8)   { r[4] = x }
403func (r *Reloc) SetType(x uint16) { binary.LittleEndian.PutUint16(r[5:], x) }
404func (r *Reloc) SetAdd(x int64)   { binary.LittleEndian.PutUint64(r[7:], uint64(x)) }
405func (r *Reloc) SetSym(x SymRef) {
406	binary.LittleEndian.PutUint32(r[15:], x.PkgIdx)
407	binary.LittleEndian.PutUint32(r[19:], x.SymIdx)
408}
409
410func (r *Reloc) Set(off int32, size uint8, typ uint16, add int64, sym SymRef) {
411	r.SetOff(off)
412	r.SetSiz(size)
413	r.SetType(typ)
414	r.SetAdd(add)
415	r.SetSym(sym)
416}
417
418func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
419
420// for testing
421func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
422
423// Aux symbol info.
424//
425// Serialized format:
426//
427//	Aux struct {
428//	   Type uint8
429//	   Sym  SymRef
430//	}
431type Aux [AuxSize]byte
432
433const AuxSize = 1 + 8
434
435// Aux Type
436const (
437	AuxGotype = iota
438	AuxFuncInfo
439	AuxFuncdata
440	AuxDwarfInfo
441	AuxDwarfLoc
442	AuxDwarfRanges
443	AuxDwarfLines
444	AuxPcsp
445	AuxPcfile
446	AuxPcline
447	AuxPcinline
448	AuxPcdata
449	AuxWasmImport
450	AuxSehUnwindInfo
451)
452
453func (a *Aux) Type() uint8 { return a[0] }
454func (a *Aux) Sym() SymRef {
455	return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
456}
457
458func (a *Aux) SetType(x uint8) { a[0] = x }
459func (a *Aux) SetSym(x SymRef) {
460	binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
461	binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
462}
463
464func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
465
466// for testing
467func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
468
469// Referenced symbol flags.
470//
471// Serialized format:
472//
473//	RefFlags struct {
474//	   Sym   symRef
475//	   Flag  uint8
476//	   Flag2 uint8
477//	}
478type RefFlags [RefFlagsSize]byte
479
480const RefFlagsSize = 8 + 1 + 1
481
482func (r *RefFlags) Sym() SymRef {
483	return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
484}
485func (r *RefFlags) Flag() uint8  { return r[8] }
486func (r *RefFlags) Flag2() uint8 { return r[9] }
487
488func (r *RefFlags) SetSym(x SymRef) {
489	binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
490	binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
491}
492func (r *RefFlags) SetFlag(x uint8)  { r[8] = x }
493func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
494
495func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
496
497// Used to construct an artificially large array type when reading an
498// item from the object file relocs section or aux sym section (needs
499// to work on 32-bit as well as 64-bit). See issue 41621.
500const huge = (1<<31 - 1) / RelocSize
501
502// Referenced symbol name.
503//
504// Serialized format:
505//
506//	RefName struct {
507//	   Sym  symRef
508//	   Name string
509//	}
510type RefName [RefNameSize]byte
511
512const RefNameSize = 8 + stringRefSize
513
514func (n *RefName) Sym() SymRef {
515	return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
516}
517func (n *RefName) Name(r *Reader) string {
518	len := binary.LittleEndian.Uint32(n[8:])
519	off := binary.LittleEndian.Uint32(n[12:])
520	return r.StringAt(off, len)
521}
522
523func (n *RefName) SetSym(x SymRef) {
524	binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
525	binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
526}
527func (n *RefName) SetName(x string, w *Writer) {
528	binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
529	binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
530}
531
532func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
533
534type Writer struct {
535	wr        *bio.Writer
536	stringMap map[string]uint32
537	off       uint32 // running offset
538
539	b [8]byte // scratch space for writing bytes
540}
541
542func NewWriter(wr *bio.Writer) *Writer {
543	return &Writer{wr: wr, stringMap: make(map[string]uint32)}
544}
545
546func (w *Writer) AddString(s string) {
547	if _, ok := w.stringMap[s]; ok {
548		return
549	}
550	w.stringMap[s] = w.off
551	w.RawString(s)
552}
553
554func (w *Writer) stringOff(s string) uint32 {
555	off, ok := w.stringMap[s]
556	if !ok {
557		panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
558	}
559	return off
560}
561
562func (w *Writer) StringRef(s string) {
563	w.Uint32(uint32(len(s)))
564	w.Uint32(w.stringOff(s))
565}
566
567func (w *Writer) RawString(s string) {
568	w.wr.WriteString(s)
569	w.off += uint32(len(s))
570}
571
572func (w *Writer) Bytes(s []byte) {
573	w.wr.Write(s)
574	w.off += uint32(len(s))
575}
576
577func (w *Writer) Uint64(x uint64) {
578	binary.LittleEndian.PutUint64(w.b[:], x)
579	w.wr.Write(w.b[:])
580	w.off += 8
581}
582
583func (w *Writer) Uint32(x uint32) {
584	binary.LittleEndian.PutUint32(w.b[:4], x)
585	w.wr.Write(w.b[:4])
586	w.off += 4
587}
588
589func (w *Writer) Uint16(x uint16) {
590	binary.LittleEndian.PutUint16(w.b[:2], x)
591	w.wr.Write(w.b[:2])
592	w.off += 2
593}
594
595func (w *Writer) Uint8(x uint8) {
596	w.wr.WriteByte(x)
597	w.off++
598}
599
600func (w *Writer) Offset() uint32 {
601	return w.off
602}
603
604type Reader struct {
605	b        []byte // mmapped bytes, if not nil
606	readonly bool   // whether b is backed with read-only memory
607
608	start uint32
609	h     Header // keep block offsets
610}
611
612func NewReaderFromBytes(b []byte, readonly bool) *Reader {
613	r := &Reader{b: b, readonly: readonly, start: 0}
614	err := r.h.Read(r)
615	if err != nil {
616		return nil
617	}
618	return r
619}
620
621func (r *Reader) BytesAt(off uint32, len int) []byte {
622	if len == 0 {
623		return nil
624	}
625	end := int(off) + len
626	return r.b[int(off):end:end]
627}
628
629func (r *Reader) uint64At(off uint32) uint64 {
630	b := r.BytesAt(off, 8)
631	return binary.LittleEndian.Uint64(b)
632}
633
634func (r *Reader) int64At(off uint32) int64 {
635	return int64(r.uint64At(off))
636}
637
638func (r *Reader) uint32At(off uint32) uint32 {
639	b := r.BytesAt(off, 4)
640	return binary.LittleEndian.Uint32(b)
641}
642
643func (r *Reader) int32At(off uint32) int32 {
644	return int32(r.uint32At(off))
645}
646
647func (r *Reader) uint16At(off uint32) uint16 {
648	b := r.BytesAt(off, 2)
649	return binary.LittleEndian.Uint16(b)
650}
651
652func (r *Reader) uint8At(off uint32) uint8 {
653	b := r.BytesAt(off, 1)
654	return b[0]
655}
656
657func (r *Reader) StringAt(off uint32, len uint32) string {
658	b := r.b[off : off+len]
659	if r.readonly {
660		return toString(b) // backed by RO memory, ok to make unsafe string
661	}
662	return string(b)
663}
664
665func toString(b []byte) string {
666	if len(b) == 0 {
667		return ""
668	}
669	return unsafe.String(&b[0], len(b))
670}
671
672func (r *Reader) StringRef(off uint32) string {
673	l := r.uint32At(off)
674	return r.StringAt(r.uint32At(off+4), l)
675}
676
677func (r *Reader) Fingerprint() FingerprintType {
678	return r.h.Fingerprint
679}
680
681func (r *Reader) Autolib() []ImportedPkg {
682	n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
683	s := make([]ImportedPkg, n)
684	off := r.h.Offsets[BlkAutolib]
685	for i := range s {
686		s[i].Pkg = r.StringRef(off)
687		copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
688		off += importedPkgSize
689	}
690	return s
691}
692
693func (r *Reader) Pkglist() []string {
694	n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
695	s := make([]string, n)
696	off := r.h.Offsets[BlkPkgIdx]
697	for i := range s {
698		s[i] = r.StringRef(off)
699		off += stringRefSize
700	}
701	return s
702}
703
704func (r *Reader) NPkg() int {
705	return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
706}
707
708func (r *Reader) Pkg(i int) string {
709	off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
710	return r.StringRef(off)
711}
712
713func (r *Reader) NFile() int {
714	return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
715}
716
717func (r *Reader) File(i int) string {
718	off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
719	return r.StringRef(off)
720}
721
722func (r *Reader) NSym() int {
723	return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
724}
725
726func (r *Reader) NHashed64def() int {
727	return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
728}
729
730func (r *Reader) NHasheddef() int {
731	return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
732}
733
734func (r *Reader) NNonpkgdef() int {
735	return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
736}
737
738func (r *Reader) NNonpkgref() int {
739	return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
740}
741
742// SymOff returns the offset of the i-th symbol.
743func (r *Reader) SymOff(i uint32) uint32 {
744	return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
745}
746
747// Sym returns a pointer to the i-th symbol.
748func (r *Reader) Sym(i uint32) *Sym {
749	off := r.SymOff(i)
750	return (*Sym)(unsafe.Pointer(&r.b[off]))
751}
752
753// NRefFlags returns the number of referenced symbol flags.
754func (r *Reader) NRefFlags() int {
755	return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
756}
757
758// RefFlags returns a pointer to the i-th referenced symbol flags.
759// Note: here i is not a local symbol index, just a counter.
760func (r *Reader) RefFlags(i int) *RefFlags {
761	off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
762	return (*RefFlags)(unsafe.Pointer(&r.b[off]))
763}
764
765// Hash64 returns the i-th short hashed symbol's hash.
766// Note: here i is the index of short hashed symbols, not all symbols
767// (unlike other accessors).
768func (r *Reader) Hash64(i uint32) uint64 {
769	off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
770	return r.uint64At(off)
771}
772
773// Hash returns a pointer to the i-th hashed symbol's hash.
774// Note: here i is the index of hashed symbols, not all symbols
775// (unlike other accessors).
776func (r *Reader) Hash(i uint32) *HashType {
777	off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
778	return (*HashType)(unsafe.Pointer(&r.b[off]))
779}
780
781// NReloc returns the number of relocations of the i-th symbol.
782func (r *Reader) NReloc(i uint32) int {
783	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
784	return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
785}
786
787// RelocOff returns the offset of the j-th relocation of the i-th symbol.
788func (r *Reader) RelocOff(i uint32, j int) uint32 {
789	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
790	relocIdx := r.uint32At(relocIdxOff)
791	return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
792}
793
794// Reloc returns a pointer to the j-th relocation of the i-th symbol.
795func (r *Reader) Reloc(i uint32, j int) *Reloc {
796	off := r.RelocOff(i, j)
797	return (*Reloc)(unsafe.Pointer(&r.b[off]))
798}
799
800// Relocs returns a pointer to the relocations of the i-th symbol.
801func (r *Reader) Relocs(i uint32) []Reloc {
802	off := r.RelocOff(i, 0)
803	n := r.NReloc(i)
804	return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
805}
806
807// NAux returns the number of aux symbols of the i-th symbol.
808func (r *Reader) NAux(i uint32) int {
809	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
810	return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
811}
812
813// AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
814func (r *Reader) AuxOff(i uint32, j int) uint32 {
815	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
816	auxIdx := r.uint32At(auxIdxOff)
817	return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
818}
819
820// Aux returns a pointer to the j-th aux symbol of the i-th symbol.
821func (r *Reader) Aux(i uint32, j int) *Aux {
822	off := r.AuxOff(i, j)
823	return (*Aux)(unsafe.Pointer(&r.b[off]))
824}
825
826// Auxs returns the aux symbols of the i-th symbol.
827func (r *Reader) Auxs(i uint32) []Aux {
828	off := r.AuxOff(i, 0)
829	n := r.NAux(i)
830	return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
831}
832
833// DataOff returns the offset of the i-th symbol's data.
834func (r *Reader) DataOff(i uint32) uint32 {
835	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
836	return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
837}
838
839// DataSize returns the size of the i-th symbol's data.
840func (r *Reader) DataSize(i uint32) int {
841	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
842	return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
843}
844
845// Data returns the i-th symbol's data.
846func (r *Reader) Data(i uint32) []byte {
847	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
848	base := r.h.Offsets[BlkData]
849	off := r.uint32At(dataIdxOff)
850	end := r.uint32At(dataIdxOff + 4)
851	return r.BytesAt(base+off, int(end-off))
852}
853
854// DataString returns the i-th symbol's data as a string.
855func (r *Reader) DataString(i uint32) string {
856	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
857	base := r.h.Offsets[BlkData]
858	off := r.uint32At(dataIdxOff)
859	end := r.uint32At(dataIdxOff + 4)
860	return r.StringAt(base+off, end-off)
861}
862
863// NRefName returns the number of referenced symbol names.
864func (r *Reader) NRefName() int {
865	return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
866}
867
868// RefName returns a pointer to the i-th referenced symbol name.
869// Note: here i is not a local symbol index, just a counter.
870func (r *Reader) RefName(i int) *RefName {
871	off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
872	return (*RefName)(unsafe.Pointer(&r.b[off]))
873}
874
875// ReadOnly returns whether r.BytesAt returns read-only bytes.
876func (r *Reader) ReadOnly() bool {
877	return r.readonly
878}
879
880// Flags returns the flag bits read from the object file header.
881func (r *Reader) Flags() uint32 {
882	return r.h.Flags
883}
884
885func (r *Reader) Shared() bool       { return r.Flags()&ObjFlagShared != 0 }
886func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }
887func (r *Reader) Unlinkable() bool   { return r.Flags()&ObjFlagUnlinkable != 0 }
888func (r *Reader) Std() bool          { return r.Flags()&ObjFlagStd != 0 }
889