1
2
3
4
5
16 package elf
17
18 import (
19 "bytes"
20 "compress/zlib"
21 "debug/dwarf"
22 "encoding/binary"
23 "errors"
24 "fmt"
25 "internal/saferio"
26 "internal/zstd"
27 "io"
28 "os"
29 "strings"
30 )
31
32
33
34
37
38
39 type FileHeader struct {
40 Class Class
41 Data Data
42 Version Version
43 OSABI OSABI
44 ABIVersion uint8
45 ByteOrder binary.ByteOrder
46 Type Type
47 Machine Machine
48 Entry uint64
49 }
50
51
52 type File struct {
53 FileHeader
54 Sections []*Section
55 Progs []*Prog
56 closer io.Closer
57 gnuNeed []verneed
58 gnuVersym []byte
59 }
60
61
62 type SectionHeader struct {
63 Name string
64 Type SectionType
65 Flags SectionFlag
66 Addr uint64
67 Offset uint64
68 Size uint64
69 Link uint32
70 Info uint32
71 Addralign uint64
72 Entsize uint64
73
74
75
76
77
78 FileSize uint64
79 }
80
81
82 type Section struct {
83 SectionHeader
84
85
86
87
88
89
90
91
92
93
94
95 io.ReaderAt
96 sr *io.SectionReader
97
98 compressionType CompressionType
99 compressionOffset int64
100 }
101
102
103
104
105
106
107 func (s *Section) Data() ([]byte, error) {
108 return saferio.ReadData(s.Open(), s.Size)
109 }
110
111
112
113 func (f *File) stringTable(link uint32) ([]byte, error) {
114 if link <= 0 || link >= uint32(len(f.Sections)) {
115 return nil, errors.New("section has invalid string table link")
116 }
117 return f.Sections[link].Data()
118 }
119
120
121
122
123
124
125
126 func (s *Section) Open() io.ReadSeeker {
127 if s.Type == SHT_NOBITS {
128 return io.NewSectionReader(&nobitsSectionReader{}, 0, int64(s.Size))
129 }
130
131 var zrd func(io.Reader) (io.ReadCloser, error)
132 if s.Flags&SHF_COMPRESSED == 0 {
133
134 if !strings.HasPrefix(s.Name, ".zdebug") {
135 return io.NewSectionReader(s.sr, 0, 1<<63-1)
136 }
137
138 b := make([]byte, 12)
139 n, _ := s.sr.ReadAt(b, 0)
140 if n != 12 || string(b[:4]) != "ZLIB" {
141 return io.NewSectionReader(s.sr, 0, 1<<63-1)
142 }
143
144 s.compressionOffset = 12
145 s.compressionType = COMPRESS_ZLIB
146 s.Size = binary.BigEndian.Uint64(b[4:12])
147 zrd = zlib.NewReader
148
149 } else if s.Flags&SHF_ALLOC != 0 {
150 return errorReader{&FormatError{int64(s.Offset),
151 "SHF_COMPRESSED applies only to non-allocable sections", s.compressionType}}
152 }
153
154 switch s.compressionType {
155 case COMPRESS_ZLIB:
156 zrd = zlib.NewReader
157 case COMPRESS_ZSTD:
158 zrd = func(r io.Reader) (io.ReadCloser, error) {
159 return io.NopCloser(zstd.NewReader(r)), nil
160 }
161 }
162
163 if zrd == nil {
164 return errorReader{&FormatError{int64(s.Offset), "unknown compression type", s.compressionType}}
165 }
166
167 return &readSeekerFromReader{
168 reset: func() (io.Reader, error) {
169 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
170 return zrd(fr)
171 },
172 size: int64(s.Size),
173 }
174 }
175
176
177 type ProgHeader struct {
178 Type ProgType
179 Flags ProgFlag
180 Off uint64
181 Vaddr uint64
182 Paddr uint64
183 Filesz uint64
184 Memsz uint64
185 Align uint64
186 }
187
188
189 type Prog struct {
190 ProgHeader
191
192
193
194
195
196
197
198 io.ReaderAt
199 sr *io.SectionReader
200 }
201
202
203 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
204
205
206 type Symbol struct {
207 Name string
208 Info, Other byte
209 Section SectionIndex
210 Value, Size uint64
211
212
213
214 Version string
215 Library string
216 }
217
218
221
222 type FormatError struct {
223 off int64
224 msg string
225 val any
226 }
227
228 func (e *FormatError) Error() string {
229 msg := e.msg
230 if e.val != nil {
231 msg += fmt.Sprintf(" '%v' ", e.val)
232 }
233 msg += fmt.Sprintf("in record at byte %#x", e.off)
234 return msg
235 }
236
237
238 func Open(name string) (*File, error) {
239 f, err := os.Open(name)
240 if err != nil {
241 return nil, err
242 }
243 ff, err := NewFile(f)
244 if err != nil {
245 f.Close()
246 return nil, err
247 }
248 ff.closer = f
249 return ff, nil
250 }
251
252
253
254
255 func (f *File) Close() error {
256 var err error
257 if f.closer != nil {
258 err = f.closer.Close()
259 f.closer = nil
260 }
261 return err
262 }
263
264
265
266 func (f *File) SectionByType(typ SectionType) *Section {
267 for _, s := range f.Sections {
268 if s.Type == typ {
269 return s
270 }
271 }
272 return nil
273 }
274
275
276
277 func NewFile(r io.ReaderAt) (*File, error) {
278 sr := io.NewSectionReader(r, 0, 1<<63-1)
279
280 var ident [16]uint8
281 if _, err := r.ReadAt(ident[0:], 0); err != nil {
282 return nil, err
283 }
284 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
285 return nil, &FormatError{0, "bad magic number", ident[0:4]}
286 }
287
288 f := new(File)
289 f.Class = Class(ident[EI_CLASS])
290 switch f.Class {
291 case ELFCLASS32:
292 case ELFCLASS64:
293
294 default:
295 return nil, &FormatError{0, "unknown ELF class", f.Class}
296 }
297
298 f.Data = Data(ident[EI_DATA])
299 switch f.Data {
300 case ELFDATA2LSB:
301 f.ByteOrder = binary.LittleEndian
302 case ELFDATA2MSB:
303 f.ByteOrder = binary.BigEndian
304 default:
305 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
306 }
307
308 f.Version = Version(ident[EI_VERSION])
309 if f.Version != EV_CURRENT {
310 return nil, &FormatError{0, "unknown ELF version", f.Version}
311 }
312
313 f.OSABI = OSABI(ident[EI_OSABI])
314 f.ABIVersion = ident[EI_ABIVERSION]
315
316
317 var phoff int64
318 var phentsize, phnum int
319 var shoff int64
320 var shentsize, shnum, shstrndx int
321 switch f.Class {
322 case ELFCLASS32:
323 hdr := new(Header32)
324 sr.Seek(0, io.SeekStart)
325 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
326 return nil, err
327 }
328 f.Type = Type(hdr.Type)
329 f.Machine = Machine(hdr.Machine)
330 f.Entry = uint64(hdr.Entry)
331 if v := Version(hdr.Version); v != f.Version {
332 return nil, &FormatError{0, "mismatched ELF version", v}
333 }
334 phoff = int64(hdr.Phoff)
335 phentsize = int(hdr.Phentsize)
336 phnum = int(hdr.Phnum)
337 shoff = int64(hdr.Shoff)
338 shentsize = int(hdr.Shentsize)
339 shnum = int(hdr.Shnum)
340 shstrndx = int(hdr.Shstrndx)
341 case ELFCLASS64:
342 hdr := new(Header64)
343 sr.Seek(0, io.SeekStart)
344 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
345 return nil, err
346 }
347 f.Type = Type(hdr.Type)
348 f.Machine = Machine(hdr.Machine)
349 f.Entry = hdr.Entry
350 if v := Version(hdr.Version); v != f.Version {
351 return nil, &FormatError{0, "mismatched ELF version", v}
352 }
353 phoff = int64(hdr.Phoff)
354 phentsize = int(hdr.Phentsize)
355 phnum = int(hdr.Phnum)
356 shoff = int64(hdr.Shoff)
357 shentsize = int(hdr.Shentsize)
358 shnum = int(hdr.Shnum)
359 shstrndx = int(hdr.Shstrndx)
360 }
361
362 if shoff < 0 {
363 return nil, &FormatError{0, "invalid shoff", shoff}
364 }
365 if phoff < 0 {
366 return nil, &FormatError{0, "invalid phoff", phoff}
367 }
368
369 if shoff == 0 && shnum != 0 {
370 return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum}
371 }
372
373 if shnum > 0 && shstrndx >= shnum {
374 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
375 }
376
377 var wantPhentsize, wantShentsize int
378 switch f.Class {
379 case ELFCLASS32:
380 wantPhentsize = 8 * 4
381 wantShentsize = 10 * 4
382 case ELFCLASS64:
383 wantPhentsize = 2*4 + 6*8
384 wantShentsize = 4*4 + 6*8
385 }
386 if phnum > 0 && phentsize < wantPhentsize {
387 return nil, &FormatError{0, "invalid ELF phentsize", phentsize}
388 }
389
390
391 f.Progs = make([]*Prog, phnum)
392 for i := 0; i < phnum; i++ {
393 off := phoff + int64(i)*int64(phentsize)
394 sr.Seek(off, io.SeekStart)
395 p := new(Prog)
396 switch f.Class {
397 case ELFCLASS32:
398 ph := new(Prog32)
399 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
400 return nil, err
401 }
402 p.ProgHeader = ProgHeader{
403 Type: ProgType(ph.Type),
404 Flags: ProgFlag(ph.Flags),
405 Off: uint64(ph.Off),
406 Vaddr: uint64(ph.Vaddr),
407 Paddr: uint64(ph.Paddr),
408 Filesz: uint64(ph.Filesz),
409 Memsz: uint64(ph.Memsz),
410 Align: uint64(ph.Align),
411 }
412 case ELFCLASS64:
413 ph := new(Prog64)
414 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
415 return nil, err
416 }
417 p.ProgHeader = ProgHeader{
418 Type: ProgType(ph.Type),
419 Flags: ProgFlag(ph.Flags),
420 Off: ph.Off,
421 Vaddr: ph.Vaddr,
422 Paddr: ph.Paddr,
423 Filesz: ph.Filesz,
424 Memsz: ph.Memsz,
425 Align: ph.Align,
426 }
427 }
428 if int64(p.Off) < 0 {
429 return nil, &FormatError{off, "invalid program header offset", p.Off}
430 }
431 if int64(p.Filesz) < 0 {
432 return nil, &FormatError{off, "invalid program header file size", p.Filesz}
433 }
434 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
435 p.ReaderAt = p.sr
436 f.Progs[i] = p
437 }
438
439
440
441
442
443 if shoff > 0 && shnum == 0 {
444 var typ, link uint32
445 sr.Seek(shoff, io.SeekStart)
446 switch f.Class {
447 case ELFCLASS32:
448 sh := new(Section32)
449 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
450 return nil, err
451 }
452 shnum = int(sh.Size)
453 typ = sh.Type
454 link = sh.Link
455 case ELFCLASS64:
456 sh := new(Section64)
457 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
458 return nil, err
459 }
460 shnum = int(sh.Size)
461 typ = sh.Type
462 link = sh.Link
463 }
464 if SectionType(typ) != SHT_NULL {
465 return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)}
466 }
467
468 if shnum < int(SHN_LORESERVE) {
469 return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum}
470 }
471
472
473
474
475
476
477 if shstrndx == int(SHN_XINDEX) {
478 shstrndx = int(link)
479 if shstrndx < int(SHN_LORESERVE) {
480 return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx}
481 }
482 }
483 }
484
485 if shnum > 0 && shentsize < wantShentsize {
486 return nil, &FormatError{0, "invalid ELF shentsize", shentsize}
487 }
488
489
490 c := saferio.SliceCap[Section](uint64(shnum))
491 if c < 0 {
492 return nil, &FormatError{0, "too many sections", shnum}
493 }
494 f.Sections = make([]*Section, 0, c)
495 names := make([]uint32, 0, c)
496 for i := 0; i < shnum; i++ {
497 off := shoff + int64(i)*int64(shentsize)
498 sr.Seek(off, io.SeekStart)
499 s := new(Section)
500 switch f.Class {
501 case ELFCLASS32:
502 sh := new(Section32)
503 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
504 return nil, err
505 }
506 names = append(names, sh.Name)
507 s.SectionHeader = SectionHeader{
508 Type: SectionType(sh.Type),
509 Flags: SectionFlag(sh.Flags),
510 Addr: uint64(sh.Addr),
511 Offset: uint64(sh.Off),
512 FileSize: uint64(sh.Size),
513 Link: sh.Link,
514 Info: sh.Info,
515 Addralign: uint64(sh.Addralign),
516 Entsize: uint64(sh.Entsize),
517 }
518 case ELFCLASS64:
519 sh := new(Section64)
520 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
521 return nil, err
522 }
523 names = append(names, sh.Name)
524 s.SectionHeader = SectionHeader{
525 Type: SectionType(sh.Type),
526 Flags: SectionFlag(sh.Flags),
527 Offset: sh.Off,
528 FileSize: sh.Size,
529 Addr: sh.Addr,
530 Link: sh.Link,
531 Info: sh.Info,
532 Addralign: sh.Addralign,
533 Entsize: sh.Entsize,
534 }
535 }
536 if int64(s.Offset) < 0 {
537 return nil, &FormatError{off, "invalid section offset", int64(s.Offset)}
538 }
539 if int64(s.FileSize) < 0 {
540 return nil, &FormatError{off, "invalid section size", int64(s.FileSize)}
541 }
542 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
543
544 if s.Flags&SHF_COMPRESSED == 0 {
545 s.ReaderAt = s.sr
546 s.Size = s.FileSize
547 } else {
548
549 switch f.Class {
550 case ELFCLASS32:
551 ch := new(Chdr32)
552 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
553 return nil, err
554 }
555 s.compressionType = CompressionType(ch.Type)
556 s.Size = uint64(ch.Size)
557 s.Addralign = uint64(ch.Addralign)
558 s.compressionOffset = int64(binary.Size(ch))
559 case ELFCLASS64:
560 ch := new(Chdr64)
561 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
562 return nil, err
563 }
564 s.compressionType = CompressionType(ch.Type)
565 s.Size = ch.Size
566 s.Addralign = ch.Addralign
567 s.compressionOffset = int64(binary.Size(ch))
568 }
569 }
570
571 f.Sections = append(f.Sections, s)
572 }
573
574 if len(f.Sections) == 0 {
575 return f, nil
576 }
577
578
579 if shstrndx == 0 {
580
581
582 return f, nil
583 }
584 shstr := f.Sections[shstrndx]
585 if shstr.Type != SHT_STRTAB {
586 return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type}
587 }
588 shstrtab, err := shstr.Data()
589 if err != nil {
590 return nil, err
591 }
592 for i, s := range f.Sections {
593 var ok bool
594 s.Name, ok = getString(shstrtab, int(names[i]))
595 if !ok {
596 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
597 }
598 }
599
600 return f, nil
601 }
602
603
604
605 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
606 switch f.Class {
607 case ELFCLASS64:
608 return f.getSymbols64(typ)
609
610 case ELFCLASS32:
611 return f.getSymbols32(typ)
612 }
613
614 return nil, nil, errors.New("not implemented")
615 }
616
617
618
619 var ErrNoSymbols = errors.New("no symbol section")
620
621 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
622 symtabSection := f.SectionByType(typ)
623 if symtabSection == nil {
624 return nil, nil, ErrNoSymbols
625 }
626
627 data, err := symtabSection.Data()
628 if err != nil {
629 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
630 }
631 if len(data) == 0 {
632 return nil, nil, errors.New("symbol section is empty")
633 }
634 if len(data)%Sym32Size != 0 {
635 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
636 }
637
638 strdata, err := f.stringTable(symtabSection.Link)
639 if err != nil {
640 return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
641 }
642
643
644 data = data[Sym32Size:]
645
646 symbols := make([]Symbol, len(data)/Sym32Size)
647
648 i := 0
649 var sym Sym32
650 for len(data) > 0 {
651 sym.Name = f.ByteOrder.Uint32(data[0:4])
652 sym.Value = f.ByteOrder.Uint32(data[4:8])
653 sym.Size = f.ByteOrder.Uint32(data[8:12])
654 sym.Info = data[12]
655 sym.Other = data[13]
656 sym.Shndx = f.ByteOrder.Uint16(data[14:16])
657 str, _ := getString(strdata, int(sym.Name))
658 symbols[i].Name = str
659 symbols[i].Info = sym.Info
660 symbols[i].Other = sym.Other
661 symbols[i].Section = SectionIndex(sym.Shndx)
662 symbols[i].Value = uint64(sym.Value)
663 symbols[i].Size = uint64(sym.Size)
664 i++
665 data = data[Sym32Size:]
666 }
667
668 return symbols, strdata, nil
669 }
670
671 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
672 symtabSection := f.SectionByType(typ)
673 if symtabSection == nil {
674 return nil, nil, ErrNoSymbols
675 }
676
677 data, err := symtabSection.Data()
678 if err != nil {
679 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
680 }
681 if len(data)%Sym64Size != 0 {
682 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
683 }
684
685 strdata, err := f.stringTable(symtabSection.Link)
686 if err != nil {
687 return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
688 }
689
690
691 data = data[Sym64Size:]
692
693 symbols := make([]Symbol, len(data)/Sym64Size)
694
695 i := 0
696 var sym Sym64
697 for len(data) > 0 {
698 sym.Name = f.ByteOrder.Uint32(data[0:4])
699 sym.Info = data[4]
700 sym.Other = data[5]
701 sym.Shndx = f.ByteOrder.Uint16(data[6:8])
702 sym.Value = f.ByteOrder.Uint64(data[8:16])
703 sym.Size = f.ByteOrder.Uint64(data[16:24])
704 str, _ := getString(strdata, int(sym.Name))
705 symbols[i].Name = str
706 symbols[i].Info = sym.Info
707 symbols[i].Other = sym.Other
708 symbols[i].Section = SectionIndex(sym.Shndx)
709 symbols[i].Value = sym.Value
710 symbols[i].Size = sym.Size
711 i++
712 data = data[Sym64Size:]
713 }
714
715 return symbols, strdata, nil
716 }
717
718
719 func getString(section []byte, start int) (string, bool) {
720 if start < 0 || start >= len(section) {
721 return "", false
722 }
723
724 for end := start; end < len(section); end++ {
725 if section[end] == 0 {
726 return string(section[start:end]), true
727 }
728 }
729 return "", false
730 }
731
732
733
734 func (f *File) Section(name string) *Section {
735 for _, s := range f.Sections {
736 if s.Name == name {
737 return s
738 }
739 }
740 return nil
741 }
742
743
744
745 func (f *File) applyRelocations(dst []byte, rels []byte) error {
746 switch {
747 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
748 return f.applyRelocationsAMD64(dst, rels)
749 case f.Class == ELFCLASS32 && f.Machine == EM_386:
750 return f.applyRelocations386(dst, rels)
751 case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
752 return f.applyRelocationsARM(dst, rels)
753 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
754 return f.applyRelocationsARM64(dst, rels)
755 case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
756 return f.applyRelocationsPPC(dst, rels)
757 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
758 return f.applyRelocationsPPC64(dst, rels)
759 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
760 return f.applyRelocationsMIPS(dst, rels)
761 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
762 return f.applyRelocationsMIPS64(dst, rels)
763 case f.Class == ELFCLASS64 && f.Machine == EM_LOONGARCH:
764 return f.applyRelocationsLOONG64(dst, rels)
765 case f.Class == ELFCLASS64 && f.Machine == EM_RISCV:
766 return f.applyRelocationsRISCV64(dst, rels)
767 case f.Class == ELFCLASS64 && f.Machine == EM_S390:
768 return f.applyRelocationss390x(dst, rels)
769 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
770 return f.applyRelocationsSPARC64(dst, rels)
771 default:
772 return errors.New("applyRelocations: not implemented")
773 }
774 }
775
776
777
778
779
780
781
782 func canApplyRelocation(sym *Symbol) bool {
783 return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE
784 }
785
786 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
787
788 if len(rels)%24 != 0 {
789 return errors.New("length of relocation section is not a multiple of 24")
790 }
791
792 symbols, _, err := f.getSymbols(SHT_SYMTAB)
793 if err != nil {
794 return err
795 }
796
797 b := bytes.NewReader(rels)
798 var rela Rela64
799
800 for b.Len() > 0 {
801 binary.Read(b, f.ByteOrder, &rela)
802 symNo := rela.Info >> 32
803 t := R_X86_64(rela.Info & 0xffff)
804
805 if symNo == 0 || symNo > uint64(len(symbols)) {
806 continue
807 }
808 sym := &symbols[symNo-1]
809 if !canApplyRelocation(sym) {
810 continue
811 }
812
813
814
815
816
817 switch t {
818 case R_X86_64_64:
819 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
820 continue
821 }
822 val64 := sym.Value + uint64(rela.Addend)
823 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
824 case R_X86_64_32:
825 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
826 continue
827 }
828 val32 := uint32(sym.Value) + uint32(rela.Addend)
829 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
830 }
831 }
832
833 return nil
834 }
835
836 func (f *File) applyRelocations386(dst []byte, rels []byte) error {
837
838 if len(rels)%8 != 0 {
839 return errors.New("length of relocation section is not a multiple of 8")
840 }
841
842 symbols, _, err := f.getSymbols(SHT_SYMTAB)
843 if err != nil {
844 return err
845 }
846
847 b := bytes.NewReader(rels)
848 var rel Rel32
849
850 for b.Len() > 0 {
851 binary.Read(b, f.ByteOrder, &rel)
852 symNo := rel.Info >> 8
853 t := R_386(rel.Info & 0xff)
854
855 if symNo == 0 || symNo > uint32(len(symbols)) {
856 continue
857 }
858 sym := &symbols[symNo-1]
859
860 if t == R_386_32 {
861 if rel.Off+4 >= uint32(len(dst)) {
862 continue
863 }
864 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
865 val += uint32(sym.Value)
866 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
867 }
868 }
869
870 return nil
871 }
872
873 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
874
875 if len(rels)%8 != 0 {
876 return errors.New("length of relocation section is not a multiple of 8")
877 }
878
879 symbols, _, err := f.getSymbols(SHT_SYMTAB)
880 if err != nil {
881 return err
882 }
883
884 b := bytes.NewReader(rels)
885 var rel Rel32
886
887 for b.Len() > 0 {
888 binary.Read(b, f.ByteOrder, &rel)
889 symNo := rel.Info >> 8
890 t := R_ARM(rel.Info & 0xff)
891
892 if symNo == 0 || symNo > uint32(len(symbols)) {
893 continue
894 }
895 sym := &symbols[symNo-1]
896
897 switch t {
898 case R_ARM_ABS32:
899 if rel.Off+4 >= uint32(len(dst)) {
900 continue
901 }
902 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
903 val += uint32(sym.Value)
904 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
905 }
906 }
907
908 return nil
909 }
910
911 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
912
913 if len(rels)%24 != 0 {
914 return errors.New("length of relocation section is not a multiple of 24")
915 }
916
917 symbols, _, err := f.getSymbols(SHT_SYMTAB)
918 if err != nil {
919 return err
920 }
921
922 b := bytes.NewReader(rels)
923 var rela Rela64
924
925 for b.Len() > 0 {
926 binary.Read(b, f.ByteOrder, &rela)
927 symNo := rela.Info >> 32
928 t := R_AARCH64(rela.Info & 0xffff)
929
930 if symNo == 0 || symNo > uint64(len(symbols)) {
931 continue
932 }
933 sym := &symbols[symNo-1]
934 if !canApplyRelocation(sym) {
935 continue
936 }
937
938
939
940
941
942 switch t {
943 case R_AARCH64_ABS64:
944 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
945 continue
946 }
947 val64 := sym.Value + uint64(rela.Addend)
948 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
949 case R_AARCH64_ABS32:
950 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
951 continue
952 }
953 val32 := uint32(sym.Value) + uint32(rela.Addend)
954 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
955 }
956 }
957
958 return nil
959 }
960
961 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
962
963 if len(rels)%12 != 0 {
964 return errors.New("length of relocation section is not a multiple of 12")
965 }
966
967 symbols, _, err := f.getSymbols(SHT_SYMTAB)
968 if err != nil {
969 return err
970 }
971
972 b := bytes.NewReader(rels)
973 var rela Rela32
974
975 for b.Len() > 0 {
976 binary.Read(b, f.ByteOrder, &rela)
977 symNo := rela.Info >> 8
978 t := R_PPC(rela.Info & 0xff)
979
980 if symNo == 0 || symNo > uint32(len(symbols)) {
981 continue
982 }
983 sym := &symbols[symNo-1]
984 if !canApplyRelocation(sym) {
985 continue
986 }
987
988 switch t {
989 case R_PPC_ADDR32:
990 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
991 continue
992 }
993 val32 := uint32(sym.Value) + uint32(rela.Addend)
994 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
995 }
996 }
997
998 return nil
999 }
1000
1001 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
1002
1003 if len(rels)%24 != 0 {
1004 return errors.New("length of relocation section is not a multiple of 24")
1005 }
1006
1007 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1008 if err != nil {
1009 return err
1010 }
1011
1012 b := bytes.NewReader(rels)
1013 var rela Rela64
1014
1015 for b.Len() > 0 {
1016 binary.Read(b, f.ByteOrder, &rela)
1017 symNo := rela.Info >> 32
1018 t := R_PPC64(rela.Info & 0xffff)
1019
1020 if symNo == 0 || symNo > uint64(len(symbols)) {
1021 continue
1022 }
1023 sym := &symbols[symNo-1]
1024 if !canApplyRelocation(sym) {
1025 continue
1026 }
1027
1028 switch t {
1029 case R_PPC64_ADDR64:
1030 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1031 continue
1032 }
1033 val64 := sym.Value + uint64(rela.Addend)
1034 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1035 case R_PPC64_ADDR32:
1036 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1037 continue
1038 }
1039 val32 := uint32(sym.Value) + uint32(rela.Addend)
1040 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1041 }
1042 }
1043
1044 return nil
1045 }
1046
1047 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
1048
1049 if len(rels)%8 != 0 {
1050 return errors.New("length of relocation section is not a multiple of 8")
1051 }
1052
1053 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1054 if err != nil {
1055 return err
1056 }
1057
1058 b := bytes.NewReader(rels)
1059 var rel Rel32
1060
1061 for b.Len() > 0 {
1062 binary.Read(b, f.ByteOrder, &rel)
1063 symNo := rel.Info >> 8
1064 t := R_MIPS(rel.Info & 0xff)
1065
1066 if symNo == 0 || symNo > uint32(len(symbols)) {
1067 continue
1068 }
1069 sym := &symbols[symNo-1]
1070
1071 switch t {
1072 case R_MIPS_32:
1073 if rel.Off+4 >= uint32(len(dst)) {
1074 continue
1075 }
1076 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
1077 val += uint32(sym.Value)
1078 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
1079 }
1080 }
1081
1082 return nil
1083 }
1084
1085 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
1086
1087 if len(rels)%24 != 0 {
1088 return errors.New("length of relocation section is not a multiple of 24")
1089 }
1090
1091 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1092 if err != nil {
1093 return err
1094 }
1095
1096 b := bytes.NewReader(rels)
1097 var rela Rela64
1098
1099 for b.Len() > 0 {
1100 binary.Read(b, f.ByteOrder, &rela)
1101 var symNo uint64
1102 var t R_MIPS
1103 if f.ByteOrder == binary.BigEndian {
1104 symNo = rela.Info >> 32
1105 t = R_MIPS(rela.Info & 0xff)
1106 } else {
1107 symNo = rela.Info & 0xffffffff
1108 t = R_MIPS(rela.Info >> 56)
1109 }
1110
1111 if symNo == 0 || symNo > uint64(len(symbols)) {
1112 continue
1113 }
1114 sym := &symbols[symNo-1]
1115 if !canApplyRelocation(sym) {
1116 continue
1117 }
1118
1119 switch t {
1120 case R_MIPS_64:
1121 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1122 continue
1123 }
1124 val64 := sym.Value + uint64(rela.Addend)
1125 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1126 case R_MIPS_32:
1127 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1128 continue
1129 }
1130 val32 := uint32(sym.Value) + uint32(rela.Addend)
1131 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1132 }
1133 }
1134
1135 return nil
1136 }
1137
1138 func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error {
1139
1140 if len(rels)%24 != 0 {
1141 return errors.New("length of relocation section is not a multiple of 24")
1142 }
1143
1144 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1145 if err != nil {
1146 return err
1147 }
1148
1149 b := bytes.NewReader(rels)
1150 var rela Rela64
1151
1152 for b.Len() > 0 {
1153 binary.Read(b, f.ByteOrder, &rela)
1154 var symNo uint64
1155 var t R_LARCH
1156 symNo = rela.Info >> 32
1157 t = R_LARCH(rela.Info & 0xffff)
1158
1159 if symNo == 0 || symNo > uint64(len(symbols)) {
1160 continue
1161 }
1162 sym := &symbols[symNo-1]
1163 if !canApplyRelocation(sym) {
1164 continue
1165 }
1166
1167 switch t {
1168 case R_LARCH_64:
1169 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1170 continue
1171 }
1172 val64 := sym.Value + uint64(rela.Addend)
1173 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1174 case R_LARCH_32:
1175 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1176 continue
1177 }
1178 val32 := uint32(sym.Value) + uint32(rela.Addend)
1179 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1180 }
1181 }
1182
1183 return nil
1184 }
1185
1186 func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
1187
1188 if len(rels)%24 != 0 {
1189 return errors.New("length of relocation section is not a multiple of 24")
1190 }
1191
1192 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1193 if err != nil {
1194 return err
1195 }
1196
1197 b := bytes.NewReader(rels)
1198 var rela Rela64
1199
1200 for b.Len() > 0 {
1201 binary.Read(b, f.ByteOrder, &rela)
1202 symNo := rela.Info >> 32
1203 t := R_RISCV(rela.Info & 0xffff)
1204
1205 if symNo == 0 || symNo > uint64(len(symbols)) {
1206 continue
1207 }
1208 sym := &symbols[symNo-1]
1209 if !canApplyRelocation(sym) {
1210 continue
1211 }
1212
1213 switch t {
1214 case R_RISCV_64:
1215 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1216 continue
1217 }
1218 val64 := sym.Value + uint64(rela.Addend)
1219 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1220 case R_RISCV_32:
1221 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1222 continue
1223 }
1224 val32 := uint32(sym.Value) + uint32(rela.Addend)
1225 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1226 }
1227 }
1228
1229 return nil
1230 }
1231
1232 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
1233
1234 if len(rels)%24 != 0 {
1235 return errors.New("length of relocation section is not a multiple of 24")
1236 }
1237
1238 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1239 if err != nil {
1240 return err
1241 }
1242
1243 b := bytes.NewReader(rels)
1244 var rela Rela64
1245
1246 for b.Len() > 0 {
1247 binary.Read(b, f.ByteOrder, &rela)
1248 symNo := rela.Info >> 32
1249 t := R_390(rela.Info & 0xffff)
1250
1251 if symNo == 0 || symNo > uint64(len(symbols)) {
1252 continue
1253 }
1254 sym := &symbols[symNo-1]
1255 if !canApplyRelocation(sym) {
1256 continue
1257 }
1258
1259 switch t {
1260 case R_390_64:
1261 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1262 continue
1263 }
1264 val64 := sym.Value + uint64(rela.Addend)
1265 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1266 case R_390_32:
1267 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1268 continue
1269 }
1270 val32 := uint32(sym.Value) + uint32(rela.Addend)
1271 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1272 }
1273 }
1274
1275 return nil
1276 }
1277
1278 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
1279
1280 if len(rels)%24 != 0 {
1281 return errors.New("length of relocation section is not a multiple of 24")
1282 }
1283
1284 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1285 if err != nil {
1286 return err
1287 }
1288
1289 b := bytes.NewReader(rels)
1290 var rela Rela64
1291
1292 for b.Len() > 0 {
1293 binary.Read(b, f.ByteOrder, &rela)
1294 symNo := rela.Info >> 32
1295 t := R_SPARC(rela.Info & 0xff)
1296
1297 if symNo == 0 || symNo > uint64(len(symbols)) {
1298 continue
1299 }
1300 sym := &symbols[symNo-1]
1301 if !canApplyRelocation(sym) {
1302 continue
1303 }
1304
1305 switch t {
1306 case R_SPARC_64, R_SPARC_UA64:
1307 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1308 continue
1309 }
1310 val64 := sym.Value + uint64(rela.Addend)
1311 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1312 case R_SPARC_32, R_SPARC_UA32:
1313 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1314 continue
1315 }
1316 val32 := uint32(sym.Value) + uint32(rela.Addend)
1317 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1318 }
1319 }
1320
1321 return nil
1322 }
1323
1324 func (f *File) DWARF() (*dwarf.Data, error) {
1325 dwarfSuffix := func(s *Section) string {
1326 switch {
1327 case strings.HasPrefix(s.Name, ".debug_"):
1328 return s.Name[7:]
1329 case strings.HasPrefix(s.Name, ".zdebug_"):
1330 return s.Name[8:]
1331 default:
1332 return ""
1333 }
1334
1335 }
1336
1337
1338 sectionData := func(i int, s *Section) ([]byte, error) {
1339 b, err := s.Data()
1340 if err != nil && uint64(len(b)) < s.Size {
1341 return nil, err
1342 }
1343
1344 if f.Type == ET_EXEC {
1345
1346
1347
1348 return b, nil
1349 }
1350
1351 for _, r := range f.Sections {
1352 if r.Type != SHT_RELA && r.Type != SHT_REL {
1353 continue
1354 }
1355 if int(r.Info) != i {
1356 continue
1357 }
1358 rd, err := r.Data()
1359 if err != nil {
1360 return nil, err
1361 }
1362 err = f.applyRelocations(b, rd)
1363 if err != nil {
1364 return nil, err
1365 }
1366 }
1367 return b, nil
1368 }
1369
1370
1371
1372 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1373 for i, s := range f.Sections {
1374 suffix := dwarfSuffix(s)
1375 if suffix == "" {
1376 continue
1377 }
1378 if _, ok := dat[suffix]; !ok {
1379 continue
1380 }
1381 b, err := sectionData(i, s)
1382 if err != nil {
1383 return nil, err
1384 }
1385 dat[suffix] = b
1386 }
1387
1388 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1389 if err != nil {
1390 return nil, err
1391 }
1392
1393
1394 for i, s := range f.Sections {
1395 suffix := dwarfSuffix(s)
1396 if suffix == "" {
1397 continue
1398 }
1399 if _, ok := dat[suffix]; ok {
1400
1401 continue
1402 }
1403
1404 b, err := sectionData(i, s)
1405 if err != nil {
1406 return nil, err
1407 }
1408
1409 if suffix == "types" {
1410 if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil {
1411 return nil, err
1412 }
1413 } else {
1414 if err := d.AddSection(".debug_"+suffix, b); err != nil {
1415 return nil, err
1416 }
1417 }
1418 }
1419
1420 return d, nil
1421 }
1422
1423
1424
1425
1426
1427
1428
1429 func (f *File) Symbols() ([]Symbol, error) {
1430 sym, _, err := f.getSymbols(SHT_SYMTAB)
1431 return sym, err
1432 }
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443 func (f *File) DynamicSymbols() ([]Symbol, error) {
1444 sym, str, err := f.getSymbols(SHT_DYNSYM)
1445 if err != nil {
1446 return nil, err
1447 }
1448 if f.gnuVersionInit(str) {
1449 for i := range sym {
1450 sym[i].Library, sym[i].Version = f.gnuVersion(i)
1451 }
1452 }
1453 return sym, nil
1454 }
1455
1456 type ImportedSymbol struct {
1457 Name string
1458 Version string
1459 Library string
1460 }
1461
1462
1463
1464
1465
1466 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
1467 sym, str, err := f.getSymbols(SHT_DYNSYM)
1468 if err != nil {
1469 return nil, err
1470 }
1471 f.gnuVersionInit(str)
1472 var all []ImportedSymbol
1473 for i, s := range sym {
1474 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
1475 all = append(all, ImportedSymbol{Name: s.Name})
1476 sym := &all[len(all)-1]
1477 sym.Library, sym.Version = f.gnuVersion(i)
1478 }
1479 }
1480 return all, nil
1481 }
1482
1483 type verneed struct {
1484 File string
1485 Name string
1486 }
1487
1488
1489
1490 func (f *File) gnuVersionInit(str []byte) bool {
1491 if f.gnuNeed != nil {
1492
1493 return true
1494 }
1495
1496
1497 vn := f.SectionByType(SHT_GNU_VERNEED)
1498 if vn == nil {
1499 return false
1500 }
1501 d, _ := vn.Data()
1502
1503 var need []verneed
1504 i := 0
1505 for {
1506 if i+16 > len(d) {
1507 break
1508 }
1509 vers := f.ByteOrder.Uint16(d[i : i+2])
1510 if vers != 1 {
1511 break
1512 }
1513 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
1514 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
1515 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
1516 next := f.ByteOrder.Uint32(d[i+12 : i+16])
1517 file, _ := getString(str, int(fileoff))
1518
1519 var name string
1520 j := i + int(aux)
1521 for c := 0; c < int(cnt); c++ {
1522 if j+16 > len(d) {
1523 break
1524 }
1525
1526
1527 other := f.ByteOrder.Uint16(d[j+6 : j+8])
1528 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
1529 next := f.ByteOrder.Uint32(d[j+12 : j+16])
1530 name, _ = getString(str, int(nameoff))
1531 ndx := int(other)
1532 if ndx >= len(need) {
1533 a := make([]verneed, 2*(ndx+1))
1534 copy(a, need)
1535 need = a
1536 }
1537
1538 need[ndx] = verneed{file, name}
1539 if next == 0 {
1540 break
1541 }
1542 j += int(next)
1543 }
1544
1545 if next == 0 {
1546 break
1547 }
1548 i += int(next)
1549 }
1550
1551
1552 vs := f.SectionByType(SHT_GNU_VERSYM)
1553 if vs == nil {
1554 return false
1555 }
1556 d, _ = vs.Data()
1557
1558 f.gnuNeed = need
1559 f.gnuVersym = d
1560 return true
1561 }
1562
1563
1564
1565 func (f *File) gnuVersion(i int) (library string, version string) {
1566
1567 i = (i + 1) * 2
1568 if i >= len(f.gnuVersym) {
1569 return
1570 }
1571 s := f.gnuVersym[i:]
1572 if len(s) < 2 {
1573 return
1574 }
1575 j := int(f.ByteOrder.Uint16(s))
1576 if j < 2 || j >= len(f.gnuNeed) {
1577 return
1578 }
1579 n := &f.gnuNeed[j]
1580 return n.File, n.Name
1581 }
1582
1583
1584
1585
1586 func (f *File) ImportedLibraries() ([]string, error) {
1587 return f.DynString(DT_NEEDED)
1588 }
1589
1590
1591
1592
1593
1594
1595 func (f *File) DynString(tag DynTag) ([]string, error) {
1596 switch tag {
1597 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
1598 default:
1599 return nil, fmt.Errorf("non-string-valued tag %v", tag)
1600 }
1601 ds := f.SectionByType(SHT_DYNAMIC)
1602 if ds == nil {
1603
1604 return nil, nil
1605 }
1606 d, err := ds.Data()
1607 if err != nil {
1608 return nil, err
1609 }
1610
1611 dynSize := 8
1612 if f.Class == ELFCLASS64 {
1613 dynSize = 16
1614 }
1615 if len(d)%dynSize != 0 {
1616 return nil, errors.New("length of dynamic section is not a multiple of dynamic entry size")
1617 }
1618
1619 str, err := f.stringTable(ds.Link)
1620 if err != nil {
1621 return nil, err
1622 }
1623 var all []string
1624 for len(d) > 0 {
1625 var t DynTag
1626 var v uint64
1627 switch f.Class {
1628 case ELFCLASS32:
1629 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1630 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1631 d = d[8:]
1632 case ELFCLASS64:
1633 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1634 v = f.ByteOrder.Uint64(d[8:16])
1635 d = d[16:]
1636 }
1637 if t == tag {
1638 s, ok := getString(str, int(v))
1639 if ok {
1640 all = append(all, s)
1641 }
1642 }
1643 }
1644 return all, nil
1645 }
1646
1647
1648
1649 func (f *File) DynValue(tag DynTag) ([]uint64, error) {
1650 ds := f.SectionByType(SHT_DYNAMIC)
1651 if ds == nil {
1652 return nil, nil
1653 }
1654 d, err := ds.Data()
1655 if err != nil {
1656 return nil, err
1657 }
1658
1659 dynSize := 8
1660 if f.Class == ELFCLASS64 {
1661 dynSize = 16
1662 }
1663 if len(d)%dynSize != 0 {
1664 return nil, errors.New("length of dynamic section is not a multiple of dynamic entry size")
1665 }
1666
1667
1668 var vals []uint64
1669 for len(d) > 0 {
1670 var t DynTag
1671 var v uint64
1672 switch f.Class {
1673 case ELFCLASS32:
1674 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1675 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1676 d = d[8:]
1677 case ELFCLASS64:
1678 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1679 v = f.ByteOrder.Uint64(d[8:16])
1680 d = d[16:]
1681 }
1682 if t == tag {
1683 vals = append(vals, v)
1684 }
1685 }
1686 return vals, nil
1687 }
1688
1689 type nobitsSectionReader struct{}
1690
1691 func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) {
1692 return 0, errors.New("unexpected read from SHT_NOBITS section")
1693 }
1694
View as plain text