1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package goobj
20
21 import (
22 "cmd/internal/bio"
23 "encoding/binary"
24 "errors"
25 "fmt"
26 "unsafe"
27 )
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166 const stringRefSize = 8
167
168 type FingerprintType [8]byte
169
170 func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
171
172
173 const (
174 PkgIdxNone = (1<<31 - 1) - iota
175 PkgIdxHashed64
176 PkgIdxHashed
177 PkgIdxBuiltin
178 PkgIdxSelf
179 PkgIdxSpecial = PkgIdxSelf
180 PkgIdxInvalid = 0
181
182 )
183
184
185 const (
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
209
210 type Header struct {
211 Magic string
212 Fingerprint FingerprintType
213 Flags uint32
214 Offsets [NBlk]uint32
215 }
216
217 const Magic = "\x00go120ld"
218
219 func (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
228 func (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
246 func (h *Header) Size() int {
247 return len(h.Magic) + len(h.Fingerprint) + 4 + 4*len(h.Offsets)
248 }
249
250
251 type ImportedPkg struct {
252 Pkg string
253 Fingerprint FingerprintType
254 }
255
256 const importedPkgSize = stringRefSize + 8
257
258 func (p *ImportedPkg) Write(w *Writer) {
259 w.StringRef(p.Pkg)
260 w.Bytes(p.Fingerprint[:])
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276 type Sym [SymSize]byte
277
278 const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4
279
280 const SymABIstatic = ^uint16(0)
281
282 const (
283 ObjFlagShared = 1 << iota
284 _
285 ObjFlagFromAssembly
286 ObjFlagUnlinkable
287 )
288
289
290 const (
291 SymFlagDupok = 1 << iota
292 SymFlagLocal
293 SymFlagTypelink
294 SymFlagLeaf
295 SymFlagNoSplit
296 SymFlagReflectMethod
297 SymFlagGoType
298 )
299
300
301 const (
302 SymFlagUsedInIface = 1 << iota
303 SymFlagItab
304 SymFlagDict
305 SymFlagPkgInit
306 )
307
308
309 func (s *Sym) NameLen(r *Reader) int {
310 return int(binary.LittleEndian.Uint32(s[:]))
311 }
312
313 func (s *Sym) Name(r *Reader) string {
314 len := binary.LittleEndian.Uint32(s[:])
315 off := binary.LittleEndian.Uint32(s[4:])
316 return r.StringAt(off, len)
317 }
318
319 func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) }
320 func (s *Sym) Type() uint8 { return s[10] }
321 func (s *Sym) Flag() uint8 { return s[11] }
322 func (s *Sym) Flag2() uint8 { return s[12] }
323 func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) }
324 func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
325
326 func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 }
327 func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 }
328 func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 }
329 func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 }
330 func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 }
331 func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
332 func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 }
333 func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 }
334 func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 }
335 func (s *Sym) IsDict() bool { return s.Flag2()&SymFlagDict != 0 }
336 func (s *Sym) IsPkgInit() bool { return s.Flag2()&SymFlagPkgInit != 0 }
337
338 func (s *Sym) SetName(x string, w *Writer) {
339 binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
340 binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
341 }
342
343 func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) }
344 func (s *Sym) SetType(x uint8) { s[10] = x }
345 func (s *Sym) SetFlag(x uint8) { s[11] = x }
346 func (s *Sym) SetFlag2(x uint8) { s[12] = x }
347 func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) }
348 func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
349
350 func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
351
352
353 func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
354
355
356 type SymRef struct {
357 PkgIdx uint32
358 SymIdx uint32
359 }
360
361 func (s SymRef) IsZero() bool { return s == SymRef{} }
362
363
364 type Hash64Type [Hash64Size]byte
365
366 const Hash64Size = 8
367
368
369 type HashType [HashSize]byte
370
371 const HashSize = 16
372
373
374
375
376
377
378
379
380
381
382
383
384 type Reloc [RelocSize]byte
385
386 const RelocSize = 4 + 1 + 2 + 8 + 8
387
388 func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) }
389 func (r *Reloc) Siz() uint8 { return r[4] }
390 func (r *Reloc) Type() uint16 { return binary.LittleEndian.Uint16(r[5:]) }
391 func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[7:])) }
392 func (r *Reloc) Sym() SymRef {
393 return SymRef{binary.LittleEndian.Uint32(r[15:]), binary.LittleEndian.Uint32(r[19:])}
394 }
395
396 func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
397 func (r *Reloc) SetSiz(x uint8) { r[4] = x }
398 func (r *Reloc) SetType(x uint16) { binary.LittleEndian.PutUint16(r[5:], x) }
399 func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[7:], uint64(x)) }
400 func (r *Reloc) SetSym(x SymRef) {
401 binary.LittleEndian.PutUint32(r[15:], x.PkgIdx)
402 binary.LittleEndian.PutUint32(r[19:], x.SymIdx)
403 }
404
405 func (r *Reloc) Set(off int32, size uint8, typ uint16, add int64, sym SymRef) {
406 r.SetOff(off)
407 r.SetSiz(size)
408 r.SetType(typ)
409 r.SetAdd(add)
410 r.SetSym(sym)
411 }
412
413 func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
414
415
416 func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
417
418
419
420
421
422
423
424
425
426 type Aux [AuxSize]byte
427
428 const AuxSize = 1 + 8
429
430
431 const (
432 AuxGotype = iota
433 AuxFuncInfo
434 AuxFuncdata
435 AuxDwarfInfo
436 AuxDwarfLoc
437 AuxDwarfRanges
438 AuxDwarfLines
439 AuxPcsp
440 AuxPcfile
441 AuxPcline
442 AuxPcinline
443 AuxPcdata
444 AuxWasmImport
445 AuxSehUnwindInfo
446 )
447
448 func (a *Aux) Type() uint8 { return a[0] }
449 func (a *Aux) Sym() SymRef {
450 return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
451 }
452
453 func (a *Aux) SetType(x uint8) { a[0] = x }
454 func (a *Aux) SetSym(x SymRef) {
455 binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
456 binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
457 }
458
459 func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
460
461
462 func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
463
464
465
466
467
468
469
470
471
472
473 type RefFlags [RefFlagsSize]byte
474
475 const RefFlagsSize = 8 + 1 + 1
476
477 func (r *RefFlags) Sym() SymRef {
478 return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
479 }
480 func (r *RefFlags) Flag() uint8 { return r[8] }
481 func (r *RefFlags) Flag2() uint8 { return r[9] }
482
483 func (r *RefFlags) SetSym(x SymRef) {
484 binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
485 binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
486 }
487 func (r *RefFlags) SetFlag(x uint8) { r[8] = x }
488 func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
489
490 func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
491
492
493
494
495 const huge = (1<<31 - 1) / RelocSize
496
497
498
499
500
501
502
503
504
505 type RefName [RefNameSize]byte
506
507 const RefNameSize = 8 + stringRefSize
508
509 func (n *RefName) Sym() SymRef {
510 return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
511 }
512 func (n *RefName) Name(r *Reader) string {
513 len := binary.LittleEndian.Uint32(n[8:])
514 off := binary.LittleEndian.Uint32(n[12:])
515 return r.StringAt(off, len)
516 }
517
518 func (n *RefName) SetSym(x SymRef) {
519 binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
520 binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
521 }
522 func (n *RefName) SetName(x string, w *Writer) {
523 binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
524 binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
525 }
526
527 func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
528
529 type Writer struct {
530 wr *bio.Writer
531 stringMap map[string]uint32
532 off uint32
533
534 b [8]byte
535 }
536
537 func NewWriter(wr *bio.Writer) *Writer {
538 return &Writer{wr: wr, stringMap: make(map[string]uint32)}
539 }
540
541 func (w *Writer) AddString(s string) {
542 if _, ok := w.stringMap[s]; ok {
543 return
544 }
545 w.stringMap[s] = w.off
546 w.RawString(s)
547 }
548
549 func (w *Writer) stringOff(s string) uint32 {
550 off, ok := w.stringMap[s]
551 if !ok {
552 panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
553 }
554 return off
555 }
556
557 func (w *Writer) StringRef(s string) {
558 w.Uint32(uint32(len(s)))
559 w.Uint32(w.stringOff(s))
560 }
561
562 func (w *Writer) RawString(s string) {
563 w.wr.WriteString(s)
564 w.off += uint32(len(s))
565 }
566
567 func (w *Writer) Bytes(s []byte) {
568 w.wr.Write(s)
569 w.off += uint32(len(s))
570 }
571
572 func (w *Writer) Uint64(x uint64) {
573 binary.LittleEndian.PutUint64(w.b[:], x)
574 w.wr.Write(w.b[:])
575 w.off += 8
576 }
577
578 func (w *Writer) Uint32(x uint32) {
579 binary.LittleEndian.PutUint32(w.b[:4], x)
580 w.wr.Write(w.b[:4])
581 w.off += 4
582 }
583
584 func (w *Writer) Uint16(x uint16) {
585 binary.LittleEndian.PutUint16(w.b[:2], x)
586 w.wr.Write(w.b[:2])
587 w.off += 2
588 }
589
590 func (w *Writer) Uint8(x uint8) {
591 w.wr.WriteByte(x)
592 w.off++
593 }
594
595 func (w *Writer) Offset() uint32 {
596 return w.off
597 }
598
599 type Reader struct {
600 b []byte
601 readonly bool
602
603 start uint32
604 h Header
605 }
606
607 func NewReaderFromBytes(b []byte, readonly bool) *Reader {
608 r := &Reader{b: b, readonly: readonly, start: 0}
609 err := r.h.Read(r)
610 if err != nil {
611 return nil
612 }
613 return r
614 }
615
616 func (r *Reader) BytesAt(off uint32, len int) []byte {
617 if len == 0 {
618 return nil
619 }
620 end := int(off) + len
621 return r.b[int(off):end:end]
622 }
623
624 func (r *Reader) uint64At(off uint32) uint64 {
625 b := r.BytesAt(off, 8)
626 return binary.LittleEndian.Uint64(b)
627 }
628
629 func (r *Reader) int64At(off uint32) int64 {
630 return int64(r.uint64At(off))
631 }
632
633 func (r *Reader) uint32At(off uint32) uint32 {
634 b := r.BytesAt(off, 4)
635 return binary.LittleEndian.Uint32(b)
636 }
637
638 func (r *Reader) int32At(off uint32) int32 {
639 return int32(r.uint32At(off))
640 }
641
642 func (r *Reader) uint16At(off uint32) uint16 {
643 b := r.BytesAt(off, 2)
644 return binary.LittleEndian.Uint16(b)
645 }
646
647 func (r *Reader) uint8At(off uint32) uint8 {
648 b := r.BytesAt(off, 1)
649 return b[0]
650 }
651
652 func (r *Reader) StringAt(off uint32, len uint32) string {
653 b := r.b[off : off+len]
654 if r.readonly {
655 return toString(b)
656 }
657 return string(b)
658 }
659
660 func toString(b []byte) string {
661 if len(b) == 0 {
662 return ""
663 }
664 return unsafe.String(&b[0], len(b))
665 }
666
667 func (r *Reader) StringRef(off uint32) string {
668 l := r.uint32At(off)
669 return r.StringAt(r.uint32At(off+4), l)
670 }
671
672 func (r *Reader) Fingerprint() FingerprintType {
673 return r.h.Fingerprint
674 }
675
676 func (r *Reader) Autolib() []ImportedPkg {
677 n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
678 s := make([]ImportedPkg, n)
679 off := r.h.Offsets[BlkAutolib]
680 for i := range s {
681 s[i].Pkg = r.StringRef(off)
682 copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
683 off += importedPkgSize
684 }
685 return s
686 }
687
688 func (r *Reader) Pkglist() []string {
689 n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
690 s := make([]string, n)
691 off := r.h.Offsets[BlkPkgIdx]
692 for i := range s {
693 s[i] = r.StringRef(off)
694 off += stringRefSize
695 }
696 return s
697 }
698
699 func (r *Reader) NPkg() int {
700 return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
701 }
702
703 func (r *Reader) Pkg(i int) string {
704 off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
705 return r.StringRef(off)
706 }
707
708 func (r *Reader) NFile() int {
709 return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
710 }
711
712 func (r *Reader) File(i int) string {
713 off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
714 return r.StringRef(off)
715 }
716
717 func (r *Reader) NSym() int {
718 return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
719 }
720
721 func (r *Reader) NHashed64def() int {
722 return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
723 }
724
725 func (r *Reader) NHasheddef() int {
726 return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
727 }
728
729 func (r *Reader) NNonpkgdef() int {
730 return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
731 }
732
733 func (r *Reader) NNonpkgref() int {
734 return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
735 }
736
737
738 func (r *Reader) SymOff(i uint32) uint32 {
739 return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
740 }
741
742
743 func (r *Reader) Sym(i uint32) *Sym {
744 off := r.SymOff(i)
745 return (*Sym)(unsafe.Pointer(&r.b[off]))
746 }
747
748
749 func (r *Reader) NRefFlags() int {
750 return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
751 }
752
753
754
755 func (r *Reader) RefFlags(i int) *RefFlags {
756 off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
757 return (*RefFlags)(unsafe.Pointer(&r.b[off]))
758 }
759
760
761
762
763 func (r *Reader) Hash64(i uint32) uint64 {
764 off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
765 return r.uint64At(off)
766 }
767
768
769
770
771 func (r *Reader) Hash(i uint32) *HashType {
772 off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
773 return (*HashType)(unsafe.Pointer(&r.b[off]))
774 }
775
776
777 func (r *Reader) NReloc(i uint32) int {
778 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
779 return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
780 }
781
782
783 func (r *Reader) RelocOff(i uint32, j int) uint32 {
784 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
785 relocIdx := r.uint32At(relocIdxOff)
786 return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
787 }
788
789
790 func (r *Reader) Reloc(i uint32, j int) *Reloc {
791 off := r.RelocOff(i, j)
792 return (*Reloc)(unsafe.Pointer(&r.b[off]))
793 }
794
795
796 func (r *Reader) Relocs(i uint32) []Reloc {
797 off := r.RelocOff(i, 0)
798 n := r.NReloc(i)
799 return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
800 }
801
802
803 func (r *Reader) NAux(i uint32) int {
804 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
805 return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
806 }
807
808
809 func (r *Reader) AuxOff(i uint32, j int) uint32 {
810 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
811 auxIdx := r.uint32At(auxIdxOff)
812 return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
813 }
814
815
816 func (r *Reader) Aux(i uint32, j int) *Aux {
817 off := r.AuxOff(i, j)
818 return (*Aux)(unsafe.Pointer(&r.b[off]))
819 }
820
821
822 func (r *Reader) Auxs(i uint32) []Aux {
823 off := r.AuxOff(i, 0)
824 n := r.NAux(i)
825 return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
826 }
827
828
829 func (r *Reader) DataOff(i uint32) uint32 {
830 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
831 return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
832 }
833
834
835 func (r *Reader) DataSize(i uint32) int {
836 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
837 return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
838 }
839
840
841 func (r *Reader) Data(i uint32) []byte {
842 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
843 base := r.h.Offsets[BlkData]
844 off := r.uint32At(dataIdxOff)
845 end := r.uint32At(dataIdxOff + 4)
846 return r.BytesAt(base+off, int(end-off))
847 }
848
849
850 func (r *Reader) DataString(i uint32) string {
851 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
852 base := r.h.Offsets[BlkData]
853 off := r.uint32At(dataIdxOff)
854 end := r.uint32At(dataIdxOff + 4)
855 return r.StringAt(base+off, end-off)
856 }
857
858
859 func (r *Reader) NRefName() int {
860 return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
861 }
862
863
864
865 func (r *Reader) RefName(i int) *RefName {
866 off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
867 return (*RefName)(unsafe.Pointer(&r.b[off]))
868 }
869
870
871 func (r *Reader) ReadOnly() bool {
872 return r.readonly
873 }
874
875
876 func (r *Reader) Flags() uint32 {
877 return r.h.Flags
878 }
879
880 func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 }
881 func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }
882 func (r *Reader) Unlinkable() bool { return r.Flags()&ObjFlagUnlinkable != 0 }
883
View as plain text