section.mx raw

   1  // Copyright 2016 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 pe
   6  
   7  import (
   8  	"encoding/binary"
   9  	"fmt"
  10  	"internal/saferio"
  11  	"io"
  12  	"strconv"
  13  )
  14  
  15  // SectionHeader32 represents real PE COFF section header.
  16  type SectionHeader32 struct {
  17  	Name                 [8]uint8
  18  	VirtualSize          uint32
  19  	VirtualAddress       uint32
  20  	SizeOfRawData        uint32
  21  	PointerToRawData     uint32
  22  	PointerToRelocations uint32
  23  	PointerToLineNumbers uint32
  24  	NumberOfRelocations  uint16
  25  	NumberOfLineNumbers  uint16
  26  	Characteristics      uint32
  27  }
  28  
  29  // fullName finds real name of section sh. Normally name is stored
  30  // in sh.Name, but if it is longer then 8 characters, it is stored
  31  // in COFF string table st instead.
  32  func (sh *SectionHeader32) fullName(st StringTable) (string, error) {
  33  	if sh.Name[0] != '/' {
  34  		return cstring(sh.Name[:]), nil
  35  	}
  36  	i, err := strconv.Atoi(cstring(sh.Name[1:]))
  37  	if err != nil {
  38  		return "", err
  39  	}
  40  	return st.String(uint32(i))
  41  }
  42  
  43  // TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here
  44  
  45  // Reloc represents a PE COFF relocation.
  46  // Each section contains its own relocation list.
  47  type Reloc struct {
  48  	VirtualAddress   uint32
  49  	SymbolTableIndex uint32
  50  	Type             uint16
  51  }
  52  
  53  func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) {
  54  	if sh.NumberOfRelocations <= 0 {
  55  		return nil, nil
  56  	}
  57  	_, err := r.Seek(int64(sh.PointerToRelocations), io.SeekStart)
  58  	if err != nil {
  59  		return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
  60  	}
  61  	relocs := []Reloc{:sh.NumberOfRelocations}
  62  	err = binary.Read(r, binary.LittleEndian, relocs)
  63  	if err != nil {
  64  		return nil, fmt.Errorf("fail to read section relocations: %v", err)
  65  	}
  66  	return relocs, nil
  67  }
  68  
  69  // SectionHeader is similar to [SectionHeader32] with Name
  70  // field replaced by Go string.
  71  type SectionHeader struct {
  72  	Name                 string
  73  	VirtualSize          uint32
  74  	VirtualAddress       uint32
  75  	Size                 uint32
  76  	Offset               uint32
  77  	PointerToRelocations uint32
  78  	PointerToLineNumbers uint32
  79  	NumberOfRelocations  uint16
  80  	NumberOfLineNumbers  uint16
  81  	Characteristics      uint32
  82  }
  83  
  84  // Section provides access to PE COFF section.
  85  type Section struct {
  86  	SectionHeader
  87  	Relocs []Reloc
  88  
  89  	// Embed ReaderAt for ReadAt method.
  90  	// Do not embed SectionReader directly
  91  	// to avoid having Read and Seek.
  92  	// If a client wants Read and Seek it must use
  93  	// Open() to avoid fighting over the seek offset
  94  	// with other clients.
  95  	io.ReaderAt
  96  	sr *io.SectionReader
  97  }
  98  
  99  // Data reads and returns the contents of the PE section s.
 100  //
 101  // If s.Offset is 0, the section has no contents,
 102  // and Data will always return a non-nil error.
 103  func (s *Section) Data() ([]byte, error) {
 104  	return saferio.ReadDataAt(s.sr, uint64(s.Size), 0)
 105  }
 106  
 107  // Open returns a new ReadSeeker reading the PE section s.
 108  //
 109  // If s.Offset is 0, the section has no contents, and all calls
 110  // to the returned reader will return a non-nil error.
 111  func (s *Section) Open() io.ReadSeeker {
 112  	return io.NewSectionReader(s.sr, 0, 1<<63-1)
 113  }
 114  
 115  // Section characteristics flags.
 116  const (
 117  	IMAGE_SCN_CNT_CODE               = 0x00000020
 118  	IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
 119  	IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
 120  	IMAGE_SCN_LNK_COMDAT             = 0x00001000
 121  	IMAGE_SCN_MEM_DISCARDABLE        = 0x02000000
 122  	IMAGE_SCN_MEM_EXECUTE            = 0x20000000
 123  	IMAGE_SCN_MEM_READ               = 0x40000000
 124  	IMAGE_SCN_MEM_WRITE              = 0x80000000
 125  )
 126