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