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