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.
32 // seekStart, seekCurrent, seekEnd are copies of
33 // io.SeekStart, io.SeekCurrent, and io.SeekEnd.
34 // We can't use the ones from package io because
35 // we want this code to build with Go 1.4 during
36 // cmd/dist bootstrap.
43 // TODO: error reporting detail
46 * Internal ELF representation
49 // A FileHeader represents an ELF file header.
50 type FileHeader struct {
56 ByteOrder binary.ByteOrder
62 // A File represents an open ELF file.
72 // A SectionHeader represents a single ELF section header.
73 type SectionHeader struct {
85 // FileSize is the size of this section in the file in bytes.
86 // If a section is compressed, FileSize is the size of the
87 // compressed data, while Size (above) is the size of the
92 // A Section represents a single section in an ELF file.
96 // Embed ReaderAt for ReadAt method.
97 // Do not embed SectionReader directly
98 // to avoid having Read and Seek.
99 // If a client wants Read and Seek it must use
100 // Open() to avoid fighting over the seek offset
101 // with other clients.
103 // ReaderAt may be nil if the section is not easily available
104 // in a random-access form. For example, a compressed section
105 // may have a nil ReaderAt.
109 compressionType CompressionType
110 compressionOffset int64
113 // Data reads and returns the contents of the ELF section.
114 // Even if the section is stored compressed in the ELF file,
115 // Data returns uncompressed data.
117 // For an SHT_NOBITS section, Data always returns a non-nil error.
118 func (s *Section) Data() ([]byte, error) {
119 return saferio.ReadData(s.Open(), s.Size)
122 // stringTable reads and returns the string table given by the
123 // specified link value.
124 func (f *File) stringTable(link uint32) ([]byte, error) {
125 if link <= 0 || link >= uint32(len(f.Sections)) {
126 return nil, errors.New("section has invalid string table link")
128 return f.Sections[link].Data()
131 // Open returns a new ReadSeeker reading the ELF section.
132 // Even if the section is stored compressed in the ELF file,
133 // the ReadSeeker reads uncompressed data.
135 // For an SHT_NOBITS section, all calls to the opened reader
136 // will return a non-nil error.
137 func (s *Section) Open() io.ReadSeeker {
138 if s.Type == SHT_NOBITS {
139 return io.NewSectionReader(&nobitsSectionReader{}, 0, int64(s.Size))
142 var zrd func(io.Reader) (io.ReadCloser, error)
143 if s.Flags&SHF_COMPRESSED == 0 {
145 if !strings.HasPrefix(s.Name, ".zdebug") {
146 return io.NewSectionReader(s.sr, 0, 1<<63-1)
149 b := make([]byte, 12)
150 n, _ := s.sr.ReadAt(b, 0)
151 if n != 12 || string(b[:4]) != "ZLIB" {
152 return io.NewSectionReader(s.sr, 0, 1<<63-1)
155 s.compressionOffset = 12
156 s.compressionType = COMPRESS_ZLIB
157 s.Size = binary.BigEndian.Uint64(b[4:12])
160 } else if s.Flags&SHF_ALLOC != 0 {
161 return errorReader{&FormatError{int64(s.Offset),
162 "SHF_COMPRESSED applies only to non-allocable sections", s.compressionType}}
165 switch s.compressionType {
169 zrd = func(r io.Reader) (io.ReadCloser, error) {
170 return io.NopCloser(zstd.NewReader(r)), nil
175 return errorReader{&FormatError{int64(s.Offset), "unknown compression type", s.compressionType}}
178 return &readSeekerFromReader{
179 reset: func() (io.Reader, error) {
180 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
187 // A ProgHeader represents a single ELF program header.
188 type ProgHeader struct {
199 // A Prog represents a single ELF program header in an ELF binary.
203 // Embed ReaderAt for ReadAt method.
204 // Do not embed SectionReader directly
205 // to avoid having Read and Seek.
206 // If a client wants Read and Seek it must use
207 // Open() to avoid fighting over the seek offset
208 // with other clients.
213 // Open returns a new ReadSeeker reading the ELF program body.
214 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
216 // A Symbol represents an entry in an ELF symbol table section.
223 // Version and Library are present only for the dynamic symbol
233 type FormatError struct {
239 func (e *FormatError) Error() string {
242 msg += fmt.Sprintf(" '%v' ", e.val)
244 msg += fmt.Sprintf("in record at byte %#x", e.off)
248 // Open opens the named file using os.Open and prepares it for use as an ELF binary.
249 func Open(name string) (*File, error) {
250 f, err := os.Open(name)
254 ff, err := NewFile(f)
263 // Close closes the File.
264 // If the File was created using NewFile directly instead of Open,
265 // Close has no effect.
266 func (f *File) Close() error {
269 err = f.closer.Close()
275 // SectionByType returns the first section in f with the
276 // given type, or nil if there is no such section.
277 func (f *File) SectionByType(typ SectionType) *Section {
278 for _, s := range f.Sections {
286 // NewFile creates a new File for accessing an ELF binary in an underlying reader.
287 // The ELF binary is expected to start at position 0 in the ReaderAt.
288 func NewFile(r io.ReaderAt) (*File, error) {
289 sr := io.NewSectionReader(r, 0, 1<<63-1)
290 // Read and decode ELF identifier
292 if _, err := r.ReadAt(ident[0:], 0); err != nil {
295 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
296 return nil, &FormatError{0, "bad magic number", ident[0:4]}
300 f.Class = Class(ident[EI_CLASS])
306 return nil, &FormatError{0, "unknown ELF class", f.Class}
309 f.Data = Data(ident[EI_DATA])
312 f.ByteOrder = binary.LittleEndian
314 f.ByteOrder = binary.BigEndian
316 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
319 f.Version = Version(ident[EI_VERSION])
320 if f.Version != EV_CURRENT {
321 return nil, &FormatError{0, "unknown ELF version", f.Version}
324 f.OSABI = OSABI(ident[EI_OSABI])
325 f.ABIVersion = ident[EI_ABIVERSION]
327 // Read ELF file header
329 var phentsize, phnum int
331 var shentsize, shnum, shstrndx int
335 sr.Seek(0, seekStart)
336 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
339 f.Type = Type(hdr.Type)
340 f.Machine = Machine(hdr.Machine)
341 f.Entry = uint64(hdr.Entry)
342 if v := Version(hdr.Version); v != f.Version {
343 return nil, &FormatError{0, "mismatched ELF version", v}
345 phoff = int64(hdr.Phoff)
346 phentsize = int(hdr.Phentsize)
347 phnum = int(hdr.Phnum)
348 shoff = int64(hdr.Shoff)
349 shentsize = int(hdr.Shentsize)
350 shnum = int(hdr.Shnum)
351 shstrndx = int(hdr.Shstrndx)
354 sr.Seek(0, seekStart)
355 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
358 f.Type = Type(hdr.Type)
359 f.Machine = Machine(hdr.Machine)
361 if v := Version(hdr.Version); v != f.Version {
362 return nil, &FormatError{0, "mismatched ELF version", v}
364 phoff = int64(hdr.Phoff)
365 phentsize = int(hdr.Phentsize)
366 phnum = int(hdr.Phnum)
367 shoff = int64(hdr.Shoff)
368 shentsize = int(hdr.Shentsize)
369 shnum = int(hdr.Shnum)
370 shstrndx = int(hdr.Shstrndx)
374 return nil, &FormatError{0, "invalid shoff", shoff}
377 return nil, &FormatError{0, "invalid phoff", phoff}
380 if shoff == 0 && shnum != 0 {
381 return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum}
384 if shnum > 0 && shstrndx >= shnum {
385 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
388 var wantPhentsize, wantShentsize int
391 wantPhentsize = 8 * 4
392 wantShentsize = 10 * 4
394 wantPhentsize = 2*4 + 6*8
395 wantShentsize = 4*4 + 6*8
397 if phnum > 0 && phentsize < wantPhentsize {
398 return nil, &FormatError{0, "invalid ELF phentsize", phentsize}
401 // Read program headers
402 f.Progs = make([]*Prog, phnum)
403 for i := 0; i < phnum; i++ {
404 off := phoff + int64(i)*int64(phentsize)
405 sr.Seek(off, seekStart)
410 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
413 p.ProgHeader = ProgHeader{
414 Type: ProgType(ph.Type),
415 Flags: ProgFlag(ph.Flags),
417 Vaddr: uint64(ph.Vaddr),
418 Paddr: uint64(ph.Paddr),
419 Filesz: uint64(ph.Filesz),
420 Memsz: uint64(ph.Memsz),
421 Align: uint64(ph.Align),
425 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
428 p.ProgHeader = ProgHeader{
429 Type: ProgType(ph.Type),
430 Flags: ProgFlag(ph.Flags),
439 if int64(p.Off) < 0 {
440 return nil, &FormatError{off, "invalid program header offset", p.Off}
442 if int64(p.Filesz) < 0 {
443 return nil, &FormatError{off, "invalid program header file size", p.Filesz}
445 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
450 // If the number of sections is greater than or equal to SHN_LORESERVE
451 // (0xff00), shnum has the value zero and the actual number of section
452 // header table entries is contained in the sh_size field of the section
453 // header at index 0.
454 if shoff > 0 && shnum == 0 {
456 sr.Seek(shoff, seekStart)
460 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
468 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
475 if SectionType(typ) != SHT_NULL {
476 return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)}
479 if shnum < int(SHN_LORESERVE) {
480 return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum}
483 // If the section name string table section index is greater than or
484 // equal to SHN_LORESERVE (0xff00), this member has the value
485 // SHN_XINDEX (0xffff) and the actual index of the section name
486 // string table section is contained in the sh_link field of the
487 // section header at index 0.
488 if shstrndx == int(SHN_XINDEX) {
490 if shstrndx < int(SHN_LORESERVE) {
491 return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx}
496 if shnum > 0 && shentsize < wantShentsize {
497 return nil, &FormatError{0, "invalid ELF shentsize", shentsize}
500 // Read section headers
501 c := saferio.SliceCap((*Section)(nil), uint64(shnum))
503 return nil, &FormatError{0, "too many sections", shnum}
505 f.Sections = make([]*Section, 0, c)
506 names := make([]uint32, 0, c)
507 for i := 0; i < shnum; i++ {
508 off := shoff + int64(i)*int64(shentsize)
509 sr.Seek(off, seekStart)
514 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
517 names = append(names, sh.Name)
518 s.SectionHeader = SectionHeader{
519 Type: SectionType(sh.Type),
520 Flags: SectionFlag(sh.Flags),
521 Addr: uint64(sh.Addr),
522 Offset: uint64(sh.Off),
523 FileSize: uint64(sh.Size),
526 Addralign: uint64(sh.Addralign),
527 Entsize: uint64(sh.Entsize),
531 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
534 names = append(names, sh.Name)
535 s.SectionHeader = SectionHeader{
536 Type: SectionType(sh.Type),
537 Flags: SectionFlag(sh.Flags),
543 Addralign: sh.Addralign,
547 if int64(s.Offset) < 0 {
548 return nil, &FormatError{off, "invalid section offset", int64(s.Offset)}
550 if int64(s.FileSize) < 0 {
551 return nil, &FormatError{off, "invalid section size", int64(s.FileSize)}
553 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
555 if s.Flags&SHF_COMPRESSED == 0 {
559 // Read the compression header.
563 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
566 s.compressionType = CompressionType(ch.Type)
567 s.Size = uint64(ch.Size)
568 s.Addralign = uint64(ch.Addralign)
569 s.compressionOffset = int64(binary.Size(ch))
572 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
575 s.compressionType = CompressionType(ch.Type)
577 s.Addralign = ch.Addralign
578 s.compressionOffset = int64(binary.Size(ch))
582 f.Sections = append(f.Sections, s)
585 if len(f.Sections) == 0 {
589 // Load section header string table.
591 // If the file has no section name string table,
592 // shstrndx holds the value SHN_UNDEF (0).
595 shstr := f.Sections[shstrndx]
596 if shstr.Type != SHT_STRTAB {
597 return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type}
599 shstrtab, err := shstr.Data()
603 for i, s := range f.Sections {
605 s.Name, ok = getString(shstrtab, int(names[i]))
607 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
614 // getSymbols returns a slice of Symbols from parsing the symbol table
615 // with the given type, along with the associated string table.
616 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
619 return f.getSymbols64(typ)
622 return f.getSymbols32(typ)
625 return nil, nil, errors.New("not implemented")
628 // ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
629 // if there is no such section in the File.
630 var ErrNoSymbols = errors.New("no symbol section")
632 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
633 symtabSection := f.SectionByType(typ)
634 if symtabSection == nil {
635 return nil, nil, ErrNoSymbols
638 data, err := symtabSection.Data()
640 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
642 symtab := bytes.NewReader(data)
643 if symtab.Len()%Sym32Size != 0 {
644 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
647 strdata, err := f.stringTable(symtabSection.Link)
649 return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
652 // The first entry is all zeros.
653 var skip [Sym32Size]byte
656 symbols := make([]Symbol, symtab.Len()/Sym32Size)
660 for symtab.Len() > 0 {
661 binary.Read(symtab, f.ByteOrder, &sym)
662 str, _ := getString(strdata, int(sym.Name))
663 symbols[i].Name = str
664 symbols[i].Info = sym.Info
665 symbols[i].Other = sym.Other
666 symbols[i].Section = SectionIndex(sym.Shndx)
667 symbols[i].Value = uint64(sym.Value)
668 symbols[i].Size = uint64(sym.Size)
672 return symbols, strdata, nil
675 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
676 symtabSection := f.SectionByType(typ)
677 if symtabSection == nil {
678 return nil, nil, ErrNoSymbols
681 data, err := symtabSection.Data()
683 return nil, nil, fmt.Errorf("cannot load symbol section: %w", err)
685 symtab := bytes.NewReader(data)
686 if symtab.Len()%Sym64Size != 0 {
687 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
690 strdata, err := f.stringTable(symtabSection.Link)
692 return nil, nil, fmt.Errorf("cannot load string table section: %w", err)
695 // The first entry is all zeros.
696 var skip [Sym64Size]byte
699 symbols := make([]Symbol, symtab.Len()/Sym64Size)
703 for symtab.Len() > 0 {
704 binary.Read(symtab, f.ByteOrder, &sym)
705 str, _ := getString(strdata, int(sym.Name))
706 symbols[i].Name = str
707 symbols[i].Info = sym.Info
708 symbols[i].Other = sym.Other
709 symbols[i].Section = SectionIndex(sym.Shndx)
710 symbols[i].Value = sym.Value
711 symbols[i].Size = sym.Size
715 return symbols, strdata, nil
718 // getString extracts a string from an ELF string table.
719 func getString(section []byte, start int) (string, bool) {
720 if start < 0 || start >= len(section) {
724 for end := start; end < len(section); end++ {
725 if section[end] == 0 {
726 return string(section[start:end]), true
732 // Section returns a section with the given name, or nil if no such
734 func (f *File) Section(name string) *Section {
735 for _, s := range f.Sections {
743 // applyRelocations applies relocations to dst. rels is a relocations section
744 // in REL or RELA format.
745 func (f *File) applyRelocations(dst []byte, rels []byte) error {
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)
772 return errors.New("applyRelocations: not implemented")
776 // canApplyRelocation reports whether we should try to apply a
777 // relocation to a DWARF data section, given a pointer to the symbol
778 // targeted by the relocation.
779 // Most relocations in DWARF data tend to be section-relative, but
780 // some target non-section symbols (for example, low_PC attrs on
781 // subprogram or compilation unit DIEs that target function symbols).
782 func canApplyRelocation(sym *Symbol) bool {
783 return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE
786 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
787 // 24 is the size of Rela64.
788 if len(rels)%24 != 0 {
789 return errors.New("length of relocation section is not a multiple of 24")
792 symbols, _, err := f.getSymbols(SHT_SYMTAB)
797 b := bytes.NewReader(rels)
801 binary.Read(b, f.ByteOrder, &rela)
802 symNo := rela.Info >> 32
803 t := R_X86_64(rela.Info & 0xffff)
805 if symNo == 0 || symNo > uint64(len(symbols)) {
808 sym := &symbols[symNo-1]
809 if !canApplyRelocation(sym) {
813 // There are relocations, so this must be a normal
814 // object file. The code below handles only basic relocations
815 // of the form S + A (symbol plus addend).
819 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
822 val64 := sym.Value + uint64(rela.Addend)
823 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
825 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
828 val32 := uint32(sym.Value) + uint32(rela.Addend)
829 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
836 func (f *File) applyRelocations386(dst []byte, rels []byte) error {
837 // 8 is the size of Rel32.
838 if len(rels)%8 != 0 {
839 return errors.New("length of relocation section is not a multiple of 8")
842 symbols, _, err := f.getSymbols(SHT_SYMTAB)
847 b := bytes.NewReader(rels)
851 binary.Read(b, f.ByteOrder, &rel)
852 symNo := rel.Info >> 8
853 t := R_386(rel.Info & 0xff)
855 if symNo == 0 || symNo > uint32(len(symbols)) {
858 sym := &symbols[symNo-1]
861 if rel.Off+4 >= uint32(len(dst)) {
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)
873 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
874 // 8 is the size of Rel32.
875 if len(rels)%8 != 0 {
876 return errors.New("length of relocation section is not a multiple of 8")
879 symbols, _, err := f.getSymbols(SHT_SYMTAB)
884 b := bytes.NewReader(rels)
888 binary.Read(b, f.ByteOrder, &rel)
889 symNo := rel.Info >> 8
890 t := R_ARM(rel.Info & 0xff)
892 if symNo == 0 || symNo > uint32(len(symbols)) {
895 sym := &symbols[symNo-1]
899 if rel.Off+4 >= uint32(len(dst)) {
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)
911 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
912 // 24 is the size of Rela64.
913 if len(rels)%24 != 0 {
914 return errors.New("length of relocation section is not a multiple of 24")
917 symbols, _, err := f.getSymbols(SHT_SYMTAB)
922 b := bytes.NewReader(rels)
926 binary.Read(b, f.ByteOrder, &rela)
927 symNo := rela.Info >> 32
928 t := R_AARCH64(rela.Info & 0xffff)
930 if symNo == 0 || symNo > uint64(len(symbols)) {
933 sym := &symbols[symNo-1]
934 if !canApplyRelocation(sym) {
938 // There are relocations, so this must be a normal
939 // object file. The code below handles only basic relocations
940 // of the form S + A (symbol plus addend).
943 case R_AARCH64_ABS64:
944 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
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 {
953 val32 := uint32(sym.Value) + uint32(rela.Addend)
954 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
961 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
962 // 12 is the size of Rela32.
963 if len(rels)%12 != 0 {
964 return errors.New("length of relocation section is not a multiple of 12")
967 symbols, _, err := f.getSymbols(SHT_SYMTAB)
972 b := bytes.NewReader(rels)
976 binary.Read(b, f.ByteOrder, &rela)
977 symNo := rela.Info >> 8
978 t := R_PPC(rela.Info & 0xff)
980 if symNo == 0 || symNo > uint32(len(symbols)) {
983 sym := &symbols[symNo-1]
984 if !canApplyRelocation(sym) {
990 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
993 val32 := uint32(sym.Value) + uint32(rela.Addend)
994 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1001 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
1002 // 24 is the size of Rela64.
1003 if len(rels)%24 != 0 {
1004 return errors.New("length of relocation section is not a multiple of 24")
1007 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1012 b := bytes.NewReader(rels)
1016 binary.Read(b, f.ByteOrder, &rela)
1017 symNo := rela.Info >> 32
1018 t := R_PPC64(rela.Info & 0xffff)
1020 if symNo == 0 || symNo > uint64(len(symbols)) {
1023 sym := &symbols[symNo-1]
1024 if !canApplyRelocation(sym) {
1029 case R_PPC64_ADDR64:
1030 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
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 {
1039 val32 := uint32(sym.Value) + uint32(rela.Addend)
1040 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1047 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
1048 // 8 is the size of Rel32.
1049 if len(rels)%8 != 0 {
1050 return errors.New("length of relocation section is not a multiple of 8")
1053 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1058 b := bytes.NewReader(rels)
1062 binary.Read(b, f.ByteOrder, &rel)
1063 symNo := rel.Info >> 8
1064 t := R_MIPS(rel.Info & 0xff)
1066 if symNo == 0 || symNo > uint32(len(symbols)) {
1069 sym := &symbols[symNo-1]
1073 if rel.Off+4 >= uint32(len(dst)) {
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)
1085 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
1086 // 24 is the size of Rela64.
1087 if len(rels)%24 != 0 {
1088 return errors.New("length of relocation section is not a multiple of 24")
1091 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1096 b := bytes.NewReader(rels)
1100 binary.Read(b, f.ByteOrder, &rela)
1103 if f.ByteOrder == binary.BigEndian {
1104 symNo = rela.Info >> 32
1105 t = R_MIPS(rela.Info & 0xff)
1107 symNo = rela.Info & 0xffffffff
1108 t = R_MIPS(rela.Info >> 56)
1111 if symNo == 0 || symNo > uint64(len(symbols)) {
1114 sym := &symbols[symNo-1]
1115 if !canApplyRelocation(sym) {
1121 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1124 val64 := sym.Value + uint64(rela.Addend)
1125 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1127 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1130 val32 := uint32(sym.Value) + uint32(rela.Addend)
1131 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1138 func (f *File) applyRelocationsLOONG64(dst []byte, rels []byte) error {
1139 // 24 is the size of Rela64.
1140 if len(rels)%24 != 0 {
1141 return errors.New("length of relocation section is not a multiple of 24")
1144 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1149 b := bytes.NewReader(rels)
1153 binary.Read(b, f.ByteOrder, &rela)
1156 symNo = rela.Info >> 32
1157 t = R_LARCH(rela.Info & 0xffff)
1159 if symNo == 0 || symNo > uint64(len(symbols)) {
1162 sym := &symbols[symNo-1]
1163 if !canApplyRelocation(sym) {
1169 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1172 val64 := sym.Value + uint64(rela.Addend)
1173 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1175 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1178 val32 := uint32(sym.Value) + uint32(rela.Addend)
1179 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1186 func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
1187 // 24 is the size of Rela64.
1188 if len(rels)%24 != 0 {
1189 return errors.New("length of relocation section is not a multiple of 24")
1192 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1197 b := bytes.NewReader(rels)
1201 binary.Read(b, f.ByteOrder, &rela)
1202 symNo := rela.Info >> 32
1203 t := R_RISCV(rela.Info & 0xffff)
1205 if symNo == 0 || symNo > uint64(len(symbols)) {
1208 sym := &symbols[symNo-1]
1209 if !canApplyRelocation(sym) {
1215 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1218 val64 := sym.Value + uint64(rela.Addend)
1219 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1221 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1224 val32 := uint32(sym.Value) + uint32(rela.Addend)
1225 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1232 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
1233 // 24 is the size of Rela64.
1234 if len(rels)%24 != 0 {
1235 return errors.New("length of relocation section is not a multiple of 24")
1238 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1243 b := bytes.NewReader(rels)
1247 binary.Read(b, f.ByteOrder, &rela)
1248 symNo := rela.Info >> 32
1249 t := R_390(rela.Info & 0xffff)
1251 if symNo == 0 || symNo > uint64(len(symbols)) {
1254 sym := &symbols[symNo-1]
1255 if !canApplyRelocation(sym) {
1261 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1264 val64 := sym.Value + uint64(rela.Addend)
1265 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1267 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1270 val32 := uint32(sym.Value) + uint32(rela.Addend)
1271 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1278 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
1279 // 24 is the size of Rela64.
1280 if len(rels)%24 != 0 {
1281 return errors.New("length of relocation section is not a multiple of 24")
1284 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1289 b := bytes.NewReader(rels)
1293 binary.Read(b, f.ByteOrder, &rela)
1294 symNo := rela.Info >> 32
1295 t := R_SPARC(rela.Info & 0xff)
1297 if symNo == 0 || symNo > uint64(len(symbols)) {
1300 sym := &symbols[symNo-1]
1301 if !canApplyRelocation(sym) {
1306 case R_SPARC_64, R_SPARC_UA64:
1307 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
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 {
1316 val32 := uint32(sym.Value) + uint32(rela.Addend)
1317 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1324 func (f *File) DWARF() (*dwarf.Data, error) {
1325 dwarfSuffix := func(s *Section) string {
1327 case strings.HasPrefix(s.Name, ".debug_"):
1329 case strings.HasPrefix(s.Name, ".zdebug_"):
1336 // sectionData gets the data for s, checks its size, and
1337 // applies any applicable relations.
1338 sectionData := func(i int, s *Section) ([]byte, error) {
1340 if err != nil && uint64(len(b)) < s.Size {
1344 if f.Type == ET_EXEC {
1345 // Do not apply relocations to DWARF sections for ET_EXEC binaries.
1346 // Relocations should already be applied, and .rela sections may
1347 // contain incorrect data.
1351 for _, r := range f.Sections {
1352 if r.Type != SHT_RELA && r.Type != SHT_REL {
1355 if int(r.Info) != i {
1362 err = f.applyRelocations(b, rd)
1370 // There are many DWARf sections, but these are the ones
1371 // the debug/dwarf package started with.
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)
1378 if _, ok := dat[suffix]; !ok {
1381 b, err := sectionData(i, s)
1388 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1393 // Look for DWARF4 .debug_types sections and DWARF5 sections.
1394 for i, s := range f.Sections {
1395 suffix := dwarfSuffix(s)
1399 if _, ok := dat[suffix]; ok {
1404 b, err := sectionData(i, s)
1409 if suffix == "types" {
1410 if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil {
1414 if err := d.AddSection(".debug_"+suffix, b); err != nil {
1423 // Symbols returns the symbol table for f. The symbols will be listed in the order
1424 // they appear in f.
1426 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
1427 // After retrieving the symbols as symtab, an externally supplied index x
1428 // corresponds to symtab[x-1], not symtab[x].
1429 func (f *File) Symbols() ([]Symbol, error) {
1430 sym, _, err := f.getSymbols(SHT_SYMTAB)
1434 // DynamicSymbols returns the dynamic symbol table for f. The symbols
1435 // will be listed in the order they appear in f.
1437 // If f has a symbol version table, the returned Symbols will have
1438 // initialized Version and Library fields.
1440 // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
1441 // After retrieving the symbols as symtab, an externally supplied index x
1442 // corresponds to symtab[x-1], not symtab[x].
1443 func (f *File) DynamicSymbols() ([]Symbol, error) {
1444 sym, str, err := f.getSymbols(SHT_DYNSYM)
1448 if f.gnuVersionInit(str) {
1449 for i := range sym {
1450 sym[i].Library, sym[i].Version = f.gnuVersion(i)
1456 type ImportedSymbol struct {
1462 // ImportedSymbols returns the names of all symbols
1463 // referred to by the binary f that are expected to be
1464 // satisfied by other libraries at dynamic load time.
1465 // It does not return weak symbols.
1466 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
1467 sym, str, err := f.getSymbols(SHT_DYNSYM)
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)
1483 type verneed struct {
1488 // gnuVersionInit parses the GNU version tables
1489 // for use by calls to gnuVersion.
1490 func (f *File) gnuVersionInit(str []byte) bool {
1491 if f.gnuNeed != nil {
1492 // Already initialized
1496 // Accumulate verneed information.
1497 vn := f.SectionByType(SHT_GNU_VERNEED)
1509 vers := f.ByteOrder.Uint16(d[i : i+2])
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))
1521 for c := 0; c < int(cnt); c++ {
1525 // hash := f.ByteOrder.Uint32(d[j:j+4])
1526 // flags := f.ByteOrder.Uint16(d[j+4:j+6])
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))
1532 if ndx >= len(need) {
1533 a := make([]verneed, 2*(ndx+1))
1538 need[ndx] = verneed{file, name}
1551 // Versym parallels symbol table, indexing into verneed.
1552 vs := f.SectionByType(SHT_GNU_VERSYM)
1563 // gnuVersion adds Library and Version information to sym,
1564 // which came from offset i of the symbol table.
1565 func (f *File) gnuVersion(i int) (library string, version string) {
1566 // Each entry is two bytes; skip undef entry at beginning.
1568 if i >= len(f.gnuVersym) {
1571 s := f.gnuVersym[i:]
1575 j := int(f.ByteOrder.Uint16(s))
1576 if j < 2 || j >= len(f.gnuNeed) {
1580 return n.File, n.Name
1583 // ImportedLibraries returns the names of all libraries
1584 // referred to by the binary f that are expected to be
1585 // linked with the binary at dynamic link time.
1586 func (f *File) ImportedLibraries() ([]string, error) {
1587 return f.DynString(DT_NEEDED)
1590 // DynString returns the strings listed for the given tag in the file's dynamic
1593 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
1595 func (f *File) DynString(tag DynTag) ([]string, error) {
1597 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
1599 return nil, fmt.Errorf("non-string-valued tag %v", tag)
1601 ds := f.SectionByType(SHT_DYNAMIC)
1603 // not dynamic, so no libraries
1610 str, err := f.stringTable(ds.Link)
1620 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1621 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1624 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1625 v = f.ByteOrder.Uint64(d[8:16])
1629 s, ok := getString(str, int(v))
1631 all = append(all, s)
1638 // DynValue returns the values listed for the given tag in the file's dynamic
1640 func (f *File) DynValue(tag DynTag) ([]uint64, error) {
1641 ds := f.SectionByType(SHT_DYNAMIC)
1650 // Parse the .dynamic section as a string of bytes.
1657 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1658 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1661 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1662 v = f.ByteOrder.Uint64(d[8:16])
1666 vals = append(vals, v)
1672 type nobitsSectionReader struct{}
1674 func (*nobitsSectionReader) ReadAt(p []byte, off int64) (n int, err error) {
1675 return 0, errors.New("unexpected read from SHT_NOBITS section")