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.
5 // Package elf implements access to ELF object files.
20 // TODO: error reporting detail
23 * Internal ELF representation
26 // A FileHeader represents an ELF file header.
27 type FileHeader
struct {
33 ByteOrder binary
.ByteOrder
39 // A File represents an open ELF file.
49 // A SectionHeader represents a single ELF section header.
50 type SectionHeader
struct {
62 // FileSize is the size of this section in the file in bytes.
63 // If a section is compressed, FileSize is the size of the
64 // compressed data, while Size (above) is the size of the
69 // A Section represents a single section in an ELF file.
73 // Embed ReaderAt for ReadAt method.
74 // Do not embed SectionReader directly
75 // to avoid having Read and Seek.
76 // If a client wants Read and Seek it must use
77 // Open() to avoid fighting over the seek offset
78 // with other clients.
80 // ReaderAt may be nil if the section is not easily available
81 // in a random-access form. For example, a compressed section
82 // may have a nil ReaderAt.
86 compressionType CompressionType
87 compressionOffset
int64
90 // Data reads and returns the contents of the ELF section.
91 // Even if the section is stored compressed in the ELF file,
92 // Data returns uncompressed data.
93 func (s
*Section
) Data() ([]byte, error
) {
94 dat
:= make([]byte, s
.Size
)
95 n
, err
:= io
.ReadFull(s
.Open(), dat
)
99 // stringTable reads and returns the string table given by the
100 // specified link value.
101 func (f
*File
) stringTable(link
uint32) ([]byte, error
) {
102 if link
<= 0 || link
>= uint32(len(f
.Sections
)) {
103 return nil, errors
.New("section has invalid string table link")
105 return f
.Sections
[link
].Data()
108 // Open returns a new ReadSeeker reading the ELF section.
109 // Even if the section is stored compressed in the ELF file,
110 // the ReadSeeker reads uncompressed data.
111 func (s
*Section
) Open() io
.ReadSeeker
{
112 if s
.Flags
&SHF_COMPRESSED
== 0 {
113 return io
.NewSectionReader(s
.sr
, 0, 1<<63-1)
115 if s
.compressionType
== COMPRESS_ZLIB
{
116 return &readSeekerFromReader
{
117 reset
: func() (io
.Reader
, error
) {
118 fr
:= io
.NewSectionReader(s
.sr
, s
.compressionOffset
, int64(s
.FileSize
)-s
.compressionOffset
)
119 return zlib
.NewReader(fr
)
124 err
:= &FormatError
{int64(s
.Offset
), "unknown compression type", s
.compressionType
}
125 return errorReader
{err
}
128 // A ProgHeader represents a single ELF program header.
129 type ProgHeader
struct {
140 // A Prog represents a single ELF program header in an ELF binary.
144 // Embed ReaderAt for ReadAt method.
145 // Do not embed SectionReader directly
146 // to avoid having Read and Seek.
147 // If a client wants Read and Seek it must use
148 // Open() to avoid fighting over the seek offset
149 // with other clients.
154 // Open returns a new ReadSeeker reading the ELF program body.
155 func (p
*Prog
) Open() io
.ReadSeeker
{ return io
.NewSectionReader(p
.sr
, 0, 1<<63-1) }
157 // A Symbol represents an entry in an ELF symbol table section.
169 type FormatError
struct {
175 func (e
*FormatError
) Error() string {
178 msg
+= fmt
.Sprintf(" '%v' ", e
.val
)
180 msg
+= fmt
.Sprintf("in record at byte %#x", e
.off
)
184 // Open opens the named file using os.Open and prepares it for use as an ELF binary.
185 func Open(name
string) (*File
, error
) {
186 f
, err
:= os
.Open(name
)
190 ff
, err
:= NewFile(f
)
199 // Close closes the File.
200 // If the File was created using NewFile directly instead of Open,
201 // Close has no effect.
202 func (f
*File
) Close() error
{
205 err
= f
.closer
.Close()
211 // SectionByType returns the first section in f with the
212 // given type, or nil if there is no such section.
213 func (f
*File
) SectionByType(typ SectionType
) *Section
{
214 for _
, s
:= range f
.Sections
{
222 // NewFile creates a new File for accessing an ELF binary in an underlying reader.
223 // The ELF binary is expected to start at position 0 in the ReaderAt.
224 func NewFile(r io
.ReaderAt
) (*File
, error
) {
225 sr
:= io
.NewSectionReader(r
, 0, 1<<63-1)
226 // Read and decode ELF identifier
228 if _
, err
:= r
.ReadAt(ident
[0:], 0); err
!= nil {
231 if ident
[0] != '\x7f' || ident
[1] != 'E' || ident
[2] != 'L' || ident
[3] != 'F' {
232 return nil, &FormatError
{0, "bad magic number", ident
[0:4]}
236 f
.Class
= Class(ident
[EI_CLASS
])
242 return nil, &FormatError
{0, "unknown ELF class", f
.Class
}
245 f
.Data
= Data(ident
[EI_DATA
])
248 f
.ByteOrder
= binary
.LittleEndian
250 f
.ByteOrder
= binary
.BigEndian
252 return nil, &FormatError
{0, "unknown ELF data encoding", f
.Data
}
255 f
.Version
= Version(ident
[EI_VERSION
])
256 if f
.Version
!= EV_CURRENT
{
257 return nil, &FormatError
{0, "unknown ELF version", f
.Version
}
260 f
.OSABI
= OSABI(ident
[EI_OSABI
])
261 f
.ABIVersion
= ident
[EI_ABIVERSION
]
263 // Read ELF file header
265 var phentsize
, phnum
int
267 var shentsize
, shnum
, shstrndx
int
272 sr
.Seek(0, io
.SeekStart
)
273 if err
:= binary
.Read(sr
, f
.ByteOrder
, hdr
); err
!= nil {
276 f
.Type
= Type(hdr
.Type
)
277 f
.Machine
= Machine(hdr
.Machine
)
278 f
.Entry
= uint64(hdr
.Entry
)
279 if v
:= Version(hdr
.Version
); v
!= f
.Version
{
280 return nil, &FormatError
{0, "mismatched ELF version", v
}
282 phoff
= int64(hdr
.Phoff
)
283 phentsize
= int(hdr
.Phentsize
)
284 phnum
= int(hdr
.Phnum
)
285 shoff
= int64(hdr
.Shoff
)
286 shentsize
= int(hdr
.Shentsize
)
287 shnum
= int(hdr
.Shnum
)
288 shstrndx
= int(hdr
.Shstrndx
)
291 sr
.Seek(0, io
.SeekStart
)
292 if err
:= binary
.Read(sr
, f
.ByteOrder
, hdr
); err
!= nil {
295 f
.Type
= Type(hdr
.Type
)
296 f
.Machine
= Machine(hdr
.Machine
)
298 if v
:= Version(hdr
.Version
); v
!= f
.Version
{
299 return nil, &FormatError
{0, "mismatched ELF version", v
}
301 phoff
= int64(hdr
.Phoff
)
302 phentsize
= int(hdr
.Phentsize
)
303 phnum
= int(hdr
.Phnum
)
304 shoff
= int64(hdr
.Shoff
)
305 shentsize
= int(hdr
.Shentsize
)
306 shnum
= int(hdr
.Shnum
)
307 shstrndx
= int(hdr
.Shstrndx
)
310 if shnum
> 0 && shoff
> 0 && (shstrndx
< 0 || shstrndx
>= shnum
) {
311 return nil, &FormatError
{0, "invalid ELF shstrndx", shstrndx
}
314 // Read program headers
315 f
.Progs
= make([]*Prog
, phnum
)
316 for i
:= 0; i
< phnum
; i
++ {
317 off
:= phoff
+ int64(i
)*int64(phentsize
)
318 sr
.Seek(off
, io
.SeekStart
)
323 if err
:= binary
.Read(sr
, f
.ByteOrder
, ph
); err
!= nil {
326 p
.ProgHeader
= ProgHeader
{
327 Type
: ProgType(ph
.Type
),
328 Flags
: ProgFlag(ph
.Flags
),
330 Vaddr
: uint64(ph
.Vaddr
),
331 Paddr
: uint64(ph
.Paddr
),
332 Filesz
: uint64(ph
.Filesz
),
333 Memsz
: uint64(ph
.Memsz
),
334 Align
: uint64(ph
.Align
),
338 if err
:= binary
.Read(sr
, f
.ByteOrder
, ph
); err
!= nil {
341 p
.ProgHeader
= ProgHeader
{
342 Type
: ProgType(ph
.Type
),
343 Flags
: ProgFlag(ph
.Flags
),
352 p
.sr
= io
.NewSectionReader(r
, int64(p
.Off
), int64(p
.Filesz
))
357 // Read section headers
358 f
.Sections
= make([]*Section
, shnum
)
359 names
:= make([]uint32, shnum
)
360 for i
:= 0; i
< shnum
; i
++ {
361 off
:= shoff
+ int64(i
)*int64(shentsize
)
362 sr
.Seek(off
, io
.SeekStart
)
367 if err
:= binary
.Read(sr
, f
.ByteOrder
, sh
); err
!= nil {
371 s
.SectionHeader
= SectionHeader
{
372 Type
: SectionType(sh
.Type
),
373 Flags
: SectionFlag(sh
.Flags
),
374 Addr
: uint64(sh
.Addr
),
375 Offset
: uint64(sh
.Off
),
376 FileSize
: uint64(sh
.Size
),
379 Addralign
: uint64(sh
.Addralign
),
380 Entsize
: uint64(sh
.Entsize
),
384 if err
:= binary
.Read(sr
, f
.ByteOrder
, sh
); err
!= nil {
388 s
.SectionHeader
= SectionHeader
{
389 Type
: SectionType(sh
.Type
),
390 Flags
: SectionFlag(sh
.Flags
),
396 Addralign
: sh
.Addralign
,
400 s
.sr
= io
.NewSectionReader(r
, int64(s
.Offset
), int64(s
.FileSize
))
402 if s
.Flags
&SHF_COMPRESSED
== 0 {
406 // Read the compression header.
410 if err
:= binary
.Read(s
.sr
, f
.ByteOrder
, ch
); err
!= nil {
413 s
.compressionType
= CompressionType(ch
.Type
)
414 s
.Size
= uint64(ch
.Size
)
415 s
.Addralign
= uint64(ch
.Addralign
)
416 s
.compressionOffset
= int64(binary
.Size(ch
))
419 if err
:= binary
.Read(s
.sr
, f
.ByteOrder
, ch
); err
!= nil {
422 s
.compressionType
= CompressionType(ch
.Type
)
424 s
.Addralign
= ch
.Addralign
425 s
.compressionOffset
= int64(binary
.Size(ch
))
432 if len(f
.Sections
) == 0 {
436 // Load section header string table.
437 shstrtab
, err
:= f
.Sections
[shstrndx
].Data()
441 for i
, s
:= range f
.Sections
{
443 s
.Name
, ok
= getString(shstrtab
, int(names
[i
]))
445 return nil, &FormatError
{shoff
+ int64(i
*shentsize
), "bad section name index", names
[i
]}
452 // getSymbols returns a slice of Symbols from parsing the symbol table
453 // with the given type, along with the associated string table.
454 func (f
*File
) getSymbols(typ SectionType
) ([]Symbol
, []byte, error
) {
457 return f
.getSymbols64(typ
)
460 return f
.getSymbols32(typ
)
463 return nil, nil, errors
.New("not implemented")
466 // ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
467 // if there is no such section in the File.
468 var ErrNoSymbols
= errors
.New("no symbol section")
470 func (f
*File
) getSymbols32(typ SectionType
) ([]Symbol
, []byte, error
) {
471 symtabSection
:= f
.SectionByType(typ
)
472 if symtabSection
== nil {
473 return nil, nil, ErrNoSymbols
476 data
, err
:= symtabSection
.Data()
478 return nil, nil, errors
.New("cannot load symbol section")
480 symtab
:= bytes
.NewReader(data
)
481 if symtab
.Len()%Sym
32Size
!= 0 {
482 return nil, nil, errors
.New("length of symbol section is not a multiple of SymSize")
485 strdata
, err
:= f
.stringTable(symtabSection
.Link
)
487 return nil, nil, errors
.New("cannot load string table section")
490 // The first entry is all zeros.
491 var skip
[Sym32Size
]byte
494 symbols
:= make([]Symbol
, symtab
.Len()/Sym32Size
)
498 for symtab
.Len() > 0 {
499 binary
.Read(symtab
, f
.ByteOrder
, &sym
)
500 str
, _
:= getString(strdata
, int(sym
.Name
))
501 symbols
[i
].Name
= str
502 symbols
[i
].Info
= sym
.Info
503 symbols
[i
].Other
= sym
.Other
504 symbols
[i
].Section
= SectionIndex(sym
.Shndx
)
505 symbols
[i
].Value
= uint64(sym
.Value
)
506 symbols
[i
].Size
= uint64(sym
.Size
)
510 return symbols
, strdata
, nil
513 func (f
*File
) getSymbols64(typ SectionType
) ([]Symbol
, []byte, error
) {
514 symtabSection
:= f
.SectionByType(typ
)
515 if symtabSection
== nil {
516 return nil, nil, ErrNoSymbols
519 data
, err
:= symtabSection
.Data()
521 return nil, nil, errors
.New("cannot load symbol section")
523 symtab
:= bytes
.NewReader(data
)
524 if symtab
.Len()%Sym
64Size
!= 0 {
525 return nil, nil, errors
.New("length of symbol section is not a multiple of Sym64Size")
528 strdata
, err
:= f
.stringTable(symtabSection
.Link
)
530 return nil, nil, errors
.New("cannot load string table section")
533 // The first entry is all zeros.
534 var skip
[Sym64Size
]byte
537 symbols
:= make([]Symbol
, symtab
.Len()/Sym64Size
)
541 for symtab
.Len() > 0 {
542 binary
.Read(symtab
, f
.ByteOrder
, &sym
)
543 str
, _
:= getString(strdata
, int(sym
.Name
))
544 symbols
[i
].Name
= str
545 symbols
[i
].Info
= sym
.Info
546 symbols
[i
].Other
= sym
.Other
547 symbols
[i
].Section
= SectionIndex(sym
.Shndx
)
548 symbols
[i
].Value
= sym
.Value
549 symbols
[i
].Size
= sym
.Size
553 return symbols
, strdata
, nil
556 // getString extracts a string from an ELF string table.
557 func getString(section
[]byte, start
int) (string, bool) {
558 if start
< 0 || start
>= len(section
) {
562 for end
:= start
; end
< len(section
); end
++ {
563 if section
[end
] == 0 {
564 return string(section
[start
:end
]), true
570 // Section returns a section with the given name, or nil if no such
572 func (f
*File
) Section(name
string) *Section
{
573 for _
, s
:= range f
.Sections
{
581 // applyRelocations applies relocations to dst. rels is a relocations section
582 // in REL or RELA format.
583 func (f
*File
) applyRelocations(dst
[]byte, rels
[]byte) error
{
585 case f
.Class
== ELFCLASS64
&& f
.Machine
== EM_X86_64
:
586 return f
.applyRelocationsAMD64(dst
, rels
)
587 case f
.Class
== ELFCLASS32
&& f
.Machine
== EM_386
:
588 return f
.applyRelocations386(dst
, rels
)
589 case f
.Class
== ELFCLASS32
&& f
.Machine
== EM_ARM
:
590 return f
.applyRelocationsARM(dst
, rels
)
591 case f
.Class
== ELFCLASS64
&& f
.Machine
== EM_AARCH64
:
592 return f
.applyRelocationsARM64(dst
, rels
)
593 case f
.Class
== ELFCLASS32
&& f
.Machine
== EM_PPC
:
594 return f
.applyRelocationsPPC(dst
, rels
)
595 case f
.Class
== ELFCLASS64
&& f
.Machine
== EM_PPC64
:
596 return f
.applyRelocationsPPC64(dst
, rels
)
597 case f
.Class
== ELFCLASS32
&& f
.Machine
== EM_MIPS
:
598 return f
.applyRelocationsMIPS(dst
, rels
)
599 case f
.Class
== ELFCLASS64
&& f
.Machine
== EM_MIPS
:
600 return f
.applyRelocationsMIPS64(dst
, rels
)
601 case f
.Class
== ELFCLASS64
&& f
.Machine
== EM_S390
:
602 return f
.applyRelocationss390x(dst
, rels
)
603 case f
.Class
== ELFCLASS32
&& (f
.Machine
== EM_SPARC || f
.Machine
== EM_SPARC32PLUS
):
604 return f
.applyRelocationsSPARC(dst
, rels
)
605 case f
.Class
== ELFCLASS64
&& f
.Machine
== EM_SPARCV9
:
606 return f
.applyRelocationsSPARC64(dst
, rels
)
607 case f
.Class
== ELFCLASS64
&& f
.Machine
== EM_ALPHA
:
608 return f
.applyRelocationsALPHA(dst
, rels
)
610 return errors
.New("applyRelocations: not implemented")
614 func (f
*File
) applyRelocationsAMD64(dst
[]byte, rels
[]byte) error
{
615 // 24 is the size of Rela64.
616 if len(rels
)%24
!= 0 {
617 return errors
.New("length of relocation section is not a multiple of 24")
620 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
625 b
:= bytes
.NewReader(rels
)
629 binary
.Read(b
, f
.ByteOrder
, &rela
)
630 symNo
:= rela
.Info
>> 32
631 t
:= R_X86_64(rela
.Info
& 0xffff)
633 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
636 sym
:= &symbols
[symNo
-1]
637 if SymType(sym
.Info
&0xf) != STT_SECTION
{
638 // We don't handle non-section relocations for now.
642 // There are relocations, so this must be a normal
643 // object file, and we only look at section symbols,
644 // so we assume that the symbol value is 0.
648 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
651 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], uint64(rela
.Addend
))
653 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
656 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
663 func (f
*File
) applyRelocations386(dst
[]byte, rels
[]byte) error
{
664 // 8 is the size of Rel32.
665 if len(rels
)%8
!= 0 {
666 return errors
.New("length of relocation section is not a multiple of 8")
669 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
674 b
:= bytes
.NewReader(rels
)
678 binary
.Read(b
, f
.ByteOrder
, &rel
)
679 symNo
:= rel
.Info
>> 8
680 t
:= R_386(rel
.Info
& 0xff)
682 if symNo
== 0 || symNo
> uint32(len(symbols
)) {
685 sym
:= &symbols
[symNo
-1]
688 if rel
.Off
+4 >= uint32(len(dst
)) {
691 val
:= f
.ByteOrder
.Uint32(dst
[rel
.Off
: rel
.Off
+4])
692 val
+= uint32(sym
.Value
)
693 f
.ByteOrder
.PutUint32(dst
[rel
.Off
:rel
.Off
+4], val
)
700 func (f
*File
) applyRelocationsARM(dst
[]byte, rels
[]byte) error
{
701 // 8 is the size of Rel32.
702 if len(rels
)%8
!= 0 {
703 return errors
.New("length of relocation section is not a multiple of 8")
706 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
711 b
:= bytes
.NewReader(rels
)
715 binary
.Read(b
, f
.ByteOrder
, &rel
)
716 symNo
:= rel
.Info
>> 8
717 t
:= R_ARM(rel
.Info
& 0xff)
719 if symNo
== 0 || symNo
> uint32(len(symbols
)) {
722 sym
:= &symbols
[symNo
-1]
726 if rel
.Off
+4 >= uint32(len(dst
)) {
729 val
:= f
.ByteOrder
.Uint32(dst
[rel
.Off
: rel
.Off
+4])
730 val
+= uint32(sym
.Value
)
731 f
.ByteOrder
.PutUint32(dst
[rel
.Off
:rel
.Off
+4], val
)
738 func (f
*File
) applyRelocationsARM64(dst
[]byte, rels
[]byte) error
{
739 // 24 is the size of Rela64.
740 if len(rels
)%24
!= 0 {
741 return errors
.New("length of relocation section is not a multiple of 24")
744 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
749 b
:= bytes
.NewReader(rels
)
753 binary
.Read(b
, f
.ByteOrder
, &rela
)
754 symNo
:= rela
.Info
>> 32
755 t
:= R_AARCH64(rela
.Info
& 0xffff)
757 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
760 sym
:= &symbols
[symNo
-1]
761 if SymType(sym
.Info
&0xf) != STT_SECTION
{
762 // We don't handle non-section relocations for now.
766 // There are relocations, so this must be a normal
767 // object file, and we only look at section symbols,
768 // so we assume that the symbol value is 0.
771 case R_AARCH64_ABS64
:
772 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
775 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], uint64(rela
.Addend
))
776 case R_AARCH64_ABS32
:
777 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
780 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
787 func (f
*File
) applyRelocationsPPC(dst
[]byte, rels
[]byte) error
{
788 // 12 is the size of Rela32.
789 if len(rels
)%12
!= 0 {
790 return errors
.New("length of relocation section is not a multiple of 12")
793 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
798 b
:= bytes
.NewReader(rels
)
802 binary
.Read(b
, f
.ByteOrder
, &rela
)
803 symNo
:= rela
.Info
>> 8
804 t
:= R_PPC(rela
.Info
& 0xff)
806 if symNo
== 0 || symNo
> uint32(len(symbols
)) {
809 sym
:= &symbols
[symNo
-1]
810 if SymType(sym
.Info
&0xf) != STT_SECTION
{
811 // We don't handle non-section relocations for now.
817 if rela
.Off
+4 >= uint32(len(dst
)) || rela
.Addend
< 0 {
820 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
827 func (f
*File
) applyRelocationsPPC64(dst
[]byte, rels
[]byte) error
{
828 // 24 is the size of Rela64.
829 if len(rels
)%24
!= 0 {
830 return errors
.New("length of relocation section is not a multiple of 24")
833 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
838 b
:= bytes
.NewReader(rels
)
842 binary
.Read(b
, f
.ByteOrder
, &rela
)
843 symNo
:= rela
.Info
>> 32
844 t
:= R_PPC64(rela
.Info
& 0xffff)
846 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
849 sym
:= &symbols
[symNo
-1]
850 if SymType(sym
.Info
&0xf) != STT_SECTION
{
851 // We don't handle non-section relocations for now.
857 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
860 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], uint64(rela
.Addend
))
862 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
865 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
872 func (f
*File
) applyRelocationsMIPS(dst
[]byte, rels
[]byte) error
{
873 // 8 is the size of Rel32.
874 if len(rels
)%8
!= 0 {
875 return errors
.New("length of relocation section is not a multiple of 8")
878 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
883 b
:= bytes
.NewReader(rels
)
887 binary
.Read(b
, f
.ByteOrder
, &rel
)
888 symNo
:= rel
.Info
>> 8
889 t
:= R_MIPS(rel
.Info
& 0xff)
891 if symNo
== 0 || symNo
> uint32(len(symbols
)) {
894 sym
:= &symbols
[symNo
-1]
898 if rel
.Off
+4 >= uint32(len(dst
)) {
901 val
:= f
.ByteOrder
.Uint32(dst
[rel
.Off
: rel
.Off
+4])
902 val
+= uint32(sym
.Value
)
903 f
.ByteOrder
.PutUint32(dst
[rel
.Off
:rel
.Off
+4], val
)
910 func (f
*File
) applyRelocationsMIPS64(dst
[]byte, rels
[]byte) error
{
911 // 24 is the size of Rela64.
912 if len(rels
)%24
!= 0 {
913 return errors
.New("length of relocation section is not a multiple of 24")
916 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
921 b
:= bytes
.NewReader(rels
)
925 binary
.Read(b
, f
.ByteOrder
, &rela
)
928 if f
.ByteOrder
== binary
.BigEndian
{
929 symNo
= rela
.Info
>> 32
930 t
= R_MIPS(rela
.Info
& 0xff)
932 symNo
= rela
.Info
& 0xffffffff
933 t
= R_MIPS(rela
.Info
>> 56)
936 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
939 sym
:= &symbols
[symNo
-1]
940 if SymType(sym
.Info
&0xf) != STT_SECTION
{
941 // We don't handle non-section relocations for now.
947 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
950 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], uint64(rela
.Addend
))
952 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
955 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
962 func (f
*File
) applyRelocationss390x(dst
[]byte, rels
[]byte) error
{
963 // 24 is the size of Rela64.
964 if len(rels
)%24
!= 0 {
965 return errors
.New("length of relocation section is not a multiple of 24")
968 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
973 b
:= bytes
.NewReader(rels
)
977 binary
.Read(b
, f
.ByteOrder
, &rela
)
978 symNo
:= rela
.Info
>> 32
979 t
:= R_390(rela
.Info
& 0xffff)
981 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
984 sym
:= &symbols
[symNo
-1]
985 switch SymType(sym
.Info
& 0xf) {
986 case STT_SECTION
, STT_NOTYPE
:
994 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
997 val
:= sym
.Value
+ uint64(rela
.Addend
)
998 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], val
)
1000 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
1003 val
:= uint32(sym
.Value
) + uint32(rela
.Addend
)
1004 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], val
)
1011 func (f
*File
) applyRelocationsSPARC(dst
[]byte, rels
[]byte) error
{
1012 // 12 is the size of Rela32.
1013 if len(rels
)%12
!= 0 {
1014 return errors
.New("length of relocation section is not a multiple of 12")
1017 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
1022 b
:= bytes
.NewReader(rels
)
1026 binary
.Read(b
, f
.ByteOrder
, &rela
)
1027 symNo
:= rela
.Info
>> 32
1028 t
:= R_SPARC(rela
.Info
& 0xff)
1030 if symNo
== 0 || symNo
> uint32(len(symbols
)) {
1033 sym
:= &symbols
[symNo
-1]
1034 if SymType(sym
.Info
&0xf) != STT_SECTION
{
1035 // We don't handle non-section relocations for now.
1040 case R_SPARC_32
, R_SPARC_UA32
:
1041 if rela
.Off
+4 >= uint32(len(dst
)) || rela
.Addend
< 0 {
1044 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
1051 func (f
*File
) applyRelocationsSPARC64(dst
[]byte, rels
[]byte) error
{
1052 // 24 is the size of Rela64.
1053 if len(rels
)%24
!= 0 {
1054 return errors
.New("length of relocation section is not a multiple of 24")
1057 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
1062 b
:= bytes
.NewReader(rels
)
1066 binary
.Read(b
, f
.ByteOrder
, &rela
)
1067 symNo
:= rela
.Info
>> 32
1068 t
:= R_SPARC(rela
.Info
& 0xff)
1070 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
1073 sym
:= &symbols
[symNo
-1]
1074 if SymType(sym
.Info
&0xf) != STT_SECTION
{
1075 // We don't handle non-section relocations for now.
1080 case R_SPARC_64
, R_SPARC_UA64
:
1081 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
1084 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], uint64(rela
.Addend
))
1085 case R_SPARC_32
, R_SPARC_UA32
:
1086 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
1089 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
1096 func (f
*File
) applyRelocationsALPHA(dst
[]byte, rels
[]byte) error
{
1097 // 24 is the size of Rela64.
1098 if len(rels
)%24
!= 0 {
1099 return errors
.New("length of relocation section is not a multiple of 24")
1102 symbols
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
1107 b
:= bytes
.NewReader(rels
)
1111 binary
.Read(b
, f
.ByteOrder
, &rela
)
1112 symNo
:= rela
.Info
>> 32
1113 t
:= R_ALPHA(rela
.Info
& 0xffff)
1115 if symNo
== 0 || symNo
> uint64(len(symbols
)) {
1118 sym
:= &symbols
[symNo
-1]
1119 if SymType(sym
.Info
&0xf) != STT_SECTION
{
1120 // We don't handle non-section relocations for now.
1124 // There are relocations, so this must be a normal
1125 // object file, and we only look at section symbols,
1126 // so we assume that the symbol value is 0.
1129 case R_ALPHA_REFQUAD
:
1130 if rela
.Off
+8 >= uint64(len(dst
)) || rela
.Addend
< 0 {
1133 f
.ByteOrder
.PutUint64(dst
[rela
.Off
:rela
.Off
+8], uint64(rela
.Addend
))
1134 case R_ALPHA_REFLONG
:
1135 if rela
.Off
+4 >= uint64(len(dst
)) || rela
.Addend
< 0 {
1138 f
.ByteOrder
.PutUint32(dst
[rela
.Off
:rela
.Off
+4], uint32(rela
.Addend
))
1145 func (f
*File
) DWARF() (*dwarf
.Data
, error
) {
1146 // sectionData gets the data for s, checks its size, and
1147 // applies any applicable relations.
1148 sectionData
:= func(i
int, s
*Section
) ([]byte, error
) {
1150 if err
!= nil && uint64(len(b
)) < s
.Size
{
1154 if len(b
) >= 12 && string(b
[:4]) == "ZLIB" {
1155 dlen
:= binary
.BigEndian
.Uint64(b
[4:12])
1156 dbuf
:= make([]byte, dlen
)
1157 r
, err
:= zlib
.NewReader(bytes
.NewBuffer(b
[12:]))
1161 if _
, err
:= io
.ReadFull(r
, dbuf
); err
!= nil {
1164 if err
:= r
.Close(); err
!= nil {
1170 for _
, r
:= range f
.Sections
{
1171 if r
.Type
!= SHT_RELA
&& r
.Type
!= SHT_REL
{
1174 if int(r
.Info
) != i
{
1181 err
= f
.applyRelocations(b
, rd
)
1189 // There are many other DWARF sections, but these
1190 // are the ones the debug/dwarf package uses.
1191 // Don't bother loading others.
1192 var dat
= map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1193 for i
, s
:= range f
.Sections
{
1196 case strings
.HasPrefix(s
.Name
, ".debug_"):
1198 case strings
.HasPrefix(s
.Name
, ".zdebug_"):
1203 if _
, ok
:= dat
[suffix
]; !ok
{
1206 b
, err
:= sectionData(i
, s
)
1213 d
, err
:= dwarf
.New(dat
["abbrev"], nil, nil, dat
["info"], dat
["line"], nil, dat
["ranges"], dat
["str"])
1218 // Look for DWARF4 .debug_types sections.
1219 for i
, s
:= range f
.Sections
{
1220 if s
.Name
== ".debug_types" {
1221 b
, err
:= sectionData(i
, s
)
1226 err
= d
.AddTypes(fmt
.Sprintf("types-%d", i
), b
)
1236 // Symbols returns the symbol table for f. The symbols will be listed in the order
1237 // they appear in f.
1239 // For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
1240 // After retrieving the symbols as symtab, an externally supplied index x
1241 // corresponds to symtab[x-1], not symtab[x].
1242 func (f
*File
) Symbols() ([]Symbol
, error
) {
1243 sym
, _
, err
:= f
.getSymbols(SHT_SYMTAB
)
1247 // DynamicSymbols returns the dynamic symbol table for f. The symbols
1248 // will be listed in the order they appear in f.
1250 // For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
1251 // After retrieving the symbols as symtab, an externally supplied index x
1252 // corresponds to symtab[x-1], not symtab[x].
1253 func (f
*File
) DynamicSymbols() ([]Symbol
, error
) {
1254 sym
, _
, err
:= f
.getSymbols(SHT_DYNSYM
)
1258 type ImportedSymbol
struct {
1264 // ImportedSymbols returns the names of all symbols
1265 // referred to by the binary f that are expected to be
1266 // satisfied by other libraries at dynamic load time.
1267 // It does not return weak symbols.
1268 func (f
*File
) ImportedSymbols() ([]ImportedSymbol
, error
) {
1269 sym
, str
, err
:= f
.getSymbols(SHT_DYNSYM
)
1273 f
.gnuVersionInit(str
)
1274 var all
[]ImportedSymbol
1275 for i
, s
:= range sym
{
1276 if ST_BIND(s
.Info
) == STB_GLOBAL
&& s
.Section
== SHN_UNDEF
{
1277 all
= append(all
, ImportedSymbol
{Name
: s
.Name
})
1278 f
.gnuVersion(i
, &all
[len(all
)-1])
1284 type verneed
struct {
1289 // gnuVersionInit parses the GNU version tables
1290 // for use by calls to gnuVersion.
1291 func (f
*File
) gnuVersionInit(str
[]byte) {
1292 // Accumulate verneed information.
1293 vn
:= f
.SectionByType(SHT_GNU_VERNEED
)
1305 vers
:= f
.ByteOrder
.Uint16(d
[i
: i
+2])
1309 cnt
:= f
.ByteOrder
.Uint16(d
[i
+2 : i
+4])
1310 fileoff
:= f
.ByteOrder
.Uint32(d
[i
+4 : i
+8])
1311 aux
:= f
.ByteOrder
.Uint32(d
[i
+8 : i
+12])
1312 next
:= f
.ByteOrder
.Uint32(d
[i
+12 : i
+16])
1313 file
, _
:= getString(str
, int(fileoff
))
1317 for c
:= 0; c
< int(cnt
); c
++ {
1321 // hash := f.ByteOrder.Uint32(d[j:j+4])
1322 // flags := f.ByteOrder.Uint16(d[j+4:j+6])
1323 other
:= f
.ByteOrder
.Uint16(d
[j
+6 : j
+8])
1324 nameoff
:= f
.ByteOrder
.Uint32(d
[j
+8 : j
+12])
1325 next
:= f
.ByteOrder
.Uint32(d
[j
+12 : j
+16])
1326 name
, _
= getString(str
, int(nameoff
))
1328 if ndx
>= len(need
) {
1329 a
:= make([]verneed
, 2*(ndx
+1))
1334 need
[ndx
] = verneed
{file
, name
}
1347 // Versym parallels symbol table, indexing into verneed.
1348 vs
:= f
.SectionByType(SHT_GNU_VERSYM
)
1358 // gnuVersion adds Library and Version information to sym,
1359 // which came from offset i of the symbol table.
1360 func (f
*File
) gnuVersion(i
int, sym
*ImportedSymbol
) {
1361 // Each entry is two bytes.
1363 if i
>= len(f
.gnuVersym
) {
1366 j
:= int(f
.ByteOrder
.Uint16(f
.gnuVersym
[i
:]))
1367 if j
< 2 || j
>= len(f
.gnuNeed
) {
1371 sym
.Library
= n
.File
1372 sym
.Version
= n
.Name
1375 // ImportedLibraries returns the names of all libraries
1376 // referred to by the binary f that are expected to be
1377 // linked with the binary at dynamic link time.
1378 func (f
*File
) ImportedLibraries() ([]string, error
) {
1379 return f
.DynString(DT_NEEDED
)
1382 // DynString returns the strings listed for the given tag in the file's dynamic
1385 // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
1387 func (f
*File
) DynString(tag DynTag
) ([]string, error
) {
1389 case DT_NEEDED
, DT_SONAME
, DT_RPATH
, DT_RUNPATH
:
1391 return nil, fmt
.Errorf("non-string-valued tag %v", tag
)
1393 ds
:= f
.SectionByType(SHT_DYNAMIC
)
1395 // not dynamic, so no libraries
1402 str
, err
:= f
.stringTable(ds
.Link
)
1412 t
= DynTag(f
.ByteOrder
.Uint32(d
[0:4]))
1413 v
= uint64(f
.ByteOrder
.Uint32(d
[4:8]))
1416 t
= DynTag(f
.ByteOrder
.Uint64(d
[0:8]))
1417 v
= f
.ByteOrder
.Uint64(d
[8:16])
1421 s
, ok
:= getString(str
, int(v
))
1423 all
= append(all
, s
)