file.mx raw

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