1 // Copyright 2009 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.
6 Package elf implements access to ELF object files.
10 This package is not designed to be hardened against adversarial inputs, and is
11 outside the scope of https://go.dev/security/policy. In particular, only basic
12 validation is done when parsing object files. As such, care should be taken when
13 parsing untrusted inputs, as parsing malformed files may consume significant
14 resources, or cause panics.
31 // seekStart, seekCurrent, seekEnd are copies of
32 // io.SeekStart, io.SeekCurrent, and io.SeekEnd.
33 // We can't use the ones from package io because
34 // we want this code to build with Go 1.4 during
35 // cmd/dist bootstrap.
42 // TODO: error reporting detail
45 * Internal ELF representation
48 // A FileHeader represents an ELF file header.
49 type FileHeader struct {
55 ByteOrder binary.ByteOrder
61 // A File represents an open ELF file.
71 // A SectionHeader represents a single ELF section header.
72 type SectionHeader struct {
84 // FileSize is the size of this section in the file in bytes.
85 // If a section is compressed, FileSize is the size of the
86 // compressed data, while Size (above) is the size of the
91 // A Section represents a single section in an ELF file.
95 // Embed ReaderAt for ReadAt method.
96 // Do not embed SectionReader directly
97 // to avoid having Read and Seek.
98 // If a client wants Read and Seek it must use
99 // Open() to avoid fighting over the seek offset
100 // with other clients.
102 // ReaderAt may be nil if the section is not easily available
103 // in a random-access form. For example, a compressed section
104 // may have a nil ReaderAt.
108 compressionType CompressionType
109 compressionOffset int64
112 // Data reads and returns the contents of the ELF section.
113 // Even if the section is stored compressed in the ELF file,
114 // Data returns uncompressed data.
116 // For an SHT_NOBITS section, Data always returns a non-nil error.
117 func (s *Section) Data() ([]byte, error) {
118 return saferio.ReadData(s.Open(), s.Size)
121 // stringTable reads and returns the string table given by the
122 // specified link value.
123 func (f *File) stringTable(link uint32) ([]byte, error) {
124 if link <= 0 || link >= uint32(len(f.Sections)) {
125 return nil, errors.New("section has invalid string table link")
127 return f.Sections[link].Data()
130 // Open returns a new ReadSeeker reading the ELF section.
131 // Even if the section is stored compressed in the ELF file,
132 // the ReadSeeker reads uncompressed data.
134 // For an SHT_NOBITS section, all calls to the opened reader
135 // will return a non-nil error.
136 func (s *Section) Open() io.ReadSeeker {
137 if s.Type == SHT_NOBITS {
138 return io.NewSectionReader(&nobitsSectionReader{}, 0, int64(s.Size))
140 if s.Flags&SHF_COMPRESSED == 0 {
141 return io.NewSectionReader(s.sr, 0, 1<<63-1)
143 if s.compressionType == COMPRESS_ZLIB {
144 return &readSeekerFromReader{
145 reset: func() (io.Reader, error) {
146 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
147 return zlib.NewReader(fr)
152 err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType}
153 return errorReader{err}
156 // A ProgHeader represents a single ELF program header.
157 type ProgHeader struct {
168 // A Prog represents a single ELF program header in an ELF binary.
172 // Embed ReaderAt for ReadAt method.
173 // Do not embed SectionReader directly
174 // to avoid having Read and Seek.
175 // If a client wants Read and Seek it must use
176 // Open() to avoid fighting over the seek offset
177 // with other clients.
182 // Open returns a new ReadSeeker reading the ELF program body.
183 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
185 // A Symbol represents an entry in an ELF symbol table section.
192 // Version and Library are present only for the dynamic symbol
202 type FormatError struct {
208 func (e *FormatError) Error() string {
211 msg += fmt.Sprintf(" '%v' ", e.val)
213 msg += fmt.Sprintf("in record at byte %#x", e.off)
217 // Open opens the named file using os.Open and prepares it for use as an ELF binary.
218 func Open(name string) (*File, error) {
219 f, err := os.Open(name)
223 ff, err := NewFile(f)
232 // Close closes the File.
233 // If the File was created using NewFile directly instead of Open,
234 // Close has no effect.
235 func (f *File) Close() error {
238 err = f.closer.Close()
244 // SectionByType returns the first section in f with the
245 // given type, or nil if there is no such section.
246 func (f *File) SectionByType(typ SectionType) *Section {
247 for _, s := range f.Sections {
255 // NewFile creates a new File for accessing an ELF binary in an underlying reader.
256 // The ELF binary is expected to start at position 0 in the ReaderAt.
257 func NewFile(r io.ReaderAt) (*File, error) {
258 sr := io.NewSectionReader(r, 0, 1<<63-1)
259 // Read and decode ELF identifier
261 if _, err := r.ReadAt(ident[0:], 0); err != nil {
264 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
265 return nil, &FormatError{0, "bad magic number", ident[0:4]}
269 f.Class = Class(ident[EI_CLASS])
275 return nil, &FormatError{0, "unknown ELF class", f.Class}
278 f.Data = Data(ident[EI_DATA])
281 f.ByteOrder = binary.LittleEndian
283 f.ByteOrder = binary.BigEndian
285 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
288 f.Version = Version(ident[EI_VERSION])
289 if f.Version != EV_CURRENT {
290 return nil, &FormatError{0, "unknown ELF version", f.Version}
293 f.OSABI = OSABI(ident[EI_OSABI])
294 f.ABIVersion = ident[EI_ABIVERSION]
296 // Read ELF file header
298 var phentsize, phnum int
300 var shentsize, shnum, shstrndx int
304 sr.Seek(0, seekStart)
305 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
308 f.Type = Type(hdr.Type)
309 f.Machine = Machine(hdr.Machine)
310 f.Entry = uint64(hdr.Entry)
311 if v := Version(hdr.Version); v != f.Version {
312 return nil, &FormatError{0, "mismatched ELF version", v}
314 phoff = int64(hdr.Phoff)
315 phentsize = int(hdr.Phentsize)
316 phnum = int(hdr.Phnum)
317 shoff = int64(hdr.Shoff)
318 shentsize = int(hdr.Shentsize)
319 shnum = int(hdr.Shnum)
320 shstrndx = int(hdr.Shstrndx)
323 sr.Seek(0, seekStart)
324 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
327 f.Type = Type(hdr.Type)
328 f.Machine = Machine(hdr.Machine)
330 if v := Version(hdr.Version); v != f.Version {
331 return nil, &FormatError{0, "mismatched ELF version", v}
333 phoff = int64(hdr.Phoff)
334 phentsize = int(hdr.Phentsize)
335 phnum = int(hdr.Phnum)
336 shoff = int64(hdr.Shoff)
337 shentsize = int(hdr.Shentsize)
338 shnum = int(hdr.Shnum)
339 shstrndx = int(hdr.Shstrndx)
343 return nil, &FormatError{0, "invalid shoff", shoff}
346 return nil, &FormatError{0, "invalid phoff", phoff}
349 if shoff == 0 && shnum != 0 {
350 return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum}
353 if shnum > 0 && shstrndx >= shnum {
354 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
357 var wantPhentsize, wantShentsize int
360 wantPhentsize = 8 * 4
361 wantShentsize = 10 * 4
363 wantPhentsize = 2*4 + 6*8
364 wantShentsize = 4*4 + 6*8
366 if phnum > 0 && phentsize < wantPhentsize {
367 return nil, &FormatError{0, "invalid ELF phentsize", phentsize}
370 // Read program headers
371 f.Progs = make([]*Prog, phnum)
372 for i := 0; i < phnum; i++ {
373 off := phoff + int64(i)*int64(phentsize)
374 sr.Seek(off, seekStart)
379 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
382 p.ProgHeader = ProgHeader{
383 Type: ProgType(ph.Type),
384 Flags: ProgFlag(ph.Flags),
386 Vaddr: uint64(ph.Vaddr),
387 Paddr: uint64(ph.Paddr),
388 Filesz: uint64(ph.Filesz),
389 Memsz: uint64(ph.Memsz),
390 Align: uint64(ph.Align),
394 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
397 p.ProgHeader = ProgHeader{
398 Type: ProgType(ph.Type),
399 Flags: ProgFlag(ph.Flags),
408 if int64(p.Off) < 0 {
409 return nil, &FormatError{off, "invalid program header offset", p.Off}
411 if int64(p.Filesz) < 0 {
412 return nil, &FormatError{off, "invalid program header file size", p.Filesz}
414 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
419 // If the number of sections is greater than or equal to SHN_LORESERVE
420 // (0xff00), shnum has the value zero and the actual number of section
421 // header table entries is contained in the sh_size field of the section
422 // header at index 0.
423 if shoff > 0 && shnum == 0 {
425 sr.Seek(shoff, seekStart)
429 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
437 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
444 if SectionType(typ) != SHT_NULL {
445 return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)}
448 if shnum < int(SHN_LORESERVE) {
449 return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum}
452 // If the section name string table section index is greater than or
453 // equal to SHN_LORESERVE (0xff00), this member has the value
454 // SHN_XINDEX (0xffff) and the actual index of the section name
455 // string table section is contained in the sh_link field of the
456 // section header at index 0.
457 if shstrndx == int(SHN_XINDEX) {
459 if shstrndx < int(SHN_LORESERVE) {
460 return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx}
465 if shnum > 0 && shentsize < wantShentsize {
466 return nil, &FormatError{0, "invalid ELF shentsize", shentsize}
469 // Read section headers
470 c := saferio.SliceCap((*Section)(nil), uint64(shnum))
472 return nil, &FormatError{0, "too many sections", shnum}
474 f.Sections = make([]*Section, 0, c)
475 names := make([]uint32, 0, c)
476 for i := 0; i < shnum; i++ {
477 off := shoff + int64(i)*int64(shentsize)
478 sr.Seek(off, seekStart)
483 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
486 names = append(names, sh.Name)
487 s.SectionHeader = SectionHeader{
488 Type: SectionType(sh.Type),
489 Flags: SectionFlag(sh.Flags),
490 Addr: uint64(sh.Addr),
491 Offset: uint64(sh.Off),
492 FileSize: uint64(sh.Size),
495 Addralign: uint64(sh.Addralign),
496 Entsize: uint64(sh.Entsize),
500 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
503 names = append(names, sh.Name)
504 s.SectionHeader = SectionHeader{
505 Type: SectionType(sh.Type),
506 Flags: SectionFlag(sh.Flags),
512 Addralign: sh.Addralign,
516 if int64(s.Offset) < 0 {
517 return nil, &FormatError{off, "invalid section offset", int64(s.Offset)}
519 if int64(s.FileSize) < 0 {
520 return nil, &FormatError{off, "invalid section size", int64(s.FileSize)}
522 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
524 if s.Flags&SHF_COMPRESSED == 0 {
528 // Read the compression header.
532 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
535 s.compressionType = CompressionType(ch.Type)
536 s.Size = uint64(ch.Size)
537 s.Addralign = uint64(ch.Addralign)
538 s.compressionOffset = int64(binary.Size(ch))
541 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
544 s.compressionType = CompressionType(ch.Type)
546 s.Addralign = ch.Addralign
547 s.compressionOffset = int64(binary.Size(ch))
551 f.Sections = append(f.Sections, s)
554 if len(f.Sections) == 0 {
558 // Load section header string table.
560 // If the file has no section name string table,
561 // shstrndx holds the value SHN_UNDEF (0).
564 shstr := f.Sections[shstrndx]
565 if shstr.Type != SHT_STRTAB {
566 return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type}
568 shstrtab, err := shstr.Data()
572 for i, s := range f.Sections {
574 s.Name, ok = getString(shstrtab, int(names[i]))
576 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
583 // getSymbols returns a slice of Symbols from parsing the symbol table
584 // with the given type, along with the associated string table.
585 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
588 return f.getSymbols64(typ)
591 return f.getSymbols32(typ)
594 return nil, nil, errors.New("not implemented")
597 // ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
598 // if there is no such section in the File.
599 var ErrNoSymbols = errors.New("no symbol section")
601 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
602 symtabSection := f.SectionByType(typ)
603 if symtabSection == nil {
604 return nil, nil, ErrNoSymbols
607 data, err := symtabSection.Data()
609 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
611 symtab := bytes.NewReader(data)
612 if symtab.Len()%Sym32Size != 0 {
613 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
616 strdata, err := f.stringTable(symtabSection.Link)
618 return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
621 // The first entry is all zeros.
622 var skip [Sym32Size]byte
625 symbols := make([]Symbol, symtab.Len()/Sym32Size)
629 for symtab.Len() > 0 {
630 binary.Read(symtab, f.ByteOrder, &sym)
631 str, _ := getString(strdata, int(sym.Name))
632 symbols[i].Name = str
633 symbols[i].Info = sym.Info
634 symbols[i].Other = sym.Other
635 symbols[i].Section = SectionIndex(sym.Shndx)
636 symbols[i].Value = uint64(sym.Value)
637 symbols[i].Size = uint64(sym.Size)
641 return symbols, strdata, nil
644 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
645 symtabSection := f.SectionByType(typ)
646 if symtabSection == nil {
647 return nil, nil, ErrNoSymbols
650 data, err := symtabSection.Data()
652 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
654 symtab := bytes.NewReader(data)
655 if symtab.Len()%Sym64Size != 0 {
656 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
659 strdata, err := f.stringTable(symtabSection.Link)
661 return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
664 // The first entry is all zeros.
665 var skip [Sym64Size]byte
668 symbols := make([]Symbol, symtab.Len()/Sym64Size)
672 for symtab.Len() > 0 {
673 binary.Read(symtab, f.ByteOrder, &sym)
674 str, _ := getString(strdata, int(sym.Name))
675 symbols[i].Name = str
676 symbols[i].Info = sym.Info
677 symbols[i].Other = sym.Other
678 symbols[i].Section = SectionIndex(sym.Shndx)
679 symbols[i].Value = sym.Value
680 symbols[i].Size = sym.Size
684 return symbols, strdata, nil
687 // getString extracts a string from an ELF string table.
688 func getString(section []byte, start int) (string, bool) {
689 if start < 0 || start >= len(section) {
693 for end := start; end < len(section); end++ {
694 if section[end] == 0 {
695 return string(section[start:end]), true
701 // Section returns a section with the given name, or nil if no such
703 func (f *File) Section(name string) *Section {
704 for _, s := range f.Sections {
712 // applyRelocations applies relocations to dst. rels is a relocations section
713 // in REL or RELA format.
714 func (f *File) applyRelocations(dst []byte, rels []byte) error {
716 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
717 return f.applyRelocationsAMD64(dst, rels)
718 case f.Class == ELFCLASS32 && f.Machine == EM_386:
719 return f.applyRelocations386(dst, rels)
720 case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
721 return f.applyRelocationsARM(dst, rels)
722 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
723 return f.applyRelocationsARM64(dst, rels)
724 case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
725 return f.applyRelocationsPPC(dst, rels)
726 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
727 return f.applyRelocationsPPC64(dst, rels)
728 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
729 return f.applyRelocationsMIPS(dst, rels)
730 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
731 return f.applyRelocationsMIPS64(dst, rels)
732 case f.Class == ELFCLASS64 && f.Machine == EM_LOONGARCH:
733 return f.applyRelocationsLOONG64(dst, rels)
734 case f.Class == ELFCLASS64 && f.Machine == EM_RISCV:
735 return f.applyRelocationsRISCV64(dst, rels)
736 case f.Class == ELFCLASS64 && f.Machine == EM_S390:
737 return f.applyRelocationss390x(dst, rels)
738 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
739 return f.applyRelocationsSPARC64(dst, rels)
741 return errors.New("applyRelocations: not implemented")
745 // canApplyRelocation reports whether we should try to apply a
746 // relocation to a DWARF data section, given a pointer to the symbol
747 // targeted by the relocation.
748 // Most relocations in DWARF data tend to be section-relative, but
749 // some target non-section symbols (for example, low_PC attrs on
750 // subprogram or compilation unit DIEs that target function symbols).
751 func canApplyRelocation(sym *Symbol) bool {
752 return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE
755 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
756 // 24 is the size of Rela64.
757 if len(rels)%24 != 0 {
758 return errors.New("length of relocation section is not a multiple of 24")
761 symbols, _, err := f.getSymbols(SHT_SYMTAB)
766 b := bytes.NewReader(rels)
770 binary.Read(b, f.ByteOrder, &rela)
771 symNo := rela.Info >> 32
772 t := R_X86_64(rela.Info & 0xffff)
774 if symNo == 0 || symNo > uint64(len(symbols)) {
777 sym := &symbols[symNo-1]
778 if !canApplyRelocation(sym) {
782 // There are relocations, so this must be a normal
783 // object file. The code below handles only basic relocations
784 // of the form S + A (symbol plus addend).
788 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
791 val64 := sym.Value + uint64(rela.Addend)
792 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
794 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
797 val32 := uint32(sym.Value) + uint32(rela.Addend)
798 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
805 func (f *File) applyRelocations386(dst []byte, rels []byte) error {
806 // 8 is the size of Rel32.
807 if len(rels)%8 != 0 {
808 return errors.New("length of relocation section is not a multiple of 8")
811 symbols, _, err := f.getSymbols(SHT_SYMTAB)
816 b := bytes.NewReader(rels)
820 binary.Read(b, f.ByteOrder, &rel)
821 symNo := rel.Info >> 8
822 t := R_386(rel.Info & 0xff)
824 if symNo == 0 || symNo > uint32(len(symbols)) {
827 sym := &symbols[symNo-1]
830 if rel.Off+4 >= uint32(len(dst)) {
833 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
834 val += uint32(sym.Value)
835 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
842 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
843 // 8 is the size of Rel32.
844 if len(rels)%8 != 0 {
845 return errors.New("length of relocation section is not a multiple of 8")
848 symbols, _, err := f.getSymbols(SHT_SYMTAB)
853 b := bytes.NewReader(rels)
857 binary.Read(b, f.ByteOrder, &rel)
858 symNo := rel.Info >> 8
859 t := R_ARM(rel.Info & 0xff)
861 if symNo == 0 || symNo > uint32(len(symbols)) {
864 sym := &symbols[symNo-1]
868 if rel.Off+4 >= uint32(len(dst)) {
871 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
872 val += uint32(sym.Value)
873 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
880 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
881 // 24 is the size of Rela64.
882 if len(rels)%24 != 0 {
883 return errors.New("length of relocation section is not a multiple of 24")
886 symbols, _, err := f.getSymbols(SHT_SYMTAB)
891 b := bytes.NewReader(rels)
895 binary.Read(b, f.ByteOrder, &rela)
896 symNo := rela.Info >> 32
897 t := R_AARCH64(rela.Info & 0xffff)
899 if symNo == 0 || symNo > uint64(len(symbols)) {
902 sym := &symbols[symNo-1]
903 if !canApplyRelocation(sym) {
907 // There are relocations, so this must be a normal
908 // object file. The code below handles only basic relocations
909 // of the form S + A (symbol plus addend).
912 case R_AARCH64_ABS64:
913 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
916 val64 := sym.Value + uint64(rela.Addend)
917 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
918 case R_AARCH64_ABS32:
919 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
922 val32 := uint32(sym.Value) + uint32(rela.Addend)
923 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
930 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
931 // 12 is the size of Rela32.
932 if len(rels)%12 != 0 {
933 return errors.New("length of relocation section is not a multiple of 12")
936 symbols, _, err := f.getSymbols(SHT_SYMTAB)
941 b := bytes.NewReader(rels)
945 binary.Read(b, f.ByteOrder, &rela)
946 symNo := rela.Info >> 8
947 t := R_PPC(rela.Info & 0xff)
949 if symNo == 0 || symNo > uint32(len(symbols)) {
952 sym := &symbols[symNo-1]
953 if !canApplyRelocation(sym) {
959 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
962 val32 := uint32(sym.Value) + uint32(rela.Addend)
963 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
970 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
971 // 24 is the size of Rela64.
972 if len(rels)%24 != 0 {
973 return errors.New("length of relocation section is not a multiple of 24")
976 symbols, _, err := f.getSymbols(SHT_SYMTAB)
981 b := bytes.NewReader(rels)
985 binary.Read(b, f.ByteOrder, &rela)
986 symNo := rela.Info >> 32
987 t := R_PPC64(rela.Info & 0xffff)
989 if symNo == 0 || symNo > uint64(len(symbols)) {
992 sym := &symbols[symNo-1]
993 if !canApplyRelocation(sym) {
999 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1002 val64 := sym.Value + uint64(rela.Addend)
1003 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1004 case R_PPC64_ADDR32:
1005 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1008 val32 := uint32(sym.Value) + uint32(rela.Addend)
1009 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1016 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
1017 // 8 is the size of Rel32.
1018 if len(rels)%8 != 0 {
1019 return errors.New("length of relocation section is not a multiple of 8")
1022 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1027 b := bytes.NewReader(rels)
1031 binary.Read(b, f.ByteOrder, &rel)
1032 symNo := rel.Info >> 8
1033 t := R_MIPS(rel.Info & 0xff)
1035 if symNo == 0 || symNo > uint32(len(symbols)) {
1038 sym := &symbols[symNo-1]
1042 if rel.Off+4 >= uint32(len(dst)) {
1045 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
1046 val += uint32(sym.Value)
1047 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
1054 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
1055 // 24 is the size of Rela64.
1056 if len(rels)%24 != 0 {
1057 return errors.New("length of relocation section is not a multiple of 24")
1060 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1065 b := bytes.NewReader(rels)
1069 binary.Read(b, f.ByteOrder, &rela)
1072 if f.ByteOrder == binary.BigEndian {
1073 symNo = rela.Info >> 32
1074 t = R_MIPS(rela.Info & 0xff)
1076 symNo = rela.Info & 0xffffffff
1077 t = R_MIPS(rela.Info >> 56)
1080 if symNo == 0 || symNo > uint64(len(symbols)) {
1083 sym := &symbols[symNo-1]
1084 if !canApplyRelocation(sym) {
1090 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1093 val64 := sym.Value + uint64(rela.Addend)
1094 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1096 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1099 val32 := uint32(sym.Value) + uint32(rela.Addend)
1100 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1107 func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error {
1108 // 24 is the size of Rela64.
1109 if len(rels)%24 != 0 {
1110 return errors.New("length of relocation section is not a multiple of 24")
1113 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1118 b := bytes.NewReader(rels)
1122 binary.Read(b, f.ByteOrder, &rela)
1125 symNo = rela.Info >> 32
1126 t = R_LARCH(rela.Info & 0xffff)
1128 if symNo == 0 || symNo > uint64(len(symbols)) {
1131 sym := &symbols[symNo-1]
1132 if !canApplyRelocation(sym) {
1138 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1141 val64 := sym.Value + uint64(rela.Addend)
1142 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1144 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1147 val32 := uint32(sym.Value) + uint32(rela.Addend)
1148 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1155 func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
1156 // 24 is the size of Rela64.
1157 if len(rels)%24 != 0 {
1158 return errors.New("length of relocation section is not a multiple of 24")
1161 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1166 b := bytes.NewReader(rels)
1170 binary.Read(b, f.ByteOrder, &rela)
1171 symNo := rela.Info >> 32
1172 t := R_RISCV(rela.Info & 0xffff)
1174 if symNo == 0 || symNo > uint64(len(symbols)) {
1177 sym := &symbols[symNo-1]
1178 if !canApplyRelocation(sym) {
1184 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1187 val64 := sym.Value + uint64(rela.Addend)
1188 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1190 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1193 val32 := uint32(sym.Value) + uint32(rela.Addend)
1194 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1201 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
1202 // 24 is the size of Rela64.
1203 if len(rels)%24 != 0 {
1204 return errors.New("length of relocation section is not a multiple of 24")
1207 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1212 b := bytes.NewReader(rels)
1216 binary.Read(b, f.ByteOrder, &rela)
1217 symNo := rela.Info >> 32
1218 t := R_390(rela.Info & 0xffff)
1220 if symNo == 0 || symNo > uint64(len(symbols)) {
1223 sym := &symbols[symNo-1]
1224 if !canApplyRelocation(sym) {
1230 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1233 val64 := sym.Value + uint64(rela.Addend)
1234 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1236 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1239 val32 := uint32(sym.Value) + uint32(rela.Addend)
1240 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1247 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
1248 // 24 is the size of Rela64.
1249 if len(rels)%24 != 0 {
1250 return errors.New("length of relocation section is not a multiple of 24")
1253 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1258 b := bytes.NewReader(rels)
1262 binary.Read(b, f.ByteOrder, &rela)
1263 symNo := rela.Info >> 32
1264 t := R_SPARC(rela.Info & 0xff)
1266 if symNo == 0 || symNo > uint64(len(symbols)) {
1269 sym := &symbols[symNo-1]
1270 if !canApplyRelocation(sym) {
1275 case R_SPARC_64, R_SPARC_UA64:
1276 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1279 val64 := sym.Value + uint64(rela.Addend)
1280 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1281 case R_SPARC_32, R_SPARC_UA32:
1282 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1285 val32 := uint32(sym.Value) + uint32(rela.Addend)
1286 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1293 func (f *File) DWARF() (*dwarf.Data, error) {
1294 dwarfSuffix := func(s *Section) string {
1296 case strings.HasPrefix(s.Name, ".debug_"):
1298 case strings.HasPrefix(s.Name, ".zdebug_"):
1305 // sectionData gets the data for s, checks its size, and
1306 // applies any applicable relations.
1307 sectionData := func(i int, s *Section) ([]byte, error) {
1309 if err != nil && uint64(len(b)) < s.Size {
1313 if len(b) >= 12 && string(b[:4]) == "ZLIB" {
1314 dlen = binary.BigEndian.Uint64(b[4:12])
1315 s.compressionOffset = 12
1317 if dlen == 0 && len(b) >= 12 && s.Flags&SHF_COMPRESSED != 0 &&
1318 s.Flags&SHF_ALLOC == 0 &&
1319 f.FileHeader.ByteOrder.Uint32(b[:]) == uint32(COMPRESS_ZLIB) {
1320 s.compressionType = COMPRESS_ZLIB
1321 switch f.FileHeader.Class {
1323 // Chdr32.Size offset
1324 dlen = uint64(f.FileHeader.ByteOrder.Uint32(b[4:]))
1325 s.compressionOffset = 12
1328 return nil, errors.New("invalid compress header 64")
1330 // Chdr64.Size offset
1331 dlen = f.FileHeader.ByteOrder.Uint64(b[8:])
1332 s.compressionOffset = 24
1334 return nil, fmt.Errorf("unsupported compress header:%s", f.FileHeader.Class)
1338 r, err := zlib.NewReader(bytes.NewBuffer(b[s.compressionOffset:]))
1342 b, err = saferio.ReadData(r, dlen)
1346 if err := r.Close(); err != nil {
1351 if f.Type == ET_EXEC {
1352 // Do not apply relocations to DWARF sections for ET_EXEC binaries.
1353 // Relocations should already be applied, and .rela sections may
1354 // contain incorrect data.
1358 for _, r := range f.Sections {
1359 if r.Type != SHT_RELA && r.Type != SHT_REL {
1362 if int(r.Info) != i {
1369 err = f.applyRelocations(b, rd)
1377 // There are many DWARf sections, but these are the ones
1378 // the debug/dwarf package started with.
1379 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1380 for i, s := range f.Sections {
1381 suffix := dwarfSuffix(s)
1385 if _, ok := dat[suffix]; !ok {
1388 b, err := sectionData(i, s)
1395 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1400 // Look for DWARF4 .debug_types sections and DWARF5 sections.
1401 for i, s := range f.Sections {
1402 suffix := dwarfSuffix(s)
1406 if _, ok := dat[suffix]; ok {
1411 b, err := sectionData(i, s)
1416 if suffix == "types" {
1417 if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil {
1421 if err := d.AddSection(".debug_"+suffix, b); err != nil {
1430 // Symbols returns the symbol table for f. The symbols will be listed in the order
1431 // they appear in f.
1433 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
1434 // After retrieving the symbols as symtab, an externally supplied index x
1435 // corresponds to symtab[x-1], not symtab[x].
1436 func (f *File) Symbols() ([]Symbol, error) {
1437 sym, _, err := f.getSymbols(SHT_SYMTAB)
1441 // DynamicSymbols returns the dynamic symbol table for f. The symbols
1442 // will be listed in the order they appear in f.
1444 // If f has a symbol version table, the returned Symbols will have
1445 // initialized Version and Library fields.
1447 // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
1448 // After retrieving the symbols as symtab, an externally supplied index x
1449 // corresponds to symtab[x-1], not symtab[x].
1450 func (f *File) DynamicSymbols() ([]Symbol, error) {
1451 sym, str, err := f.getSymbols(SHT_DYNSYM)
1455 if f.gnuVersionInit(str) {
1456 for i := range sym {
1457 sym[i].Library, sym[i].Version = f.gnuVersion(i)
1463 type ImportedSymbol struct {
1469 // ImportedSymbols returns the names of all symbols
1470 // referred to by the binary f that are expected to be
1471 // satisfied by other libraries at dynamic load time.
1472 // It does not return weak symbols.
1473 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
1474 sym, str, err := f.getSymbols(SHT_DYNSYM)
1478 f.gnuVersionInit(str)
1479 var all []ImportedSymbol
1480 for i, s := range sym {
1481 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
1482 all = append(all, ImportedSymbol{Name: s.Name})
1483 sym := &all[len(all)-1]
1484 sym.Library, sym.Version = f.gnuVersion(i)
1490 type verneed struct {
1495 // gnuVersionInit parses the GNU version tables
1496 // for use by calls to gnuVersion.
1497 func (f *File) gnuVersionInit(str []byte) bool {
1498 if f.gnuNeed != nil {
1499 // Already initialized
1503 // Accumulate verneed information.
1504 vn := f.SectionByType(SHT_GNU_VERNEED)
1516 vers := f.ByteOrder.Uint16(d[i : i+2])
1520 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
1521 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
1522 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
1523 next := f.ByteOrder.Uint32(d[i+12 : i+16])
1524 file, _ := getString(str, int(fileoff))
1528 for c := 0; c < int(cnt); c++ {
1532 // hash := f.ByteOrder.Uint32(d[j:j+4])
1533 // flags := f.ByteOrder.Uint16(d[j+4:j+6])
1534 other := f.ByteOrder.Uint16(d[j+6 : j+8])
1535 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
1536 next := f.ByteOrder.Uint32(d[j+12 : j+16])
1537 name, _ = getString(str, int(nameoff))
1539 if ndx >= len(need) {
1540 a := make([]verneed, 2*(ndx+1))
1545 need[ndx] = verneed{file, name}
1558 // Versym parallels symbol table, indexing into verneed.
1559 vs := f.SectionByType(SHT_GNU_VERSYM)
1570 // gnuVersion adds Library and Version information to sym,
1571 // which came from offset i of the symbol table.
1572 func (f *File) gnuVersion(i int) (library string, version string) {
1573 // Each entry is two bytes; skip undef entry at beginning.
1575 if i >= len(f.gnuVersym) {
1578 s := f.gnuVersym[i:]
1582 j := int(f.ByteOrder.Uint16(s))
1583 if j < 2 || j >= len(f.gnuNeed) {
1587 return n.File, n.Name
1590 // ImportedLibraries returns the names of all libraries
1591 // referred to by the binary f that are expected to be
1592 // linked with the binary at dynamic link time.
1593 func (f *File) ImportedLibraries() ([]string, error) {
1594 return f.DynString(DT_NEEDED)
1597 // DynString returns the strings listed for the given tag in the file's dynamic
1600 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
1602 func (f *File) DynString(tag DynTag) ([]string, error) {
1604 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
1606 return nil, fmt.Errorf("non-string-valued tag %v", tag)
1608 ds := f.SectionByType(SHT_DYNAMIC)
1610 // not dynamic, so no libraries
1617 str, err := f.stringTable(ds.Link)
1627 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1628 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1631 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1632 v = f.ByteOrder.Uint64(d[8:16])
1636 s, ok := getString(str, int(v))
1638 all = append(all, s)
1645 // DynValue returns the values listed for the given tag in the file's dynamic
1647 func (f *File) DynValue(tag DynTag) ([]uint64, error) {
1648 ds := f.SectionByType(SHT_DYNAMIC)
1657 // Parse the .dynamic section as a string of bytes.
1664 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1665 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1668 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1669 v = f.ByteOrder.Uint64(d[8:16])
1673 vals = append(vals, v)
1679 type nobitsSectionReader struct{}
1681 func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) {
1682 return 0, errors.New("unexpected read from SHT_NOBITS section")