...

Source file src/pkg/cmd/link/internal/loadpe/ldpe.go

     1	// Copyright 2010 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 loadpe implements a PE/COFF file reader.
     6	package loadpe
     7	
     8	import (
     9		"cmd/internal/bio"
    10		"cmd/internal/objabi"
    11		"cmd/internal/sys"
    12		"cmd/link/internal/sym"
    13		"debug/pe"
    14		"encoding/binary"
    15		"errors"
    16		"fmt"
    17		"io"
    18		"sort"
    19		"strings"
    20	)
    21	
    22	const (
    23		// TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 (same with IMAGE_SYM_DTYPE_POINTER and IMAGE_SYM_DTYPE_FUNCTION)
    24		IMAGE_SYM_UNDEFINED              = 0
    25		IMAGE_SYM_ABSOLUTE               = -1
    26		IMAGE_SYM_DEBUG                  = -2
    27		IMAGE_SYM_TYPE_NULL              = 0
    28		IMAGE_SYM_TYPE_VOID              = 1
    29		IMAGE_SYM_TYPE_CHAR              = 2
    30		IMAGE_SYM_TYPE_SHORT             = 3
    31		IMAGE_SYM_TYPE_INT               = 4
    32		IMAGE_SYM_TYPE_LONG              = 5
    33		IMAGE_SYM_TYPE_FLOAT             = 6
    34		IMAGE_SYM_TYPE_DOUBLE            = 7
    35		IMAGE_SYM_TYPE_STRUCT            = 8
    36		IMAGE_SYM_TYPE_UNION             = 9
    37		IMAGE_SYM_TYPE_ENUM              = 10
    38		IMAGE_SYM_TYPE_MOE               = 11
    39		IMAGE_SYM_TYPE_BYTE              = 12
    40		IMAGE_SYM_TYPE_WORD              = 13
    41		IMAGE_SYM_TYPE_UINT              = 14
    42		IMAGE_SYM_TYPE_DWORD             = 15
    43		IMAGE_SYM_TYPE_PCODE             = 32768
    44		IMAGE_SYM_DTYPE_NULL             = 0
    45		IMAGE_SYM_DTYPE_POINTER          = 0x10
    46		IMAGE_SYM_DTYPE_FUNCTION         = 0x20
    47		IMAGE_SYM_DTYPE_ARRAY            = 0x30
    48		IMAGE_SYM_CLASS_END_OF_FUNCTION  = -1
    49		IMAGE_SYM_CLASS_NULL             = 0
    50		IMAGE_SYM_CLASS_AUTOMATIC        = 1
    51		IMAGE_SYM_CLASS_EXTERNAL         = 2
    52		IMAGE_SYM_CLASS_STATIC           = 3
    53		IMAGE_SYM_CLASS_REGISTER         = 4
    54		IMAGE_SYM_CLASS_EXTERNAL_DEF     = 5
    55		IMAGE_SYM_CLASS_LABEL            = 6
    56		IMAGE_SYM_CLASS_UNDEFINED_LABEL  = 7
    57		IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
    58		IMAGE_SYM_CLASS_ARGUMENT         = 9
    59		IMAGE_SYM_CLASS_STRUCT_TAG       = 10
    60		IMAGE_SYM_CLASS_MEMBER_OF_UNION  = 11
    61		IMAGE_SYM_CLASS_UNION_TAG        = 12
    62		IMAGE_SYM_CLASS_TYPE_DEFINITION  = 13
    63		IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
    64		IMAGE_SYM_CLASS_ENUM_TAG         = 15
    65		IMAGE_SYM_CLASS_MEMBER_OF_ENUM   = 16
    66		IMAGE_SYM_CLASS_REGISTER_PARAM   = 17
    67		IMAGE_SYM_CLASS_BIT_FIELD        = 18
    68		IMAGE_SYM_CLASS_FAR_EXTERNAL     = 68 /* Not in PECOFF v8 spec */
    69		IMAGE_SYM_CLASS_BLOCK            = 100
    70		IMAGE_SYM_CLASS_FUNCTION         = 101
    71		IMAGE_SYM_CLASS_END_OF_STRUCT    = 102
    72		IMAGE_SYM_CLASS_FILE             = 103
    73		IMAGE_SYM_CLASS_SECTION          = 104
    74		IMAGE_SYM_CLASS_WEAK_EXTERNAL    = 105
    75		IMAGE_SYM_CLASS_CLR_TOKEN        = 107
    76		IMAGE_REL_I386_ABSOLUTE          = 0x0000
    77		IMAGE_REL_I386_DIR16             = 0x0001
    78		IMAGE_REL_I386_REL16             = 0x0002
    79		IMAGE_REL_I386_DIR32             = 0x0006
    80		IMAGE_REL_I386_DIR32NB           = 0x0007
    81		IMAGE_REL_I386_SEG12             = 0x0009
    82		IMAGE_REL_I386_SECTION           = 0x000A
    83		IMAGE_REL_I386_SECREL            = 0x000B
    84		IMAGE_REL_I386_TOKEN             = 0x000C
    85		IMAGE_REL_I386_SECREL7           = 0x000D
    86		IMAGE_REL_I386_REL32             = 0x0014
    87		IMAGE_REL_AMD64_ABSOLUTE         = 0x0000
    88		IMAGE_REL_AMD64_ADDR64           = 0x0001
    89		IMAGE_REL_AMD64_ADDR32           = 0x0002
    90		IMAGE_REL_AMD64_ADDR32NB         = 0x0003
    91		IMAGE_REL_AMD64_REL32            = 0x0004
    92		IMAGE_REL_AMD64_REL32_1          = 0x0005
    93		IMAGE_REL_AMD64_REL32_2          = 0x0006
    94		IMAGE_REL_AMD64_REL32_3          = 0x0007
    95		IMAGE_REL_AMD64_REL32_4          = 0x0008
    96		IMAGE_REL_AMD64_REL32_5          = 0x0009
    97		IMAGE_REL_AMD64_SECTION          = 0x000A
    98		IMAGE_REL_AMD64_SECREL           = 0x000B
    99		IMAGE_REL_AMD64_SECREL7          = 0x000C
   100		IMAGE_REL_AMD64_TOKEN            = 0x000D
   101		IMAGE_REL_AMD64_SREL32           = 0x000E
   102		IMAGE_REL_AMD64_PAIR             = 0x000F
   103		IMAGE_REL_AMD64_SSPAN32          = 0x0010
   104		IMAGE_REL_ARM_ABSOLUTE           = 0x0000
   105		IMAGE_REL_ARM_ADDR32             = 0x0001
   106		IMAGE_REL_ARM_ADDR32NB           = 0x0002
   107		IMAGE_REL_ARM_BRANCH24           = 0x0003
   108		IMAGE_REL_ARM_BRANCH11           = 0x0004
   109		IMAGE_REL_ARM_SECTION            = 0x000E
   110		IMAGE_REL_ARM_SECREL             = 0x000F
   111		IMAGE_REL_ARM_MOV32              = 0x0010
   112		IMAGE_REL_THUMB_MOV32            = 0x0011
   113		IMAGE_REL_THUMB_BRANCH20         = 0x0012
   114		IMAGE_REL_THUMB_BRANCH24         = 0x0014
   115		IMAGE_REL_THUMB_BLX23            = 0x0015
   116		IMAGE_REL_ARM_PAIR               = 0x0016
   117	)
   118	
   119	// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe.
   120	const (
   121		IMAGE_SCN_CNT_CODE               = 0x00000020
   122		IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
   123		IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
   124		IMAGE_SCN_MEM_DISCARDABLE        = 0x02000000
   125		IMAGE_SCN_MEM_EXECUTE            = 0x20000000
   126		IMAGE_SCN_MEM_READ               = 0x40000000
   127		IMAGE_SCN_MEM_WRITE              = 0x80000000
   128	)
   129	
   130	// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf
   131	
   132	// peBiobuf makes bio.Reader look like io.ReaderAt.
   133	type peBiobuf bio.Reader
   134	
   135	func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
   136		ret := ((*bio.Reader)(f)).MustSeek(off, 0)
   137		if ret < 0 {
   138			return 0, errors.New("fail to seek")
   139		}
   140		n, err := f.Read(p)
   141		if err != nil {
   142			return 0, err
   143		}
   144		return n, nil
   145	}
   146	
   147	// Load loads the PE file pn from input.
   148	// Symbols are written into syms, and a slice of the text symbols is returned.
   149	// If an .rsrc section is found, its symbol is returned as rsrc.
   150	func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
   151		localSymVersion := syms.IncVersion()
   152	
   153		sectsyms := make(map[*pe.Section]*sym.Symbol)
   154		sectdata := make(map[*pe.Section][]byte)
   155	
   156		// Some input files are archives containing multiple of
   157		// object files, and pe.NewFile seeks to the start of
   158		// input file and get confused. Create section reader
   159		// to stop pe.NewFile looking before current position.
   160		sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1)
   161	
   162		// TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
   163		f, err := pe.NewFile(sr)
   164		if err != nil {
   165			return nil, nil, err
   166		}
   167		defer f.Close()
   168	
   169		// TODO return error if found .cormeta
   170	
   171		// create symbols for mapped sections
   172		for _, sect := range f.Sections {
   173			if sect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
   174				continue
   175			}
   176	
   177			if sect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
   178				// This has been seen for .idata sections, which we
   179				// want to ignore. See issues 5106 and 5273.
   180				continue
   181			}
   182	
   183			name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
   184			s := syms.Lookup(name, localSymVersion)
   185	
   186			switch sect.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
   187			case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
   188				s.Type = sym.SRODATA
   189	
   190			case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
   191				s.Type = sym.SNOPTRBSS
   192	
   193			case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
   194				s.Type = sym.SNOPTRDATA
   195	
   196			case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
   197				s.Type = sym.STEXT
   198	
   199			default:
   200				return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
   201			}
   202	
   203			if s.Type != sym.SNOPTRBSS {
   204				data, err := sect.Data()
   205				if err != nil {
   206					return nil, nil, err
   207				}
   208				sectdata[sect] = data
   209				s.P = data
   210			}
   211			s.Size = int64(sect.Size)
   212			sectsyms[sect] = s
   213			if sect.Name == ".rsrc" {
   214				rsrc = s
   215			}
   216		}
   217	
   218		// load relocations
   219		for _, rsect := range f.Sections {
   220			if _, found := sectsyms[rsect]; !found {
   221				continue
   222			}
   223			if rsect.NumberOfRelocations == 0 {
   224				continue
   225			}
   226			if rsect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
   227				continue
   228			}
   229			if rsect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
   230				// This has been seen for .idata sections, which we
   231				// want to ignore. See issues 5106 and 5273.
   232				continue
   233			}
   234	
   235			rs := make([]sym.Reloc, rsect.NumberOfRelocations)
   236			for j, r := range rsect.Relocs {
   237				rp := &rs[j]
   238				if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
   239					return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
   240				}
   241				pesym := &f.COFFSymbols[r.SymbolTableIndex]
   242				gosym, err := readpesym(arch, syms, f, pesym, sectsyms, localSymVersion)
   243				if err != nil {
   244					return nil, nil, err
   245				}
   246				if gosym == nil {
   247					name, err := pesym.FullName(f.StringTable)
   248					if err != nil {
   249						name = string(pesym.Name[:])
   250					}
   251					return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
   252				}
   253	
   254				rp.Sym = gosym
   255				rp.Siz = 4
   256				rp.Off = int32(r.VirtualAddress)
   257				switch arch.Family {
   258				default:
   259					return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
   260				case sys.I386, sys.AMD64:
   261					switch r.Type {
   262					default:
   263						return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
   264	
   265					case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
   266						IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
   267						IMAGE_REL_AMD64_ADDR32NB:
   268						rp.Type = objabi.R_PCREL
   269	
   270						rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
   271	
   272					case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
   273						rp.Type = objabi.R_ADDR
   274	
   275						// load addend from image
   276						rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
   277	
   278					case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
   279						rp.Siz = 8
   280	
   281						rp.Type = objabi.R_ADDR
   282	
   283						// load addend from image
   284						rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:]))
   285					}
   286	
   287				case sys.ARM:
   288					switch r.Type {
   289					default:
   290						return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
   291	
   292					case IMAGE_REL_ARM_SECREL:
   293						rp.Type = objabi.R_PCREL
   294	
   295						rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
   296	
   297					case IMAGE_REL_ARM_ADDR32:
   298						rp.Type = objabi.R_ADDR
   299	
   300						rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
   301	
   302					case IMAGE_REL_ARM_BRANCH24:
   303						rp.Type = objabi.R_CALLARM
   304	
   305						rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
   306					}
   307				}
   308	
   309				// ld -r could generate multiple section symbols for the
   310				// same section but with different values, we have to take
   311				// that into account
   312				if issect(pesym) {
   313					rp.Add += int64(pesym.Value)
   314				}
   315			}
   316	
   317			sort.Sort(sym.RelocByOff(rs[:rsect.NumberOfRelocations]))
   318	
   319			s := sectsyms[rsect]
   320			s.R = rs
   321			s.R = s.R[:rsect.NumberOfRelocations]
   322		}
   323	
   324		// enter sub-symbols into symbol table.
   325		for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 {
   326			pesym := &f.COFFSymbols[i]
   327	
   328			numaux = int(pesym.NumberOfAuxSymbols)
   329	
   330			name, err := pesym.FullName(f.StringTable)
   331			if err != nil {
   332				return nil, nil, err
   333			}
   334			if name == "" {
   335				continue
   336			}
   337			if issect(pesym) {
   338				continue
   339			}
   340			if int(pesym.SectionNumber) > len(f.Sections) {
   341				continue
   342			}
   343			if pesym.SectionNumber == IMAGE_SYM_DEBUG {
   344				continue
   345			}
   346			var sect *pe.Section
   347			if pesym.SectionNumber > 0 {
   348				sect = f.Sections[pesym.SectionNumber-1]
   349				if _, found := sectsyms[sect]; !found {
   350					continue
   351				}
   352			}
   353	
   354			s, err := readpesym(arch, syms, f, pesym, sectsyms, localSymVersion)
   355			if err != nil {
   356				return nil, nil, err
   357			}
   358	
   359			if pesym.SectionNumber == 0 { // extern
   360				if s.Type == sym.SDYNIMPORT {
   361					s.SetPlt(-2) // flag for dynimport in PE object files.
   362				}
   363				if s.Type == sym.SXREF && pesym.Value > 0 { // global data
   364					s.Type = sym.SNOPTRDATA
   365					s.Size = int64(pesym.Value)
   366				}
   367	
   368				continue
   369			} else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
   370				sect = f.Sections[pesym.SectionNumber-1]
   371				if _, found := sectsyms[sect]; !found {
   372					return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
   373				}
   374			} else {
   375				return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
   376			}
   377	
   378			if sect == nil {
   379				return nil, rsrc, nil
   380			}
   381	
   382			if s.Outer != nil {
   383				if s.Attr.DuplicateOK() {
   384					continue
   385				}
   386				return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name)
   387			}
   388	
   389			sectsym := sectsyms[sect]
   390			s.Sub = sectsym.Sub
   391			sectsym.Sub = s
   392			s.Type = sectsym.Type
   393			s.Attr |= sym.AttrSubSymbol
   394			s.Value = int64(pesym.Value)
   395			s.Size = 4
   396			s.Outer = sectsym
   397			if sectsym.Type == sym.STEXT {
   398				if s.Attr.External() && !s.Attr.DuplicateOK() {
   399					return nil, nil, fmt.Errorf("%s: duplicate symbol definition", s.Name)
   400				}
   401				s.Attr |= sym.AttrExternal
   402			}
   403		}
   404	
   405		// Sort outer lists by address, adding to textp.
   406		// This keeps textp in increasing address order.
   407		for _, sect := range f.Sections {
   408			s := sectsyms[sect]
   409			if s == nil {
   410				continue
   411			}
   412			if s.Sub != nil {
   413				s.Sub = sym.SortSub(s.Sub)
   414			}
   415			if s.Type == sym.STEXT {
   416				if s.Attr.OnList() {
   417					return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
   418				}
   419				s.Attr |= sym.AttrOnList
   420				textp = append(textp, s)
   421				for s = s.Sub; s != nil; s = s.Sub {
   422					if s.Attr.OnList() {
   423						return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
   424					}
   425					s.Attr |= sym.AttrOnList
   426					textp = append(textp, s)
   427				}
   428			}
   429		}
   430	
   431		return textp, rsrc, nil
   432	}
   433	
   434	func issect(s *pe.COFFSymbol) bool {
   435		return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
   436	}
   437	
   438	func readpesym(arch *sys.Arch, syms *sym.Symbols, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
   439		symname, err := pesym.FullName(f.StringTable)
   440		if err != nil {
   441			return nil, err
   442		}
   443		var name string
   444		if issect(pesym) {
   445			name = sectsyms[f.Sections[pesym.SectionNumber-1]].Name
   446		} else {
   447			name = symname
   448			name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name
   449			if arch.Family == sys.I386 && name[0] == '_' {
   450				name = name[1:] // _Name => Name
   451			}
   452		}
   453	
   454		// remove last @XXX
   455		if i := strings.LastIndex(name, "@"); i >= 0 {
   456			name = name[:i]
   457		}
   458	
   459		var s *sym.Symbol
   460		switch pesym.Type {
   461		default:
   462			return nil, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
   463	
   464		case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
   465			switch pesym.StorageClass {
   466			case IMAGE_SYM_CLASS_EXTERNAL: //global
   467				s = syms.Lookup(name, 0)
   468	
   469			case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
   470				s = syms.Lookup(name, localSymVersion)
   471				s.Attr |= sym.AttrDuplicateOK
   472	
   473			default:
   474				return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
   475			}
   476		}
   477	
   478		if s != nil && s.Type == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
   479			s.Type = sym.SXREF
   480		}
   481		if strings.HasPrefix(symname, "__imp_") {
   482			s.SetGot(-2) // flag for __imp_
   483		}
   484	
   485		return s, nil
   486	}
   487	

View as plain text