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