github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/ld/ldpe.go (about)

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