objfile.go raw
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
19 package goobj
20
21 import (
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
171 const stringRefSize = 8 // two uint32s
172
173 type FingerprintType [8]byte
174
175 func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
176
177 // Package Index.
178 const (
179 PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
180 PkgIdxHashed64 // Short hashed (content-addressable) symbols
181 PkgIdxHashed // Hashed (content-addressable) symbols
182 PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject)
183 PkgIdxSelf // Symbols defined in the current package
184 PkgIdxInvalid = 0
185 // The index of other referenced packages starts from 1.
186 )
187
188 // Blocks
189 const (
190 BlkAutolib = iota
191 BlkPkgIdx
192 BlkFile
193 BlkSymdef
194 BlkHashed64def
195 BlkHasheddef
196 BlkNonpkgdef
197 BlkNonpkgref
198 BlkRefFlags
199 BlkHash64
200 BlkHash
201 BlkRelocIdx
202 BlkAuxIdx
203 BlkDataIdx
204 BlkReloc
205 BlkAux
206 BlkData
207 BlkPcdata
208 BlkRefName
209 BlkEnd
210 NBlk
211 )
212
213 // File header.
214 // TODO: probably no need to export this.
215 type Header struct {
216 Magic string
217 Fingerprint FingerprintType
218 Flags uint32
219 Offsets [NBlk]uint32
220 }
221
222 const Magic = "\x00go116ld"
223
224 func (h *Header) Write(w *Writer) {
225 w.RawString(h.Magic)
226 w.Bytes(h.Fingerprint[:])
227 w.Uint32(h.Flags)
228 for _, x := range h.Offsets {
229 w.Uint32(x)
230 }
231 }
232
233 func (h *Header) Read(r *Reader) error {
234 b := r.BytesAt(0, len(Magic))
235 h.Magic = string(b)
236 if h.Magic != Magic {
237 return errors.New("wrong magic, not a Go object file")
238 }
239 off := uint32(len(h.Magic))
240 copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
241 off += 8
242 h.Flags = r.uint32At(off)
243 off += 4
244 for i := range h.Offsets {
245 h.Offsets[i] = r.uint32At(off)
246 off += 4
247 }
248 return nil
249 }
250
251 func (h *Header) Size() int {
252 return len(h.Magic) + 4 + 4*len(h.Offsets)
253 }
254
255 // Autolib
256 type ImportedPkg struct {
257 Pkg string
258 Fingerprint FingerprintType
259 }
260
261 const importedPkgSize = stringRefSize + 8
262
263 func (p *ImportedPkg) Write(w *Writer) {
264 w.StringRef(p.Pkg)
265 w.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 // }
280 type Sym [SymSize]byte
281
282 const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4
283
284 const SymABIstatic = ^uint16(0)
285
286 const (
287 ObjFlagShared = 1 << iota // this object is built with -shared
288 ObjFlagNeedNameExpansion // the linker needs to expand `"".` to package path in symbol names
289 ObjFlagFromAssembly // object is from asm src, not go
290 )
291
292 // Sym.Flag
293 const (
294 SymFlagDupok = 1 << iota
295 SymFlagLocal
296 SymFlagTypelink
297 SymFlagLeaf
298 SymFlagNoSplit
299 SymFlagReflectMethod
300 SymFlagGoType
301 SymFlagTopFrame
302 )
303
304 // Sym.Flag2
305 const (
306 SymFlagUsedInIface = 1 << iota
307 SymFlagItab
308 )
309
310 // Returns the length of the name of the symbol.
311 func (s *Sym) NameLen(r *Reader) int {
312 return int(binary.LittleEndian.Uint32(s[:]))
313 }
314
315 func (s *Sym) Name(r *Reader) string {
316 len := binary.LittleEndian.Uint32(s[:])
317 off := binary.LittleEndian.Uint32(s[4:])
318 return r.StringAt(off, len)
319 }
320
321 func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) }
322 func (s *Sym) Type() uint8 { return s[10] }
323 func (s *Sym) Flag() uint8 { return s[11] }
324 func (s *Sym) Flag2() uint8 { return s[12] }
325 func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) }
326 func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
327
328 func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 }
329 func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 }
330 func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 }
331 func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 }
332 func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 }
333 func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
334 func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 }
335 func (s *Sym) TopFrame() bool { return s.Flag()&SymFlagTopFrame != 0 }
336 func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 }
337 func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 }
338
339 func (s *Sym) SetName(x string, w *Writer) {
340 binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
341 binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
342 }
343
344 func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) }
345 func (s *Sym) SetType(x uint8) { s[10] = x }
346 func (s *Sym) SetFlag(x uint8) { s[11] = x }
347 func (s *Sym) SetFlag2(x uint8) { s[12] = x }
348 func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) }
349 func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
350
351 func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
352
353 // for testing
354 func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
355
356 // Symbol reference.
357 type SymRef struct {
358 PkgIdx uint32
359 SymIdx uint32
360 }
361
362 // Hash64
363 type Hash64Type [Hash64Size]byte
364
365 const Hash64Size = 8
366
367 // Hash
368 type HashType [HashSize]byte
369
370 const 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 // }
382 type Reloc [RelocSize]byte
383
384 const RelocSize = 4 + 1 + 1 + 8 + 8
385
386 func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) }
387 func (r *Reloc) Siz() uint8 { return r[4] }
388 func (r *Reloc) Type() uint8 { return r[5] }
389 func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) }
390 func (r *Reloc) Sym() SymRef {
391 return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])}
392 }
393
394 func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
395 func (r *Reloc) SetSiz(x uint8) { r[4] = x }
396 func (r *Reloc) SetType(x uint8) { r[5] = x }
397 func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[6:], uint64(x)) }
398 func (r *Reloc) SetSym(x SymRef) {
399 binary.LittleEndian.PutUint32(r[14:], x.PkgIdx)
400 binary.LittleEndian.PutUint32(r[18:], x.SymIdx)
401 }
402
403 func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) {
404 r.SetOff(off)
405 r.SetSiz(size)
406 r.SetType(typ)
407 r.SetAdd(add)
408 r.SetSym(sym)
409 }
410
411 func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
412
413 // for testing
414 func (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 // }
423 type Aux [AuxSize]byte
424
425 const AuxSize = 1 + 8
426
427 // Aux Type
428 const (
429 AuxGotype = iota
430 AuxFuncInfo
431 AuxFuncdata
432 AuxDwarfInfo
433 AuxDwarfLoc
434 AuxDwarfRanges
435 AuxDwarfLines
436
437 // TODO: more. Pcdata?
438 )
439
440 func (a *Aux) Type() uint8 { return a[0] }
441 func (a *Aux) Sym() SymRef {
442 return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
443 }
444
445 func (a *Aux) SetType(x uint8) { a[0] = x }
446 func (a *Aux) SetSym(x SymRef) {
447 binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
448 binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
449 }
450
451 func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
452
453 // for testing
454 func (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 // }
464 type RefFlags [RefFlagsSize]byte
465
466 const RefFlagsSize = 8 + 1 + 1
467
468 func (r *RefFlags) Sym() SymRef {
469 return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
470 }
471 func (r *RefFlags) Flag() uint8 { return r[8] }
472 func (r *RefFlags) Flag2() uint8 { return r[9] }
473
474 func (r *RefFlags) SetSym(x SymRef) {
475 binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
476 binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
477 }
478 func (r *RefFlags) SetFlag(x uint8) { r[8] = x }
479 func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
480
481 func (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 // }
490 type RefName [RefNameSize]byte
491
492 const RefNameSize = 8 + stringRefSize
493
494 func (n *RefName) Sym() SymRef {
495 return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
496 }
497 func (n *RefName) Name(r *Reader) string {
498 len := binary.LittleEndian.Uint32(n[8:])
499 off := binary.LittleEndian.Uint32(n[12:])
500 return r.StringAt(off, len)
501 }
502
503 func (n *RefName) SetSym(x SymRef) {
504 binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
505 binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
506 }
507 func (n *RefName) SetName(x string, w *Writer) {
508 binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
509 binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
510 }
511
512 func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
513
514 type Writer struct {
515 wr *bio.Writer
516 stringMap map[string]uint32
517 off uint32 // running offset
518 }
519
520 func NewWriter(wr *bio.Writer) *Writer {
521 return &Writer{wr: wr, stringMap: make(map[string]uint32)}
522 }
523
524 func (w *Writer) AddString(s string) {
525 if _, ok := w.stringMap[s]; ok {
526 return
527 }
528 w.stringMap[s] = w.off
529 w.RawString(s)
530 }
531
532 func (w *Writer) stringOff(s string) uint32 {
533 off, ok := w.stringMap[s]
534 if !ok {
535 panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
536 }
537 return off
538 }
539
540 func (w *Writer) StringRef(s string) {
541 w.Uint32(uint32(len(s)))
542 w.Uint32(w.stringOff(s))
543 }
544
545 func (w *Writer) RawString(s string) {
546 w.wr.WriteString(s)
547 w.off += uint32(len(s))
548 }
549
550 func (w *Writer) Bytes(s []byte) {
551 w.wr.Write(s)
552 w.off += uint32(len(s))
553 }
554
555 func (w *Writer) Uint64(x uint64) {
556 var b [8]byte
557 binary.LittleEndian.PutUint64(b[:], x)
558 w.wr.Write(b[:])
559 w.off += 8
560 }
561
562 func (w *Writer) Uint32(x uint32) {
563 var b [4]byte
564 binary.LittleEndian.PutUint32(b[:], x)
565 w.wr.Write(b[:])
566 w.off += 4
567 }
568
569 func (w *Writer) Uint16(x uint16) {
570 var b [2]byte
571 binary.LittleEndian.PutUint16(b[:], x)
572 w.wr.Write(b[:])
573 w.off += 2
574 }
575
576 func (w *Writer) Uint8(x uint8) {
577 w.wr.WriteByte(x)
578 w.off++
579 }
580
581 func (w *Writer) Offset() uint32 {
582 return w.off
583 }
584
585 type Reader struct {
586 b []byte // mmapped bytes, if not nil
587 readonly bool // whether b is backed with read-only memory
588
589 rd io.ReaderAt
590 start uint32
591 h Header // keep block offsets
592 }
593
594 func NewReaderFromBytes(b []byte, readonly bool) *Reader {
595 r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
596 err := r.h.Read(r)
597 if err != nil {
598 return nil
599 }
600 return r
601 }
602
603 func (r *Reader) BytesAt(off uint32, len int) []byte {
604 if len == 0 {
605 return nil
606 }
607 end := int(off) + len
608 return r.b[int(off):end:end]
609 }
610
611 func (r *Reader) uint64At(off uint32) uint64 {
612 b := r.BytesAt(off, 8)
613 return binary.LittleEndian.Uint64(b)
614 }
615
616 func (r *Reader) int64At(off uint32) int64 {
617 return int64(r.uint64At(off))
618 }
619
620 func (r *Reader) uint32At(off uint32) uint32 {
621 b := r.BytesAt(off, 4)
622 return binary.LittleEndian.Uint32(b)
623 }
624
625 func (r *Reader) int32At(off uint32) int32 {
626 return int32(r.uint32At(off))
627 }
628
629 func (r *Reader) uint16At(off uint32) uint16 {
630 b := r.BytesAt(off, 2)
631 return binary.LittleEndian.Uint16(b)
632 }
633
634 func (r *Reader) uint8At(off uint32) uint8 {
635 b := r.BytesAt(off, 1)
636 return b[0]
637 }
638
639 func (r *Reader) StringAt(off uint32, len uint32) string {
640 b := r.b[off : off+len]
641 if r.readonly {
642 return toString(b) // backed by RO memory, ok to make unsafe string
643 }
644 return string(b)
645 }
646
647 func toString(b []byte) string {
648 if len(b) == 0 {
649 return ""
650 }
651
652 var s string
653 hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
654 hdr.Data = unsafe.Pointer(&b[0])
655 hdr.Len = len(b)
656
657 return s
658 }
659
660 func (r *Reader) StringRef(off uint32) string {
661 l := r.uint32At(off)
662 return r.StringAt(r.uint32At(off+4), l)
663 }
664
665 func (r *Reader) Fingerprint() FingerprintType {
666 return r.h.Fingerprint
667 }
668
669 func (r *Reader) Autolib() []ImportedPkg {
670 n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
671 s := make([]ImportedPkg, n)
672 off := r.h.Offsets[BlkAutolib]
673 for i := range s {
674 s[i].Pkg = r.StringRef(off)
675 copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
676 off += importedPkgSize
677 }
678 return s
679 }
680
681 func (r *Reader) Pkglist() []string {
682 n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
683 s := make([]string, n)
684 off := r.h.Offsets[BlkPkgIdx]
685 for i := range s {
686 s[i] = r.StringRef(off)
687 off += stringRefSize
688 }
689 return s
690 }
691
692 func (r *Reader) NPkg() int {
693 return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
694 }
695
696 func (r *Reader) Pkg(i int) string {
697 off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
698 return r.StringRef(off)
699 }
700
701 func (r *Reader) NFile() int {
702 return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
703 }
704
705 func (r *Reader) File(i int) string {
706 off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
707 return r.StringRef(off)
708 }
709
710 func (r *Reader) NSym() int {
711 return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
712 }
713
714 func (r *Reader) NHashed64def() int {
715 return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
716 }
717
718 func (r *Reader) NHasheddef() int {
719 return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
720 }
721
722 func (r *Reader) NNonpkgdef() int {
723 return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
724 }
725
726 func (r *Reader) NNonpkgref() int {
727 return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
728 }
729
730 // SymOff returns the offset of the i-th symbol.
731 func (r *Reader) SymOff(i uint32) uint32 {
732 return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
733 }
734
735 // Sym returns a pointer to the i-th symbol.
736 func (r *Reader) Sym(i uint32) *Sym {
737 off := r.SymOff(i)
738 return (*Sym)(unsafe.Pointer(&r.b[off]))
739 }
740
741 // NRefFlags returns the number of referenced symbol flags.
742 func (r *Reader) NRefFlags() int {
743 return 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.
748 func (r *Reader) RefFlags(i int) *RefFlags {
749 off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
750 return (*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).
756 func (r *Reader) Hash64(i uint32) uint64 {
757 off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
758 return 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).
764 func (r *Reader) Hash(i uint32) *HashType {
765 off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
766 return (*HashType)(unsafe.Pointer(&r.b[off]))
767 }
768
769 // NReloc returns the number of relocations of the i-th symbol.
770 func (r *Reader) NReloc(i uint32) int {
771 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
772 return 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.
776 func (r *Reader) RelocOff(i uint32, j int) uint32 {
777 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
778 relocIdx := r.uint32At(relocIdxOff)
779 return 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.
783 func (r *Reader) Reloc(i uint32, j int) *Reloc {
784 off := r.RelocOff(i, j)
785 return (*Reloc)(unsafe.Pointer(&r.b[off]))
786 }
787
788 // Relocs returns a pointer to the relocations of the i-th symbol.
789 func (r *Reader) Relocs(i uint32) []Reloc {
790 off := r.RelocOff(i, 0)
791 n := r.NReloc(i)
792 return (*[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.
796 func (r *Reader) NAux(i uint32) int {
797 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
798 return 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.
802 func (r *Reader) AuxOff(i uint32, j int) uint32 {
803 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
804 auxIdx := r.uint32At(auxIdxOff)
805 return 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.
809 func (r *Reader) Aux(i uint32, j int) *Aux {
810 off := r.AuxOff(i, j)
811 return (*Aux)(unsafe.Pointer(&r.b[off]))
812 }
813
814 // Auxs returns the aux symbols of the i-th symbol.
815 func (r *Reader) Auxs(i uint32) []Aux {
816 off := r.AuxOff(i, 0)
817 n := r.NAux(i)
818 return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
819 }
820
821 // DataOff returns the offset of the i-th symbol's data.
822 func (r *Reader) DataOff(i uint32) uint32 {
823 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
824 return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
825 }
826
827 // DataSize returns the size of the i-th symbol's data.
828 func (r *Reader) DataSize(i uint32) int {
829 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
830 return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
831 }
832
833 // Data returns the i-th symbol's data.
834 func (r *Reader) Data(i uint32) []byte {
835 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
836 base := r.h.Offsets[BlkData]
837 off := r.uint32At(dataIdxOff)
838 end := r.uint32At(dataIdxOff + 4)
839 return r.BytesAt(base+off, int(end-off))
840 }
841
842 // AuxDataBase returns the base offset of the aux data block.
843 func (r *Reader) PcdataBase() uint32 {
844 return r.h.Offsets[BlkPcdata]
845 }
846
847 // NRefName returns the number of referenced symbol names.
848 func (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.
854 func (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.
860 func (r *Reader) ReadOnly() bool {
861 return r.readonly
862 }
863
864 // Flags returns the flag bits read from the object file header.
865 func (r *Reader) Flags() uint32 {
866 return r.h.Flags
867 }
868
869 func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 }
870 func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 }
871 func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }
872