github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/link/internal/ld/ldpe.go (about)

     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 ld
     6  
     7  import (
     8  	"cmd/internal/bio"
     9  	"cmd/internal/obj"
    10  	"cmd/internal/sys"
    11  	"encoding/binary"
    12  	"fmt"
    13  	"io"
    14  	"log"
    15  	"sort"
    16  	"strconv"
    17  	"strings"
    18  )
    19  
    20  const (
    21  	IMAGE_SYM_UNDEFINED              = 0
    22  	IMAGE_SYM_ABSOLUTE               = -1
    23  	IMAGE_SYM_DEBUG                  = -2
    24  	IMAGE_SYM_TYPE_NULL              = 0
    25  	IMAGE_SYM_TYPE_VOID              = 1
    26  	IMAGE_SYM_TYPE_CHAR              = 2
    27  	IMAGE_SYM_TYPE_SHORT             = 3
    28  	IMAGE_SYM_TYPE_INT               = 4
    29  	IMAGE_SYM_TYPE_LONG              = 5
    30  	IMAGE_SYM_TYPE_FLOAT             = 6
    31  	IMAGE_SYM_TYPE_DOUBLE            = 7
    32  	IMAGE_SYM_TYPE_STRUCT            = 8
    33  	IMAGE_SYM_TYPE_UNION             = 9
    34  	IMAGE_SYM_TYPE_ENUM              = 10
    35  	IMAGE_SYM_TYPE_MOE               = 11
    36  	IMAGE_SYM_TYPE_BYTE              = 12
    37  	IMAGE_SYM_TYPE_WORD              = 13
    38  	IMAGE_SYM_TYPE_UINT              = 14
    39  	IMAGE_SYM_TYPE_DWORD             = 15
    40  	IMAGE_SYM_TYPE_PCODE             = 32768
    41  	IMAGE_SYM_DTYPE_NULL             = 0
    42  	IMAGE_SYM_DTYPE_POINTER          = 0x10
    43  	IMAGE_SYM_DTYPE_FUNCTION         = 0x20
    44  	IMAGE_SYM_DTYPE_ARRAY            = 0x30
    45  	IMAGE_SYM_CLASS_END_OF_FUNCTION  = -1
    46  	IMAGE_SYM_CLASS_NULL             = 0
    47  	IMAGE_SYM_CLASS_AUTOMATIC        = 1
    48  	IMAGE_SYM_CLASS_EXTERNAL         = 2
    49  	IMAGE_SYM_CLASS_STATIC           = 3
    50  	IMAGE_SYM_CLASS_REGISTER         = 4
    51  	IMAGE_SYM_CLASS_EXTERNAL_DEF     = 5
    52  	IMAGE_SYM_CLASS_LABEL            = 6
    53  	IMAGE_SYM_CLASS_UNDEFINED_LABEL  = 7
    54  	IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
    55  	IMAGE_SYM_CLASS_ARGUMENT         = 9
    56  	IMAGE_SYM_CLASS_STRUCT_TAG       = 10
    57  	IMAGE_SYM_CLASS_MEMBER_OF_UNION  = 11
    58  	IMAGE_SYM_CLASS_UNION_TAG        = 12
    59  	IMAGE_SYM_CLASS_TYPE_DEFINITION  = 13
    60  	IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
    61  	IMAGE_SYM_CLASS_ENUM_TAG         = 15
    62  	IMAGE_SYM_CLASS_MEMBER_OF_ENUM   = 16
    63  	IMAGE_SYM_CLASS_REGISTER_PARAM   = 17
    64  	IMAGE_SYM_CLASS_BIT_FIELD        = 18
    65  	IMAGE_SYM_CLASS_FAR_EXTERNAL     = 68 /* Not in PECOFF v8 spec */
    66  	IMAGE_SYM_CLASS_BLOCK            = 100
    67  	IMAGE_SYM_CLASS_FUNCTION         = 101
    68  	IMAGE_SYM_CLASS_END_OF_STRUCT    = 102
    69  	IMAGE_SYM_CLASS_FILE             = 103
    70  	IMAGE_SYM_CLASS_SECTION          = 104
    71  	IMAGE_SYM_CLASS_WEAK_EXTERNAL    = 105
    72  	IMAGE_SYM_CLASS_CLR_TOKEN        = 107
    73  	IMAGE_REL_I386_ABSOLUTE          = 0x0000
    74  	IMAGE_REL_I386_DIR16             = 0x0001
    75  	IMAGE_REL_I386_REL16             = 0x0002
    76  	IMAGE_REL_I386_DIR32             = 0x0006
    77  	IMAGE_REL_I386_DIR32NB           = 0x0007
    78  	IMAGE_REL_I386_SEG12             = 0x0009
    79  	IMAGE_REL_I386_SECTION           = 0x000A
    80  	IMAGE_REL_I386_SECREL            = 0x000B
    81  	IMAGE_REL_I386_TOKEN             = 0x000C
    82  	IMAGE_REL_I386_SECREL7           = 0x000D
    83  	IMAGE_REL_I386_REL32             = 0x0014
    84  	IMAGE_REL_AMD64_ABSOLUTE         = 0x0000
    85  	IMAGE_REL_AMD64_ADDR64           = 0x0001
    86  	IMAGE_REL_AMD64_ADDR32           = 0x0002
    87  	IMAGE_REL_AMD64_ADDR32NB         = 0x0003
    88  	IMAGE_REL_AMD64_REL32            = 0x0004
    89  	IMAGE_REL_AMD64_REL32_1          = 0x0005
    90  	IMAGE_REL_AMD64_REL32_2          = 0x0006
    91  	IMAGE_REL_AMD64_REL32_3          = 0x0007
    92  	IMAGE_REL_AMD64_REL32_4          = 0x0008
    93  	IMAGE_REL_AMD64_REL32_5          = 0x0009
    94  	IMAGE_REL_AMD64_SECTION          = 0x000A
    95  	IMAGE_REL_AMD64_SECREL           = 0x000B
    96  	IMAGE_REL_AMD64_SECREL7          = 0x000C
    97  	IMAGE_REL_AMD64_TOKEN            = 0x000D
    98  	IMAGE_REL_AMD64_SREL32           = 0x000E
    99  	IMAGE_REL_AMD64_PAIR             = 0x000F
   100  	IMAGE_REL_AMD64_SSPAN32          = 0x0010
   101  )
   102  
   103  type PeSym struct {
   104  	name    string
   105  	value   uint32
   106  	sectnum uint16
   107  	type_   uint16
   108  	sclass  uint8
   109  	aux     uint8
   110  	sym     *Symbol
   111  }
   112  
   113  type PeSect struct {
   114  	name string
   115  	base []byte
   116  	size uint64
   117  	sym  *Symbol
   118  	sh   IMAGE_SECTION_HEADER
   119  }
   120  
   121  type PeObj struct {
   122  	f      *bio.Reader
   123  	name   string
   124  	base   uint32
   125  	sect   []PeSect
   126  	nsect  uint
   127  	pesym  []PeSym
   128  	npesym uint
   129  	fh     IMAGE_FILE_HEADER
   130  	snames []byte
   131  }
   132  
   133  func ldpe(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
   134  	if ctxt.Debugvlog != 0 {
   135  		ctxt.Logf("%5.2f ldpe %s\n", obj.Cputime(), pn)
   136  	}
   137  
   138  	var sect *PeSect
   139  	ctxt.IncVersion()
   140  	base := f.Offset()
   141  
   142  	peobj := new(PeObj)
   143  	peobj.f = f
   144  	peobj.base = uint32(base)
   145  	peobj.name = pn
   146  
   147  	// read header
   148  	var err error
   149  	var j int
   150  	var l uint32
   151  	var name string
   152  	var numaux int
   153  	var r []Reloc
   154  	var rp *Reloc
   155  	var rsect *PeSect
   156  	var s *Symbol
   157  	var sym *PeSym
   158  	var symbuf [18]uint8
   159  	if err = binary.Read(f, binary.LittleEndian, &peobj.fh); err != nil {
   160  		goto bad
   161  	}
   162  
   163  	// load section list
   164  	peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)
   165  
   166  	peobj.nsect = uint(peobj.fh.NumberOfSections)
   167  	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
   168  		if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
   169  			goto bad
   170  		}
   171  		peobj.sect[i].size = uint64(peobj.sect[i].sh.SizeOfRawData)
   172  		peobj.sect[i].name = cstring(peobj.sect[i].sh.Name[:])
   173  	}
   174  
   175  	// TODO return error if found .cormeta
   176  
   177  	// load string table
   178  	f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
   179  
   180  	if _, err := io.ReadFull(f, symbuf[:4]); err != nil {
   181  		goto bad
   182  	}
   183  	l = Le32(symbuf[:])
   184  	peobj.snames = make([]byte, l)
   185  	f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
   186  	if _, err := io.ReadFull(f, peobj.snames); err != nil {
   187  		goto bad
   188  	}
   189  
   190  	// rewrite section names if they start with /
   191  	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
   192  		if peobj.sect[i].name == "" {
   193  			continue
   194  		}
   195  		if peobj.sect[i].name[0] != '/' {
   196  			continue
   197  		}
   198  		n, _ := strconv.Atoi(peobj.sect[i].name[1:])
   199  		peobj.sect[i].name = cstring(peobj.snames[n:])
   200  	}
   201  
   202  	// read symbols
   203  	peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
   204  
   205  	peobj.npesym = uint(peobj.fh.NumberOfSymbols)
   206  	f.Seek(base+int64(peobj.fh.PointerToSymbolTable), 0)
   207  	for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
   208  		f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
   209  		if _, err := io.ReadFull(f, symbuf[:]); err != nil {
   210  			goto bad
   211  		}
   212  
   213  		if (symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0) {
   214  			l = Le32(symbuf[4:])
   215  			peobj.pesym[i].name = cstring(peobj.snames[l:]) // sym name length <= 8
   216  		} else {
   217  			peobj.pesym[i].name = cstring(symbuf[:8])
   218  		}
   219  
   220  		peobj.pesym[i].value = Le32(symbuf[8:])
   221  		peobj.pesym[i].sectnum = Le16(symbuf[12:])
   222  		peobj.pesym[i].sclass = symbuf[16]
   223  		peobj.pesym[i].aux = symbuf[17]
   224  		peobj.pesym[i].type_ = Le16(symbuf[14:])
   225  		numaux = int(peobj.pesym[i].aux)
   226  		if numaux < 0 {
   227  			numaux = 0
   228  		}
   229  	}
   230  
   231  	// create symbols for mapped sections
   232  	for i := 0; uint(i) < peobj.nsect; i++ {
   233  		sect = &peobj.sect[i]
   234  		if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
   235  			continue
   236  		}
   237  
   238  		if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
   239  			// This has been seen for .idata sections, which we
   240  			// want to ignore. See issues 5106 and 5273.
   241  			continue
   242  		}
   243  
   244  		if pemap(peobj, sect) < 0 {
   245  			goto bad
   246  		}
   247  
   248  		name = fmt.Sprintf("%s(%s)", pkg, sect.name)
   249  		s = Linklookup(ctxt, name, ctxt.Version)
   250  
   251  		switch sect.sh.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) {
   252  		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
   253  			s.Type = obj.SRODATA
   254  
   255  		case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
   256  			s.Type = obj.SNOPTRBSS
   257  
   258  		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
   259  			s.Type = obj.SNOPTRDATA
   260  
   261  		case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
   262  			s.Type = obj.STEXT
   263  
   264  		default:
   265  			err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
   266  			goto bad
   267  		}
   268  
   269  		s.P = sect.base
   270  		s.P = s.P[:sect.size]
   271  		s.Size = int64(sect.size)
   272  		sect.sym = s
   273  		if sect.name == ".rsrc" {
   274  			setpersrc(ctxt, sect.sym)
   275  		}
   276  	}
   277  
   278  	// load relocations
   279  	for i := 0; uint(i) < peobj.nsect; i++ {
   280  		rsect = &peobj.sect[i]
   281  		if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
   282  			continue
   283  		}
   284  		if rsect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
   285  			continue
   286  		}
   287  		if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
   288  			// This has been seen for .idata sections, which we
   289  			// want to ignore. See issues 5106 and 5273.
   290  			continue
   291  		}
   292  
   293  		r = make([]Reloc, rsect.sh.NumberOfRelocations)
   294  		f.Seek(int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
   295  		for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
   296  			rp = &r[j]
   297  			if _, err := io.ReadFull(f, symbuf[:10]); err != nil {
   298  				goto bad
   299  			}
   300  			rva := Le32(symbuf[0:])
   301  			symindex := Le32(symbuf[4:])
   302  			type_ := Le16(symbuf[8:])
   303  			if err = readpesym(ctxt, peobj, int(symindex), &sym); err != nil {
   304  				goto bad
   305  			}
   306  			if sym.sym == nil {
   307  				err = fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", sym.name, symindex, sym.type_)
   308  				goto bad
   309  			}
   310  
   311  			rp.Sym = sym.sym
   312  			rp.Siz = 4
   313  			rp.Off = int32(rva)
   314  			switch type_ {
   315  			default:
   316  				ctxt.Diag("%s: unknown relocation type %d;", pn, type_)
   317  				fallthrough
   318  
   319  			case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
   320  				IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
   321  				IMAGE_REL_AMD64_ADDR32NB:
   322  				rp.Type = obj.R_PCREL
   323  
   324  				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
   325  
   326  			case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
   327  				rp.Type = obj.R_ADDR
   328  
   329  				// load addend from image
   330  				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
   331  
   332  			case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
   333  				rp.Siz = 8
   334  
   335  				rp.Type = obj.R_ADDR
   336  
   337  				// load addend from image
   338  				rp.Add = int64(Le64(rsect.base[rp.Off:]))
   339  			}
   340  
   341  			// ld -r could generate multiple section symbols for the
   342  			// same section but with different values, we have to take
   343  			// that into account
   344  			if issect(&peobj.pesym[symindex]) {
   345  				rp.Add += int64(peobj.pesym[symindex].value)
   346  			}
   347  		}
   348  
   349  		sort.Sort(rbyoff(r[:rsect.sh.NumberOfRelocations]))
   350  
   351  		s = rsect.sym
   352  		s.R = r
   353  		s.R = s.R[:rsect.sh.NumberOfRelocations]
   354  	}
   355  
   356  	// enter sub-symbols into symbol table.
   357  	for i := 0; uint(i) < peobj.npesym; i++ {
   358  		if peobj.pesym[i].name == "" {
   359  			continue
   360  		}
   361  		if issect(&peobj.pesym[i]) {
   362  			continue
   363  		}
   364  		if uint(peobj.pesym[i].sectnum) > peobj.nsect {
   365  			continue
   366  		}
   367  		if peobj.pesym[i].sectnum > 0 {
   368  			sect = &peobj.sect[peobj.pesym[i].sectnum-1]
   369  			if sect.sym == nil {
   370  				continue
   371  			}
   372  		}
   373  
   374  		if err = readpesym(ctxt, peobj, i, &sym); err != nil {
   375  			goto bad
   376  		}
   377  
   378  		s = sym.sym
   379  		if sym.sectnum == 0 { // extern
   380  			if s.Type == obj.SDYNIMPORT {
   381  				s.Plt = -2 // flag for dynimport in PE object files.
   382  			}
   383  			if s.Type == obj.SXREF && sym.value > 0 { // global data
   384  				s.Type = obj.SNOPTRDATA
   385  				s.Size = int64(sym.value)
   386  			}
   387  
   388  			continue
   389  		} else if sym.sectnum > 0 && uint(sym.sectnum) <= peobj.nsect {
   390  			sect = &peobj.sect[sym.sectnum-1]
   391  			if sect.sym == nil {
   392  				ctxt.Diag("%s: %s sym == 0!", pn, s.Name)
   393  			}
   394  		} else {
   395  			ctxt.Diag("%s: %s sectnum < 0!", pn, s.Name)
   396  		}
   397  
   398  		if sect == nil {
   399  			return
   400  		}
   401  
   402  		if s.Outer != nil {
   403  			if s.Attr.DuplicateOK() {
   404  				continue
   405  			}
   406  			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
   407  		}
   408  
   409  		s.Sub = sect.sym.Sub
   410  		sect.sym.Sub = s
   411  		s.Type = sect.sym.Type | obj.SSUB
   412  		s.Value = int64(sym.value)
   413  		s.Size = 4
   414  		s.Outer = sect.sym
   415  		if sect.sym.Type == obj.STEXT {
   416  			if s.Attr.External() && !s.Attr.DuplicateOK() {
   417  				ctxt.Diag("%s: duplicate definition of %s", pn, s.Name)
   418  			}
   419  			s.Attr |= AttrExternal
   420  		}
   421  	}
   422  
   423  	// Sort outer lists by address, adding to textp.
   424  	// This keeps textp in increasing address order.
   425  	for i := 0; uint(i) < peobj.nsect; i++ {
   426  		s = peobj.sect[i].sym
   427  		if s == nil {
   428  			continue
   429  		}
   430  		if s.Sub != nil {
   431  			s.Sub = listsort(s.Sub)
   432  		}
   433  		if s.Type == obj.STEXT {
   434  			if s.Attr.OnList() {
   435  				log.Fatalf("symbol %s listed multiple times", s.Name)
   436  			}
   437  			s.Attr |= AttrOnList
   438  			ctxt.Textp = append(ctxt.Textp, s)
   439  			for s = s.Sub; s != nil; s = s.Sub {
   440  				if s.Attr.OnList() {
   441  					log.Fatalf("symbol %s listed multiple times", s.Name)
   442  				}
   443  				s.Attr |= AttrOnList
   444  				ctxt.Textp = append(ctxt.Textp, s)
   445  			}
   446  		}
   447  	}
   448  
   449  	return
   450  
   451  bad:
   452  	ctxt.Diag("%s: malformed pe file: %v", pn, err)
   453  }
   454  
   455  func pemap(peobj *PeObj, sect *PeSect) int {
   456  	if sect.base != nil {
   457  		return 0
   458  	}
   459  
   460  	sect.base = make([]byte, sect.sh.SizeOfRawData)
   461  	if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
   462  		return 0
   463  	}
   464  	if peobj.f.Seek(int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 {
   465  		return -1
   466  	}
   467  	if _, err := io.ReadFull(peobj.f, sect.base); err != nil {
   468  		return -1
   469  	}
   470  
   471  	return 0
   472  }
   473  
   474  func issect(s *PeSym) bool {
   475  	return s.sclass == IMAGE_SYM_CLASS_STATIC && s.type_ == 0 && s.name[0] == '.'
   476  }
   477  
   478  func readpesym(ctxt *Link, peobj *PeObj, i int, y **PeSym) (err error) {
   479  	if uint(i) >= peobj.npesym || i < 0 {
   480  		err = fmt.Errorf("invalid pe symbol index")
   481  		return err
   482  	}
   483  
   484  	sym := &peobj.pesym[i]
   485  	*y = sym
   486  
   487  	var name string
   488  	if issect(sym) {
   489  		name = peobj.sect[sym.sectnum-1].sym.Name
   490  	} else {
   491  		name = sym.name
   492  		if strings.HasPrefix(name, "__imp_") {
   493  			name = name[6:] // __imp_Name => Name
   494  		}
   495  		if SysArch.Family == sys.I386 && name[0] == '_' {
   496  			name = name[1:] // _Name => Name
   497  		}
   498  	}
   499  
   500  	// remove last @XXX
   501  	if i := strings.LastIndex(name, "@"); i >= 0 {
   502  		name = name[:i]
   503  	}
   504  
   505  	var s *Symbol
   506  	switch sym.type_ {
   507  	default:
   508  		err = fmt.Errorf("%s: invalid symbol type %d", sym.name, sym.type_)
   509  		return err
   510  
   511  	case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
   512  		switch sym.sclass {
   513  		case IMAGE_SYM_CLASS_EXTERNAL: //global
   514  			s = Linklookup(ctxt, name, 0)
   515  
   516  		case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
   517  			s = Linklookup(ctxt, name, ctxt.Version)
   518  			s.Attr |= AttrDuplicateOK
   519  
   520  		default:
   521  			err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
   522  			return err
   523  		}
   524  	}
   525  
   526  	if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
   527  		s.Type = obj.SXREF
   528  	}
   529  	if strings.HasPrefix(sym.name, "__imp_") {
   530  		s.Got = -2 // flag for __imp_
   531  	}
   532  	sym.sym = s
   533  
   534  	return nil
   535  }