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