src/pkg/debug/elf/file.go - The Go Programming Language

Golang

Source file src/pkg/debug/elf/file.go

     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	// Package elf implements access to ELF object files.
     6	package elf
     7	
     8	import (
     9		"bytes"
    10		"debug/dwarf"
    11		"encoding/binary"
    12		"errors"
    13		"fmt"
    14		"io"
    15		"os"
    16	)
    17	
    18	// TODO: error reporting detail
    19	
    20	/*
    21	 * Internal ELF representation
    22	 */
    23	
    24	// A FileHeader represents an ELF file header.
    25	type FileHeader struct {
    26		Class      Class
    27		Data       Data
    28		Version    Version
    29		OSABI      OSABI
    30		ABIVersion uint8
    31		ByteOrder  binary.ByteOrder
    32		Type       Type
    33		Machine    Machine
    34	}
    35	
    36	// A File represents an open ELF file.
    37	type File struct {
    38		FileHeader
    39		Sections  []*Section
    40		Progs     []*Prog
    41		closer    io.Closer
    42		gnuNeed   []verneed
    43		gnuVersym []byte
    44	}
    45	
    46	// A SectionHeader represents a single ELF section header.
    47	type SectionHeader struct {
    48		Name      string
    49		Type      SectionType
    50		Flags     SectionFlag
    51		Addr      uint64
    52		Offset    uint64
    53		Size      uint64
    54		Link      uint32
    55		Info      uint32
    56		Addralign uint64
    57		Entsize   uint64
    58	}
    59	
    60	// A Section represents a single section in an ELF file.
    61	type Section struct {
    62		SectionHeader
    63	
    64		// Embed ReaderAt for ReadAt method.
    65		// Do not embed SectionReader directly
    66		// to avoid having Read and Seek.
    67		// If a client wants Read and Seek it must use
    68		// Open() to avoid fighting over the seek offset
    69		// with other clients.
    70		io.ReaderAt
    71		sr *io.SectionReader
    72	}
    73	
    74	// Data reads and returns the contents of the ELF section.
    75	func (s *Section) Data() ([]byte, error) {
    76		dat := make([]byte, s.sr.Size())
    77		n, err := s.sr.ReadAt(dat, 0)
    78		return dat[0:n], err
    79	}
    80	
    81	// stringTable reads and returns the string table given by the
    82	// specified link value.
    83	func (f *File) stringTable(link uint32) ([]byte, error) {
    84		if link <= 0 || link >= uint32(len(f.Sections)) {
    85			return nil, errors.New("section has invalid string table link")
    86		}
    87		return f.Sections[link].Data()
    88	}
    89	
    90	// Open returns a new ReadSeeker reading the ELF section.
    91	func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
    92	
    93	// A ProgHeader represents a single ELF program header.
    94	type ProgHeader struct {
    95		Type   ProgType
    96		Flags  ProgFlag
    97		Off    uint64
    98		Vaddr  uint64
    99		Paddr  uint64
   100		Filesz uint64
   101		Memsz  uint64
   102		Align  uint64
   103	}
   104	
   105	// A Prog represents a single ELF program header in an ELF binary.
   106	type Prog struct {
   107		ProgHeader
   108	
   109		// Embed ReaderAt for ReadAt method.
   110		// Do not embed SectionReader directly
   111		// to avoid having Read and Seek.
   112		// If a client wants Read and Seek it must use
   113		// Open() to avoid fighting over the seek offset
   114		// with other clients.
   115		io.ReaderAt
   116		sr *io.SectionReader
   117	}
   118	
   119	// Open returns a new ReadSeeker reading the ELF program body.
   120	func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
   121	
   122	// A Symbol represents an entry in an ELF symbol table section.
   123	type Symbol struct {
   124		Name        string
   125		Info, Other byte
   126		Section     SectionIndex
   127		Value, Size uint64
   128	}
   129	
   130	/*
   131	 * ELF reader
   132	 */
   133	
   134	type FormatError struct {
   135		off int64
   136		msg string
   137		val interface{}
   138	}
   139	
   140	func (e *FormatError) Error() string {
   141		msg := e.msg
   142		if e.val != nil {
   143			msg += fmt.Sprintf(" '%v' ", e.val)
   144		}
   145		msg += fmt.Sprintf("in record at byte %#x", e.off)
   146		return msg
   147	}
   148	
   149	// Open opens the named file using os.Open and prepares it for use as an ELF binary.
   150	func Open(name string) (*File, error) {
   151		f, err := os.Open(name)
   152		if err != nil {
   153			return nil, err
   154		}
   155		ff, err := NewFile(f)
   156		if err != nil {
   157			f.Close()
   158			return nil, err
   159		}
   160		ff.closer = f
   161		return ff, nil
   162	}
   163	
   164	// Close closes the File.
   165	// If the File was created using NewFile directly instead of Open,
   166	// Close has no effect.
   167	func (f *File) Close() error {
   168		var err error
   169		if f.closer != nil {
   170			err = f.closer.Close()
   171			f.closer = nil
   172		}
   173		return err
   174	}
   175	
   176	// SectionByType returns the first section in f with the
   177	// given type, or nil if there is no such section.
   178	func (f *File) SectionByType(typ SectionType) *Section {
   179		for _, s := range f.Sections {
   180			if s.Type == typ {
   181				return s
   182			}
   183		}
   184		return nil
   185	}
   186	
   187	// NewFile creates a new File for accessing an ELF binary in an underlying reader.
   188	// The ELF binary is expected to start at position 0 in the ReaderAt.
   189	func NewFile(r io.ReaderAt) (*File, error) {
   190		sr := io.NewSectionReader(r, 0, 1<<63-1)
   191		// Read and decode ELF identifier
   192		var ident [16]uint8
   193		if _, err := r.ReadAt(ident[0:], 0); err != nil {
   194			return nil, err
   195		}
   196		if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
   197			return nil, &FormatError{0, "bad magic number", ident[0:4]}
   198		}
   199	
   200		f := new(File)
   201		f.Class = Class(ident[EI_CLASS])
   202		switch f.Class {
   203		case ELFCLASS32:
   204		case ELFCLASS64:
   205			// ok
   206		default:
   207			return nil, &FormatError{0, "unknown ELF class", f.Class}
   208		}
   209	
   210		f.Data = Data(ident[EI_DATA])
   211		switch f.Data {
   212		case ELFDATA2LSB:
   213			f.ByteOrder = binary.LittleEndian
   214		case ELFDATA2MSB:
   215			f.ByteOrder = binary.BigEndian
   216		default:
   217			return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
   218		}
   219	
   220		f.Version = Version(ident[EI_VERSION])
   221		if f.Version != EV_CURRENT {
   222			return nil, &FormatError{0, "unknown ELF version", f.Version}
   223		}
   224	
   225		f.OSABI = OSABI(ident[EI_OSABI])
   226		f.ABIVersion = ident[EI_ABIVERSION]
   227	
   228		// Read ELF file header
   229		var phoff int64
   230		var phentsize, phnum int
   231		var shoff int64
   232		var shentsize, shnum, shstrndx int
   233		shstrndx = -1
   234		switch f.Class {
   235		case ELFCLASS32:
   236			hdr := new(Header32)
   237			sr.Seek(0, os.SEEK_SET)
   238			if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
   239				return nil, err
   240			}
   241			f.Type = Type(hdr.Type)
   242			f.Machine = Machine(hdr.Machine)
   243			if v := Version(hdr.Version); v != f.Version {
   244				return nil, &FormatError{0, "mismatched ELF version", v}
   245			}
   246			phoff = int64(hdr.Phoff)
   247			phentsize = int(hdr.Phentsize)
   248			phnum = int(hdr.Phnum)
   249			shoff = int64(hdr.Shoff)
   250			shentsize = int(hdr.Shentsize)
   251			shnum = int(hdr.Shnum)
   252			shstrndx = int(hdr.Shstrndx)
   253		case ELFCLASS64:
   254			hdr := new(Header64)
   255			sr.Seek(0, os.SEEK_SET)
   256			if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
   257				return nil, err
   258			}
   259			f.Type = Type(hdr.Type)
   260			f.Machine = Machine(hdr.Machine)
   261			if v := Version(hdr.Version); v != f.Version {
   262				return nil, &FormatError{0, "mismatched ELF version", v}
   263			}
   264			phoff = int64(hdr.Phoff)
   265			phentsize = int(hdr.Phentsize)
   266			phnum = int(hdr.Phnum)
   267			shoff = int64(hdr.Shoff)
   268			shentsize = int(hdr.Shentsize)
   269			shnum = int(hdr.Shnum)
   270			shstrndx = int(hdr.Shstrndx)
   271		}
   272		if shstrndx < 0 || shstrndx >= shnum {
   273			return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
   274		}
   275	
   276		// Read program headers
   277		f.Progs = make([]*Prog, phnum)
   278		for i := 0; i < phnum; i++ {
   279			off := phoff + int64(i)*int64(phentsize)
   280			sr.Seek(off, os.SEEK_SET)
   281			p := new(Prog)
   282			switch f.Class {
   283			case ELFCLASS32:
   284				ph := new(Prog32)
   285				if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
   286					return nil, err
   287				}
   288				p.ProgHeader = ProgHeader{
   289					Type:   ProgType(ph.Type),
   290					Flags:  ProgFlag(ph.Flags),
   291					Off:    uint64(ph.Off),
   292					Vaddr:  uint64(ph.Vaddr),
   293					Paddr:  uint64(ph.Paddr),
   294					Filesz: uint64(ph.Filesz),
   295					Memsz:  uint64(ph.Memsz),
   296					Align:  uint64(ph.Align),
   297				}
   298			case ELFCLASS64:
   299				ph := new(Prog64)
   300				if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
   301					return nil, err
   302				}
   303				p.ProgHeader = ProgHeader{
   304					Type:   ProgType(ph.Type),
   305					Flags:  ProgFlag(ph.Flags),
   306					Off:    uint64(ph.Off),
   307					Vaddr:  uint64(ph.Vaddr),
   308					Paddr:  uint64(ph.Paddr),
   309					Filesz: uint64(ph.Filesz),
   310					Memsz:  uint64(ph.Memsz),
   311					Align:  uint64(ph.Align),
   312				}
   313			}
   314			p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
   315			p.ReaderAt = p.sr
   316			f.Progs[i] = p
   317		}
   318	
   319		// Read section headers
   320		f.Sections = make([]*Section, shnum)
   321		names := make([]uint32, shnum)
   322		for i := 0; i < shnum; i++ {
   323			off := shoff + int64(i)*int64(shentsize)
   324			sr.Seek(off, os.SEEK_SET)
   325			s := new(Section)
   326			switch f.Class {
   327			case ELFCLASS32:
   328				sh := new(Section32)
   329				if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
   330					return nil, err
   331				}
   332				names[i] = sh.Name
   333				s.SectionHeader = SectionHeader{
   334					Type:      SectionType(sh.Type),
   335					Flags:     SectionFlag(sh.Flags),
   336					Addr:      uint64(sh.Addr),
   337					Offset:    uint64(sh.Off),
   338					Size:      uint64(sh.Size),
   339					Link:      uint32(sh.Link),
   340					Info:      uint32(sh.Info),
   341					Addralign: uint64(sh.Addralign),
   342					Entsize:   uint64(sh.Entsize),
   343				}
   344			case ELFCLASS64:
   345				sh := new(Section64)
   346				if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
   347					return nil, err
   348				}
   349				names[i] = sh.Name
   350				s.SectionHeader = SectionHeader{
   351					Type:      SectionType(sh.Type),
   352					Flags:     SectionFlag(sh.Flags),
   353					Offset:    uint64(sh.Off),
   354					Size:      uint64(sh.Size),
   355					Addr:      uint64(sh.Addr),
   356					Link:      uint32(sh.Link),
   357					Info:      uint32(sh.Info),
   358					Addralign: uint64(sh.Addralign),
   359					Entsize:   uint64(sh.Entsize),
   360				}
   361			}
   362			s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
   363			s.ReaderAt = s.sr
   364			f.Sections[i] = s
   365		}
   366	
   367		// Load section header string table.
   368		shstrtab, err := f.Sections[shstrndx].Data()
   369		if err != nil {
   370			return nil, err
   371		}
   372		for i, s := range f.Sections {
   373			var ok bool
   374			s.Name, ok = getString(shstrtab, int(names[i]))
   375			if !ok {
   376				return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
   377			}
   378		}
   379	
   380		return f, nil
   381	}
   382	
   383	// getSymbols returns a slice of Symbols from parsing the symbol table
   384	// with the given type, along with the associated string table.
   385	func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
   386		switch f.Class {
   387		case ELFCLASS64:
   388			return f.getSymbols64(typ)
   389	
   390		case ELFCLASS32:
   391			return f.getSymbols32(typ)
   392		}
   393	
   394		return nil, nil, errors.New("not implemented")
   395	}
   396	
   397	func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
   398		symtabSection := f.SectionByType(typ)
   399		if symtabSection == nil {
   400			return nil, nil, errors.New("no symbol section")
   401		}
   402	
   403		data, err := symtabSection.Data()
   404		if err != nil {
   405			return nil, nil, errors.New("cannot load symbol section")
   406		}
   407		symtab := bytes.NewBuffer(data)
   408		if symtab.Len()%Sym32Size != 0 {
   409			return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
   410		}
   411	
   412		strdata, err := f.stringTable(symtabSection.Link)
   413		if err != nil {
   414			return nil, nil, errors.New("cannot load string table section")
   415		}
   416	
   417		// The first entry is all zeros.
   418		var skip [Sym32Size]byte
   419		symtab.Read(skip[0:])
   420	
   421		symbols := make([]Symbol, symtab.Len()/Sym32Size)
   422	
   423		i := 0
   424		var sym Sym32
   425		for symtab.Len() > 0 {
   426			binary.Read(symtab, f.ByteOrder, &sym)
   427			str, _ := getString(strdata, int(sym.Name))
   428			symbols[i].Name = str
   429			symbols[i].Info = sym.Info
   430			symbols[i].Other = sym.Other
   431			symbols[i].Section = SectionIndex(sym.Shndx)
   432			symbols[i].Value = uint64(sym.Value)
   433			symbols[i].Size = uint64(sym.Size)
   434			i++
   435		}
   436	
   437		return symbols, strdata, nil
   438	}
   439	
   440	func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
   441		symtabSection := f.SectionByType(typ)
   442		if symtabSection == nil {
   443			return nil, nil, errors.New("no symbol section")
   444		}
   445	
   446		data, err := symtabSection.Data()
   447		if err != nil {
   448			return nil, nil, errors.New("cannot load symbol section")
   449		}
   450		symtab := bytes.NewBuffer(data)
   451		if symtab.Len()%Sym64Size != 0 {
   452			return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
   453		}
   454	
   455		strdata, err := f.stringTable(symtabSection.Link)
   456		if err != nil {
   457			return nil, nil, errors.New("cannot load string table section")
   458		}
   459	
   460		// The first entry is all zeros.
   461		var skip [Sym64Size]byte
   462		symtab.Read(skip[0:])
   463	
   464		symbols := make([]Symbol, symtab.Len()/Sym64Size)
   465	
   466		i := 0
   467		var sym Sym64
   468		for symtab.Len() > 0 {
   469			binary.Read(symtab, f.ByteOrder, &sym)
   470			str, _ := getString(strdata, int(sym.Name))
   471			symbols[i].Name = str
   472			symbols[i].Info = sym.Info
   473			symbols[i].Other = sym.Other
   474			symbols[i].Section = SectionIndex(sym.Shndx)
   475			symbols[i].Value = sym.Value
   476			symbols[i].Size = sym.Size
   477			i++
   478		}
   479	
   480		return symbols, strdata, nil
   481	}
   482	
   483	// getString extracts a string from an ELF string table.
   484	func getString(section []byte, start int) (string, bool) {
   485		if start < 0 || start >= len(section) {
   486			return "", false
   487		}
   488	
   489		for end := start; end < len(section); end++ {
   490			if section[end] == 0 {
   491				return string(section[start:end]), true
   492			}
   493		}
   494		return "", false
   495	}
   496	
   497	// Section returns a section with the given name, or nil if no such
   498	// section exists.
   499	func (f *File) Section(name string) *Section {
   500		for _, s := range f.Sections {
   501			if s.Name == name {
   502				return s
   503			}
   504		}
   505		return nil
   506	}
   507	
   508	// applyRelocations applies relocations to dst. rels is a relocations section
   509	// in RELA format.
   510	func (f *File) applyRelocations(dst []byte, rels []byte) error {
   511		if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
   512			return f.applyRelocationsAMD64(dst, rels)
   513		}
   514	
   515		return errors.New("not implemented")
   516	}
   517	
   518	func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
   519		if len(rels)%Sym64Size != 0 {
   520			return errors.New("length of relocation section is not a multiple of Sym64Size")
   521		}
   522	
   523		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   524		if err != nil {
   525			return err
   526		}
   527	
   528		b := bytes.NewBuffer(rels)
   529		var rela Rela64
   530	
   531		for b.Len() > 0 {
   532			binary.Read(b, f.ByteOrder, &rela)
   533			symNo := rela.Info >> 32
   534			t := R_X86_64(rela.Info & 0xffff)
   535	
   536			if symNo >= uint64(len(symbols)) {
   537				continue
   538			}
   539			sym := &symbols[symNo]
   540			if SymType(sym.Info&0xf) != STT_SECTION {
   541				// We don't handle non-section relocations for now.
   542				continue
   543			}
   544	
   545			switch t {
   546			case R_X86_64_64:
   547				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
   548					continue
   549				}
   550				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
   551			case R_X86_64_32:
   552				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
   553					continue
   554				}
   555				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   556			}
   557		}
   558	
   559		return nil
   560	}
   561	
   562	func (f *File) DWARF() (*dwarf.Data, error) {
   563		// There are many other DWARF sections, but these
   564		// are the required ones, and the debug/dwarf package
   565		// does not use the others, so don't bother loading them.
   566		var names = [...]string{"abbrev", "info", "str"}
   567		var dat [len(names)][]byte
   568		for i, name := range names {
   569			name = ".debug_" + name
   570			s := f.Section(name)
   571			if s == nil {
   572				continue
   573			}
   574			b, err := s.Data()
   575			if err != nil && uint64(len(b)) < s.Size {
   576				return nil, err
   577			}
   578			dat[i] = b
   579		}
   580	
   581		// If there's a relocation table for .debug_info, we have to process it
   582		// now otherwise the data in .debug_info is invalid for x86-64 objects.
   583		rela := f.Section(".rela.debug_info")
   584		if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
   585			data, err := rela.Data()
   586			if err != nil {
   587				return nil, err
   588			}
   589			err = f.applyRelocations(dat[1], data)
   590			if err != nil {
   591				return nil, err
   592			}
   593		}
   594	
   595		abbrev, info, str := dat[0], dat[1], dat[2]
   596		return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
   597	}
   598	
   599	// Symbols returns the symbol table for f.
   600	func (f *File) Symbols() ([]Symbol, error) {
   601		sym, _, err := f.getSymbols(SHT_SYMTAB)
   602		return sym, err
   603	}
   604	
   605	type ImportedSymbol struct {
   606		Name    string
   607		Version string
   608		Library string
   609	}
   610	
   611	// ImportedSymbols returns the names of all symbols
   612	// referred to by the binary f that are expected to be
   613	// satisfied by other libraries at dynamic load time.
   614	// It does not return weak symbols.
   615	func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
   616		sym, str, err := f.getSymbols(SHT_DYNSYM)
   617		if err != nil {
   618			return nil, err
   619		}
   620		f.gnuVersionInit(str)
   621		var all []ImportedSymbol
   622		for i, s := range sym {
   623			if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
   624				all = append(all, ImportedSymbol{Name: s.Name})
   625				f.gnuVersion(i, &all[len(all)-1])
   626			}
   627		}
   628		return all, nil
   629	}
   630	
   631	type verneed struct {
   632		File string
   633		Name string
   634	}
   635	
   636	// gnuVersionInit parses the GNU version tables
   637	// for use by calls to gnuVersion.
   638	func (f *File) gnuVersionInit(str []byte) {
   639		// Accumulate verneed information.
   640		vn := f.SectionByType(SHT_GNU_VERNEED)
   641		if vn == nil {
   642			return
   643		}
   644		d, _ := vn.Data()
   645	
   646		var need []verneed
   647		i := 0
   648		for {
   649			if i+16 > len(d) {
   650				break
   651			}
   652			vers := f.ByteOrder.Uint16(d[i : i+2])
   653			if vers != 1 {
   654				break
   655			}
   656			cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
   657			fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
   658			aux := f.ByteOrder.Uint32(d[i+8 : i+12])
   659			next := f.ByteOrder.Uint32(d[i+12 : i+16])
   660			file, _ := getString(str, int(fileoff))
   661	
   662			var name string
   663			j := i + int(aux)
   664			for c := 0; c < int(cnt); c++ {
   665				if j+16 > len(d) {
   666					break
   667				}
   668				// hash := f.ByteOrder.Uint32(d[j:j+4])
   669				// flags := f.ByteOrder.Uint16(d[j+4:j+6])
   670				other := f.ByteOrder.Uint16(d[j+6 : j+8])
   671				nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
   672				next := f.ByteOrder.Uint32(d[j+12 : j+16])
   673				name, _ = getString(str, int(nameoff))
   674				ndx := int(other)
   675				if ndx >= len(need) {
   676					a := make([]verneed, 2*(ndx+1))
   677					copy(a, need)
   678					need = a
   679				}
   680	
   681				need[ndx] = verneed{file, name}
   682				if next == 0 {
   683					break
   684				}
   685				j += int(next)
   686			}
   687	
   688			if next == 0 {
   689				break
   690			}
   691			i += int(next)
   692		}
   693	
   694		// Versym parallels symbol table, indexing into verneed.
   695		vs := f.SectionByType(SHT_GNU_VERSYM)
   696		if vs == nil {
   697			return
   698		}
   699		d, _ = vs.Data()
   700	
   701		f.gnuNeed = need
   702		f.gnuVersym = d
   703	}
   704	
   705	// gnuVersion adds Library and Version information to sym,
   706	// which came from offset i of the symbol table.
   707	func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
   708		// Each entry is two bytes; skip undef entry at beginning.
   709		i = (i + 1) * 2
   710		if i >= len(f.gnuVersym) {
   711			return
   712		}
   713		j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
   714		if j < 2 || j >= len(f.gnuNeed) {
   715			return
   716		}
   717		n := &f.gnuNeed[j]
   718		sym.Library = n.File
   719		sym.Version = n.Name
   720	}
   721	
   722	// ImportedLibraries returns the names of all libraries
   723	// referred to by the binary f that are expected to be
   724	// linked with the binary at dynamic link time.
   725	func (f *File) ImportedLibraries() ([]string, error) {
   726		ds := f.SectionByType(SHT_DYNAMIC)
   727		if ds == nil {
   728			// not dynamic, so no libraries
   729			return nil, nil
   730		}
   731		d, err := ds.Data()
   732		if err != nil {
   733			return nil, err
   734		}
   735		str, err := f.stringTable(ds.Link)
   736		if err != nil {
   737			return nil, err
   738		}
   739		var all []string
   740		for len(d) > 0 {
   741			var tag DynTag
   742			var value uint64
   743			switch f.Class {
   744			case ELFCLASS32:
   745				tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
   746				value = uint64(f.ByteOrder.Uint32(d[4:8]))
   747				d = d[8:]
   748			case ELFCLASS64:
   749				tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
   750				value = f.ByteOrder.Uint64(d[8:16])
   751				d = d[16:]
   752			}
   753			if tag == DT_NEEDED {
   754				s, ok := getString(str, int(value))
   755				if ok {
   756					all = append(all, s)
   757				}
   758			}
   759		}
   760	
   761		return all, nil
   762	}