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/bio"
      9 	"cmd/internal/obj"
     10 	"cmd/internal/sys"
     11 	"debug/pe"
     12 	"errors"
     13 	"fmt"
     14 	"io"
     15 	"log"
     16 	"sort"
     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 // TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf
    104 
    105 // peBiobuf makes bio.Reader look like io.ReaderAt.
    106 type peBiobuf bio.Reader
    107 
    108 func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
    109 	ret := ((*bio.Reader)(f)).Seek(off, 0)
    110 	if ret < 0 {
    111 		return 0, errors.New("fail to seek")
    112 	}
    113 	n, err := f.Read(p)
    114 	if err != nil {
    115 		return 0, err
    116 	}
    117 	return n, nil
    118 }
    119 
    120 func ldpe(ctxt *Link, input *bio.Reader, pkg string, length int64, pn string) {
    121 	err := ldpeError(ctxt, input, pkg, length, pn)
    122 	if err != nil {
    123 		Errorf(nil, "%s: malformed pe file: %v", pn, err)
    124 	}
    125 }
    126 
    127 func ldpeError(ctxt *Link, input *bio.Reader, pkg string, length int64, pn string) error {
    128 	if ctxt.Debugvlog != 0 {
    129 		ctxt.Logf("%5.2f ldpe %s\n", obj.Cputime(), pn)
    130 	}
    131 
    132 	localSymVersion := ctxt.Syms.IncVersion()
    133 
    134 	sectsyms := make(map[*pe.Section]*Symbol)
    135 	sectdata := make(map[*pe.Section][]byte)
    136 
    137 	// Some input files are archives containing multiple of
    138 	// object files, and pe.NewFile seeks to the start of
    139 	// input file and get confused. Create section reader
    140 	// to stop pe.NewFile looking before current position.
    141 	sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1)
    142 
    143 	// TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
    144 	f, err := pe.NewFile(sr)
    145 	if err != nil {
    146 		return err
    147 	}
    148 	defer f.Close()
    149 
    150 	// TODO return error if found .cormeta
    151 
    152 	// create symbols for mapped sections
    153 	for _, sect := range f.Sections {
    154 		if sect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
    155 			continue
    156 		}
    157 
    158 		if sect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
    159 			// This has been seen for .idata sections, which we
    160 			// want to ignore. See issues 5106 and 5273.
    161 			continue
    162 		}
    163 
    164 		data, err := sect.Data()
    165 		if err != nil {
    166 			return err
    167 		}
    168 		sectdata[sect] = data
    169 
    170 		name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
    171 		s := ctxt.Syms.Lookup(name, localSymVersion)
    172 
    173 		switch sect.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) {
    174 		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
    175 			s.Type = obj.SRODATA
    176 
    177 		case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
    178 			s.Type = obj.SNOPTRBSS
    179 
    180 		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
    181 			s.Type = obj.SNOPTRDATA
    182 
    183 		case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
    184 			s.Type = obj.STEXT
    185 
    186 		default:
    187 			return fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
    188 		}
    189 
    190 		s.P = data
    191 		s.Size = int64(len(data))
    192 		sectsyms[sect] = s
    193 		if sect.Name == ".rsrc" {
    194 			setpersrc(ctxt, s)
    195 		}
    196 	}
    197 
    198 	// load relocations
    199 	for _, rsect := range f.Sections {
    200 		if _, found := sectsyms[rsect]; !found {
    201 			continue
    202 		}
    203 		if rsect.NumberOfRelocations == 0 {
    204 			continue
    205 		}
    206 		if rsect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
    207 			continue
    208 		}
    209 		if rsect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
    210 			// This has been seen for .idata sections, which we
    211 			// want to ignore. See issues 5106 and 5273.
    212 			continue
    213 		}
    214 
    215 		rs := make([]Reloc, rsect.NumberOfRelocations)
    216 		for j, r := range rsect.Relocs {
    217 			rp := &rs[j]
    218 			if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
    219 				return fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
    220 			}
    221 			pesym := &f.COFFSymbols[r.SymbolTableIndex]
    222 			gosym, err := readpesym(ctxt, f, pesym, sectsyms, localSymVersion)
    223 			if err != nil {
    224 				return err
    225 			}
    226 			if gosym == nil {
    227 				name, err := pesym.FullName(f.StringTable)
    228 				if err != nil {
    229 					name = string(pesym.Name[:])
    230 				}
    231 				return fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
    232 			}
    233 
    234 			rp.Sym = gosym
    235 			rp.Siz = 4
    236 			rp.Off = int32(r.VirtualAddress)
    237 			switch r.Type {
    238 			default:
    239 				Errorf(sectsyms[rsect], "%s: unknown relocation type %d;", pn, r.Type)
    240 				fallthrough
    241 
    242 			case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
    243 				IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
    244 				IMAGE_REL_AMD64_ADDR32NB:
    245 				rp.Type = obj.R_PCREL
    246 
    247 				rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:])))
    248 
    249 			case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
    250 				rp.Type = obj.R_ADDR
    251 
    252 				// load addend from image
    253 				rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:])))
    254 
    255 			case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
    256 				rp.Siz = 8
    257 
    258 				rp.Type = obj.R_ADDR
    259 
    260 				// load addend from image
    261 				rp.Add = int64(Le64(sectdata[rsect][rp.Off:]))
    262 			}
    263 
    264 			// ld -r could generate multiple section symbols for the
    265 			// same section but with different values, we have to take
    266 			// that into account
    267 			if issect(pesym) {
    268 				rp.Add += int64(pesym.Value)
    269 			}
    270 		}
    271 
    272 		sort.Sort(rbyoff(rs[:rsect.NumberOfRelocations]))
    273 
    274 		s := sectsyms[rsect]
    275 		s.R = rs
    276 		s.R = s.R[:rsect.NumberOfRelocations]
    277 	}
    278 
    279 	// enter sub-symbols into symbol table.
    280 	for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 {
    281 		pesym := &f.COFFSymbols[i]
    282 
    283 		numaux = int(pesym.NumberOfAuxSymbols)
    284 
    285 		name, err := pesym.FullName(f.StringTable)
    286 		if err != nil {
    287 			return err
    288 		}
    289 		if name == "" {
    290 			continue
    291 		}
    292 		if issect(pesym) {
    293 			continue
    294 		}
    295 		if int(pesym.SectionNumber) > len(f.Sections) {
    296 			continue
    297 		}
    298 		if pesym.SectionNumber == IMAGE_SYM_DEBUG {
    299 			continue
    300 		}
    301 		var sect *pe.Section
    302 		if pesym.SectionNumber > 0 {
    303 			sect = f.Sections[pesym.SectionNumber-1]
    304 			if _, found := sectsyms[sect]; !found {
    305 				continue
    306 			}
    307 		}
    308 
    309 		s, err := readpesym(ctxt, f, pesym, sectsyms, localSymVersion)
    310 		if err != nil {
    311 			return err
    312 		}
    313 
    314 		if pesym.SectionNumber == 0 { // extern
    315 			if s.Type == obj.SDYNIMPORT {
    316 				s.Plt = -2 // flag for dynimport in PE object files.
    317 			}
    318 			if s.Type == obj.SXREF && pesym.Value > 0 { // global data
    319 				s.Type = obj.SNOPTRDATA
    320 				s.Size = int64(pesym.Value)
    321 			}
    322 
    323 			continue
    324 		} else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
    325 			sect = f.Sections[pesym.SectionNumber-1]
    326 			if _, found := sectsyms[sect]; !found {
    327 				Errorf(s, "%s: missing sect.sym", pn)
    328 			}
    329 		} else {
    330 			Errorf(s, "%s: sectnum < 0!", pn)
    331 		}
    332 
    333 		if sect == nil {
    334 			return nil
    335 		}
    336 
    337 		if s.Outer != nil {
    338 			if s.Attr.DuplicateOK() {
    339 				continue
    340 			}
    341 			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name)
    342 		}
    343 
    344 		sectsym := sectsyms[sect]
    345 		s.Sub = sectsym.Sub
    346 		sectsym.Sub = s
    347 		s.Type = sectsym.Type | obj.SSUB
    348 		s.Value = int64(pesym.Value)
    349 		s.Size = 4
    350 		s.Outer = sectsym
    351 		if sectsym.Type == obj.STEXT {
    352 			if s.Attr.External() && !s.Attr.DuplicateOK() {
    353 				Errorf(s, "%s: duplicate symbol definition", pn)
    354 			}
    355 			s.Attr |= AttrExternal
    356 		}
    357 	}
    358 
    359 	// Sort outer lists by address, adding to textp.
    360 	// This keeps textp in increasing address order.
    361 	for _, sect := range f.Sections {
    362 		s := sectsyms[sect]
    363 		if s == nil {
    364 			continue
    365 		}
    366 		if s.Sub != nil {
    367 			s.Sub = listsort(s.Sub)
    368 		}
    369 		if s.Type == obj.STEXT {
    370 			if s.Attr.OnList() {
    371 				log.Fatalf("symbol %s listed multiple times", s.Name)
    372 			}
    373 			s.Attr |= AttrOnList
    374 			ctxt.Textp = append(ctxt.Textp, s)
    375 			for s = s.Sub; s != nil; s = s.Sub {
    376 				if s.Attr.OnList() {
    377 					log.Fatalf("symbol %s listed multiple times", s.Name)
    378 				}
    379 				s.Attr |= AttrOnList
    380 				ctxt.Textp = append(ctxt.Textp, s)
    381 			}
    382 		}
    383 	}
    384 
    385 	return nil
    386 }
    387 
    388 func issect(s *pe.COFFSymbol) bool {
    389 	return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
    390 }
    391 
    392 func readpesym(ctxt *Link, f *pe.File, sym *pe.COFFSymbol, sectsyms map[*pe.Section]*Symbol, localSymVersion int) (*Symbol, error) {
    393 	symname, err := sym.FullName(f.StringTable)
    394 	if err != nil {
    395 		return nil, err
    396 	}
    397 	var name string
    398 	if issect(sym) {
    399 		name = sectsyms[f.Sections[sym.SectionNumber-1]].Name
    400 	} else {
    401 		name = symname
    402 		if strings.HasPrefix(name, "__imp_") {
    403 			name = name[6:] // __imp_Name => Name
    404 		}
    405 		if SysArch.Family == sys.I386 && name[0] == '_' {
    406 			name = name[1:] // _Name => Name
    407 		}
    408 	}
    409 
    410 	// remove last @XXX
    411 	if i := strings.LastIndex(name, "@"); i >= 0 {
    412 		name = name[:i]
    413 	}
    414 
    415 	var s *Symbol
    416 	switch sym.Type {
    417 	default:
    418 		return nil, fmt.Errorf("%s: invalid symbol type %d", symname, sym.Type)
    419 
    420 	case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
    421 		switch sym.StorageClass {
    422 		case IMAGE_SYM_CLASS_EXTERNAL: //global
    423 			s = ctxt.Syms.Lookup(name, 0)
    424 
    425 		case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
    426 			s = ctxt.Syms.Lookup(name, localSymVersion)
    427 			s.Attr |= AttrDuplicateOK
    428 
    429 		default:
    430 			return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, sym.StorageClass)
    431 		}
    432 	}
    433 
    434 	if s != nil && s.Type == 0 && (sym.StorageClass != IMAGE_SYM_CLASS_STATIC || sym.Value != 0) {
    435 		s.Type = obj.SXREF
    436 	}
    437 	if strings.HasPrefix(symname, "__imp_") {
    438 		s.Got = -2 // flag for __imp_
    439 	}
    440 
    441 	return s, nil
    442 }
    443