Home | History | Annotate | Download | only in ld
      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      *obj.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 *obj.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(obj.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 	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
    175 
    176 	if obj.Bread(f, symbuf[:4]) != 4 {
    177 		goto bad
    178 	}
    179 	l = Le32(symbuf[:])
    180 	peobj.snames = make([]byte, l)
    181 	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
    182 	if obj.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 	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
    203 	for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
    204 		obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
    205 		if obj.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 = obj.SRODATA
    250 
    251 		case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
    252 			s.Type = obj.SNOPTRBSS
    253 
    254 		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
    255 			s.Type = obj.SNOPTRDATA
    256 
    257 		case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
    258 			s.Type = obj.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 		obj.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 obj.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 = obj.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 = obj.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 = obj.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 == obj.SDYNIMPORT {
    377 				s.Plt = -2 // flag for dynimport in PE object files.
    378 			}
    379 			if s.Type == obj.SXREF && sym.value > 0 { // global data
    380 				s.Type = obj.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 			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
    403 		}
    404 
    405 		s.Sub = sect.sym.Sub
    406 		sect.sym.Sub = s
    407 		s.Type = sect.sym.Type | obj.SSUB
    408 		s.Value = int64(sym.value)
    409 		s.Size = 4
    410 		s.Outer = sect.sym
    411 		if sect.sym.Type == obj.STEXT {
    412 			if s.External != 0 && s.Dupok == 0 {
    413 				Diag("%s: duplicate definition of %s", pn, s.Name)
    414 			}
    415 			s.External = 1
    416 		}
    417 	}
    418 
    419 	// Sort outer lists by address, adding to textp.
    420 	// This keeps textp in increasing address order.
    421 	for i := 0; uint(i) < peobj.nsect; i++ {
    422 		s = peobj.sect[i].sym
    423 		if s == nil {
    424 			continue
    425 		}
    426 		if s.Sub != nil {
    427 			s.Sub = listsort(s.Sub, valuecmp, listsubp)
    428 		}
    429 		if s.Type == obj.STEXT {
    430 			if s.Onlist != 0 {
    431 				log.Fatalf("symbol %s listed multiple times", s.Name)
    432 			}
    433 			s.Onlist = 1
    434 			if Ctxt.Etextp != nil {
    435 				Ctxt.Etextp.Next = s
    436 			} else {
    437 				Ctxt.Textp = s
    438 			}
    439 			Ctxt.Etextp = s
    440 			for s = s.Sub; s != nil; s = s.Sub {
    441 				if s.Onlist != 0 {
    442 					log.Fatalf("symbol %s listed multiple times", s.Name)
    443 				}
    444 				s.Onlist = 1
    445 				Ctxt.Etextp.Next = s
    446 				Ctxt.Etextp = s
    447 			}
    448 		}
    449 	}
    450 
    451 	return
    452 
    453 bad:
    454 	Diag("%s: malformed pe file: %v", pn, err)
    455 }
    456 
    457 func pemap(peobj *PeObj, sect *PeSect) int {
    458 	if sect.base != nil {
    459 		return 0
    460 	}
    461 
    462 	sect.base = make([]byte, sect.sh.SizeOfRawData)
    463 	if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
    464 		return 0
    465 	}
    466 	if obj.Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || obj.Bread(peobj.f, sect.base) != len(sect.base) {
    467 		return -1
    468 	}
    469 
    470 	return 0
    471 }
    472 
    473 func issect(s *PeSym) bool {
    474 	return s.sclass == IMAGE_SYM_CLASS_STATIC && s.type_ == 0 && s.name[0] == '.'
    475 }
    476 
    477 func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
    478 	if uint(i) >= peobj.npesym || i < 0 {
    479 		err = fmt.Errorf("invalid pe symbol index")
    480 		return err
    481 	}
    482 
    483 	sym := &peobj.pesym[i]
    484 	*y = sym
    485 
    486 	var name string
    487 	if issect(sym) {
    488 		name = peobj.sect[sym.sectnum-1].sym.Name
    489 	} else {
    490 		name = sym.name
    491 		if strings.HasPrefix(name, "__imp_") {
    492 			name = name[6:] // __imp_Name => Name
    493 		}
    494 		if Thearch.Thechar == '8' && name[0] == '_' {
    495 			name = name[1:] // _Name => Name
    496 		}
    497 	}
    498 
    499 	// remove last @XXX
    500 	if i := strings.LastIndex(name, "@"); i >= 0 {
    501 		name = name[:i]
    502 	}
    503 
    504 	var s *LSym
    505 	switch sym.type_ {
    506 	default:
    507 		err = fmt.Errorf("%s: invalid symbol type %d", sym.name, sym.type_)
    508 		return err
    509 
    510 	case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
    511 		switch sym.sclass {
    512 		case IMAGE_SYM_CLASS_EXTERNAL: //global
    513 			s = Linklookup(Ctxt, name, 0)
    514 
    515 		case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
    516 			s = Linklookup(Ctxt, name, Ctxt.Version)
    517 			s.Dupok = 1
    518 
    519 		default:
    520 			err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
    521 			return err
    522 		}
    523 	}
    524 
    525 	if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
    526 		s.Type = obj.SXREF
    527 	}
    528 	if strings.HasPrefix(sym.name, "__imp_") {
    529 		s.Got = -2 // flag for __imp_
    530 	}
    531 	sym.sym = s
    532 
    533 	return nil
    534 }
    535