]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/link/internal/loadpe/ldpe.go
[dev.link] cmd/link: remove old objs from host obj loaders
[gostls13.git] / src / cmd / link / internal / loadpe / ldpe.go
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 loadpe implements a PE/COFF file reader.
6 package loadpe
7
8 import (
9         "cmd/internal/bio"
10         "cmd/internal/objabi"
11         "cmd/internal/sys"
12         "cmd/link/internal/loader"
13         "cmd/link/internal/sym"
14         "debug/pe"
15         "encoding/binary"
16         "errors"
17         "fmt"
18         "io"
19         "sort"
20         "strings"
21 )
22
23 const (
24         // TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 (same with IMAGE_SYM_DTYPE_POINTER and IMAGE_SYM_DTYPE_FUNCTION)
25         IMAGE_SYM_UNDEFINED              = 0
26         IMAGE_SYM_ABSOLUTE               = -1
27         IMAGE_SYM_DEBUG                  = -2
28         IMAGE_SYM_TYPE_NULL              = 0
29         IMAGE_SYM_TYPE_VOID              = 1
30         IMAGE_SYM_TYPE_CHAR              = 2
31         IMAGE_SYM_TYPE_SHORT             = 3
32         IMAGE_SYM_TYPE_INT               = 4
33         IMAGE_SYM_TYPE_LONG              = 5
34         IMAGE_SYM_TYPE_FLOAT             = 6
35         IMAGE_SYM_TYPE_DOUBLE            = 7
36         IMAGE_SYM_TYPE_STRUCT            = 8
37         IMAGE_SYM_TYPE_UNION             = 9
38         IMAGE_SYM_TYPE_ENUM              = 10
39         IMAGE_SYM_TYPE_MOE               = 11
40         IMAGE_SYM_TYPE_BYTE              = 12
41         IMAGE_SYM_TYPE_WORD              = 13
42         IMAGE_SYM_TYPE_UINT              = 14
43         IMAGE_SYM_TYPE_DWORD             = 15
44         IMAGE_SYM_TYPE_PCODE             = 32768
45         IMAGE_SYM_DTYPE_NULL             = 0
46         IMAGE_SYM_DTYPE_POINTER          = 0x10
47         IMAGE_SYM_DTYPE_FUNCTION         = 0x20
48         IMAGE_SYM_DTYPE_ARRAY            = 0x30
49         IMAGE_SYM_CLASS_END_OF_FUNCTION  = -1
50         IMAGE_SYM_CLASS_NULL             = 0
51         IMAGE_SYM_CLASS_AUTOMATIC        = 1
52         IMAGE_SYM_CLASS_EXTERNAL         = 2
53         IMAGE_SYM_CLASS_STATIC           = 3
54         IMAGE_SYM_CLASS_REGISTER         = 4
55         IMAGE_SYM_CLASS_EXTERNAL_DEF     = 5
56         IMAGE_SYM_CLASS_LABEL            = 6
57         IMAGE_SYM_CLASS_UNDEFINED_LABEL  = 7
58         IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
59         IMAGE_SYM_CLASS_ARGUMENT         = 9
60         IMAGE_SYM_CLASS_STRUCT_TAG       = 10
61         IMAGE_SYM_CLASS_MEMBER_OF_UNION  = 11
62         IMAGE_SYM_CLASS_UNION_TAG        = 12
63         IMAGE_SYM_CLASS_TYPE_DEFINITION  = 13
64         IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
65         IMAGE_SYM_CLASS_ENUM_TAG         = 15
66         IMAGE_SYM_CLASS_MEMBER_OF_ENUM   = 16
67         IMAGE_SYM_CLASS_REGISTER_PARAM   = 17
68         IMAGE_SYM_CLASS_BIT_FIELD        = 18
69         IMAGE_SYM_CLASS_FAR_EXTERNAL     = 68 /* Not in PECOFF v8 spec */
70         IMAGE_SYM_CLASS_BLOCK            = 100
71         IMAGE_SYM_CLASS_FUNCTION         = 101
72         IMAGE_SYM_CLASS_END_OF_STRUCT    = 102
73         IMAGE_SYM_CLASS_FILE             = 103
74         IMAGE_SYM_CLASS_SECTION          = 104
75         IMAGE_SYM_CLASS_WEAK_EXTERNAL    = 105
76         IMAGE_SYM_CLASS_CLR_TOKEN        = 107
77         IMAGE_REL_I386_ABSOLUTE          = 0x0000
78         IMAGE_REL_I386_DIR16             = 0x0001
79         IMAGE_REL_I386_REL16             = 0x0002
80         IMAGE_REL_I386_DIR32             = 0x0006
81         IMAGE_REL_I386_DIR32NB           = 0x0007
82         IMAGE_REL_I386_SEG12             = 0x0009
83         IMAGE_REL_I386_SECTION           = 0x000A
84         IMAGE_REL_I386_SECREL            = 0x000B
85         IMAGE_REL_I386_TOKEN             = 0x000C
86         IMAGE_REL_I386_SECREL7           = 0x000D
87         IMAGE_REL_I386_REL32             = 0x0014
88         IMAGE_REL_AMD64_ABSOLUTE         = 0x0000
89         IMAGE_REL_AMD64_ADDR64           = 0x0001
90         IMAGE_REL_AMD64_ADDR32           = 0x0002
91         IMAGE_REL_AMD64_ADDR32NB         = 0x0003
92         IMAGE_REL_AMD64_REL32            = 0x0004
93         IMAGE_REL_AMD64_REL32_1          = 0x0005
94         IMAGE_REL_AMD64_REL32_2          = 0x0006
95         IMAGE_REL_AMD64_REL32_3          = 0x0007
96         IMAGE_REL_AMD64_REL32_4          = 0x0008
97         IMAGE_REL_AMD64_REL32_5          = 0x0009
98         IMAGE_REL_AMD64_SECTION          = 0x000A
99         IMAGE_REL_AMD64_SECREL           = 0x000B
100         IMAGE_REL_AMD64_SECREL7          = 0x000C
101         IMAGE_REL_AMD64_TOKEN            = 0x000D
102         IMAGE_REL_AMD64_SREL32           = 0x000E
103         IMAGE_REL_AMD64_PAIR             = 0x000F
104         IMAGE_REL_AMD64_SSPAN32          = 0x0010
105         IMAGE_REL_ARM_ABSOLUTE           = 0x0000
106         IMAGE_REL_ARM_ADDR32             = 0x0001
107         IMAGE_REL_ARM_ADDR32NB           = 0x0002
108         IMAGE_REL_ARM_BRANCH24           = 0x0003
109         IMAGE_REL_ARM_BRANCH11           = 0x0004
110         IMAGE_REL_ARM_SECTION            = 0x000E
111         IMAGE_REL_ARM_SECREL             = 0x000F
112         IMAGE_REL_ARM_MOV32              = 0x0010
113         IMAGE_REL_THUMB_MOV32            = 0x0011
114         IMAGE_REL_THUMB_BRANCH20         = 0x0012
115         IMAGE_REL_THUMB_BRANCH24         = 0x0014
116         IMAGE_REL_THUMB_BLX23            = 0x0015
117         IMAGE_REL_ARM_PAIR               = 0x0016
118 )
119
120 // TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe.
121 const (
122         IMAGE_SCN_CNT_CODE               = 0x00000020
123         IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
124         IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
125         IMAGE_SCN_MEM_DISCARDABLE        = 0x02000000
126         IMAGE_SCN_MEM_EXECUTE            = 0x20000000
127         IMAGE_SCN_MEM_READ               = 0x40000000
128         IMAGE_SCN_MEM_WRITE              = 0x80000000
129 )
130
131 // TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf
132
133 // peBiobuf makes bio.Reader look like io.ReaderAt.
134 type peBiobuf bio.Reader
135
136 func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
137         ret := ((*bio.Reader)(f)).MustSeek(off, 0)
138         if ret < 0 {
139                 return 0, errors.New("fail to seek")
140         }
141         n, err := f.Read(p)
142         if err != nil {
143                 return 0, err
144         }
145         return n, nil
146 }
147
148 // Load loads the PE file pn from input.
149 // Symbols are written into syms, and a slice of the text symbols is returned.
150 // If an .rsrc section is found, its symbol is returned as rsrc.
151 func Load(l *loader.Loader, arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, length int64, pn string) (textp []*sym.Symbol, rsrc *sym.Symbol, err error) {
152         lookup := func(name string, version int) *sym.Symbol {
153                 return l.LookupOrCreate(name, version, syms)
154         }
155         localSymVersion := syms.IncVersion()
156         sectsyms := make(map[*pe.Section]*sym.Symbol)
157         sectdata := make(map[*pe.Section][]byte)
158
159         // Some input files are archives containing multiple of
160         // object files, and pe.NewFile seeks to the start of
161         // input file and get confused. Create section reader
162         // to stop pe.NewFile looking before current position.
163         sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1)
164
165         // TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
166         f, err := pe.NewFile(sr)
167         if err != nil {
168                 return nil, nil, err
169         }
170         defer f.Close()
171
172         // TODO return error if found .cormeta
173
174         // create symbols for mapped sections
175         for _, sect := range f.Sections {
176                 if sect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
177                         continue
178                 }
179
180                 if sect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
181                         // This has been seen for .idata sections, which we
182                         // want to ignore. See issues 5106 and 5273.
183                         continue
184                 }
185
186                 name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
187                 s := lookup(name, localSymVersion)
188
189                 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) {
190                 case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
191                         s.Type = sym.SRODATA
192
193                 case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
194                         s.Type = sym.SNOPTRBSS
195
196                 case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
197                         s.Type = sym.SNOPTRDATA
198
199                 case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
200                         s.Type = sym.STEXT
201
202                 default:
203                         return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
204                 }
205
206                 if s.Type != sym.SNOPTRBSS {
207                         data, err := sect.Data()
208                         if err != nil {
209                                 return nil, nil, err
210                         }
211                         sectdata[sect] = data
212                         s.P = data
213                 }
214                 s.Size = int64(sect.Size)
215                 sectsyms[sect] = s
216                 if sect.Name == ".rsrc" {
217                         rsrc = s
218                 }
219         }
220
221         // load relocations
222         for _, rsect := range f.Sections {
223                 if _, found := sectsyms[rsect]; !found {
224                         continue
225                 }
226                 if rsect.NumberOfRelocations == 0 {
227                         continue
228                 }
229                 if rsect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
230                         continue
231                 }
232                 if rsect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
233                         // This has been seen for .idata sections, which we
234                         // want to ignore. See issues 5106 and 5273.
235                         continue
236                 }
237
238                 rs := make([]sym.Reloc, rsect.NumberOfRelocations)
239                 for j, r := range rsect.Relocs {
240                         rp := &rs[j]
241                         if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
242                                 return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
243                         }
244                         pesym := &f.COFFSymbols[r.SymbolTableIndex]
245                         gosym, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
246                         if err != nil {
247                                 return nil, nil, err
248                         }
249                         if gosym == nil {
250                                 name, err := pesym.FullName(f.StringTable)
251                                 if err != nil {
252                                         name = string(pesym.Name[:])
253                                 }
254                                 return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
255                         }
256
257                         rp.Sym = gosym
258                         rp.Siz = 4
259                         rp.Off = int32(r.VirtualAddress)
260                         switch arch.Family {
261                         default:
262                                 return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
263                         case sys.I386, sys.AMD64:
264                                 switch r.Type {
265                                 default:
266                                         return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
267
268                                 case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
269                                         IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
270                                         IMAGE_REL_AMD64_ADDR32NB:
271                                         rp.Type = objabi.R_PCREL
272
273                                         rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
274
275                                 case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
276                                         rp.Type = objabi.R_ADDR
277
278                                         // load addend from image
279                                         rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
280
281                                 case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
282                                         rp.Siz = 8
283
284                                         rp.Type = objabi.R_ADDR
285
286                                         // load addend from image
287                                         rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:]))
288                                 }
289
290                         case sys.ARM:
291                                 switch r.Type {
292                                 default:
293                                         return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
294
295                                 case IMAGE_REL_ARM_SECREL:
296                                         rp.Type = objabi.R_PCREL
297
298                                         rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
299
300                                 case IMAGE_REL_ARM_ADDR32:
301                                         rp.Type = objabi.R_ADDR
302
303                                         rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
304
305                                 case IMAGE_REL_ARM_BRANCH24:
306                                         rp.Type = objabi.R_CALLARM
307
308                                         rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
309                                 }
310                         }
311
312                         // ld -r could generate multiple section symbols for the
313                         // same section but with different values, we have to take
314                         // that into account
315                         if issect(pesym) {
316                                 rp.Add += int64(pesym.Value)
317                         }
318                 }
319
320                 sort.Sort(sym.RelocByOff(rs[:rsect.NumberOfRelocations]))
321
322                 s := sectsyms[rsect]
323                 s.R = rs
324                 s.R = s.R[:rsect.NumberOfRelocations]
325         }
326
327         // enter sub-symbols into symbol table.
328         for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 {
329                 pesym := &f.COFFSymbols[i]
330
331                 numaux = int(pesym.NumberOfAuxSymbols)
332
333                 name, err := pesym.FullName(f.StringTable)
334                 if err != nil {
335                         return nil, nil, err
336                 }
337                 if name == "" {
338                         continue
339                 }
340                 if issect(pesym) {
341                         continue
342                 }
343                 if int(pesym.SectionNumber) > len(f.Sections) {
344                         continue
345                 }
346                 if pesym.SectionNumber == IMAGE_SYM_DEBUG {
347                         continue
348                 }
349                 var sect *pe.Section
350                 if pesym.SectionNumber > 0 {
351                         sect = f.Sections[pesym.SectionNumber-1]
352                         if _, found := sectsyms[sect]; !found {
353                                 continue
354                         }
355                 }
356
357                 s, err := readpesym(arch, lookup, f, pesym, sectsyms, localSymVersion)
358                 if err != nil {
359                         return nil, nil, err
360                 }
361
362                 if pesym.SectionNumber == 0 { // extern
363                         if s.Type == sym.SDYNIMPORT {
364                                 s.SetPlt(-2) // flag for dynimport in PE object files.
365                         }
366                         if s.Type == sym.SXREF && pesym.Value > 0 { // global data
367                                 s.Type = sym.SNOPTRDATA
368                                 s.Size = int64(pesym.Value)
369                         }
370
371                         continue
372                 } else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
373                         sect = f.Sections[pesym.SectionNumber-1]
374                         if _, found := sectsyms[sect]; !found {
375                                 return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
376                         }
377                 } else {
378                         return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
379                 }
380
381                 if sect == nil {
382                         return nil, rsrc, nil
383                 }
384
385                 if s.Outer != nil {
386                         if s.Attr.DuplicateOK() {
387                                 continue
388                         }
389                         return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name)
390                 }
391
392                 sectsym := sectsyms[sect]
393                 s.Sub = sectsym.Sub
394                 sectsym.Sub = s
395                 s.Type = sectsym.Type
396                 s.Attr |= sym.AttrSubSymbol
397                 s.Value = int64(pesym.Value)
398                 s.Size = 4
399                 s.Outer = sectsym
400                 if sectsym.Type == sym.STEXT {
401                         if s.Attr.External() && !s.Attr.DuplicateOK() {
402                                 return nil, nil, fmt.Errorf("%s: duplicate symbol definition", s.Name)
403                         }
404                         s.Attr |= sym.AttrExternal
405                 }
406         }
407
408         // Sort outer lists by address, adding to textp.
409         // This keeps textp in increasing address order.
410         for _, sect := range f.Sections {
411                 s := sectsyms[sect]
412                 if s == nil {
413                         continue
414                 }
415                 if s.Sub != nil {
416                         s.Sub = sym.SortSub(s.Sub)
417                 }
418                 if s.Type == sym.STEXT {
419                         if s.Attr.OnList() {
420                                 return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
421                         }
422                         s.Attr |= sym.AttrOnList
423                         textp = append(textp, s)
424                         for s = s.Sub; s != nil; s = s.Sub {
425                                 if s.Attr.OnList() {
426                                         return nil, nil, fmt.Errorf("symbol %s listed multiple times", s.Name)
427                                 }
428                                 s.Attr |= sym.AttrOnList
429                                 textp = append(textp, s)
430                         }
431                 }
432         }
433
434         return textp, rsrc, nil
435 }
436
437 func issect(s *pe.COFFSymbol) bool {
438         return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
439 }
440
441 func readpesym(arch *sys.Arch, lookup func(string, int) *sym.Symbol, f *pe.File, pesym *pe.COFFSymbol, sectsyms map[*pe.Section]*sym.Symbol, localSymVersion int) (*sym.Symbol, error) {
442         symname, err := pesym.FullName(f.StringTable)
443         if err != nil {
444                 return nil, err
445         }
446         var name string
447         if issect(pesym) {
448                 name = sectsyms[f.Sections[pesym.SectionNumber-1]].Name
449         } else {
450                 name = symname
451                 switch arch.Family {
452                 case sys.AMD64:
453                         if name == "__imp___acrt_iob_func" {
454                                 // Do not rename __imp___acrt_iob_func into __acrt_iob_func,
455                                 // becasue __imp___acrt_iob_func symbol is real
456                                 // (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for detials).
457                         } else {
458                                 name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name
459                         }
460                 case sys.I386:
461                         if name == "__imp____acrt_iob_func" {
462                                 // Do not rename __imp____acrt_iob_func into ___acrt_iob_func,
463                                 // becasue __imp____acrt_iob_func symbol is real
464                                 // (see commit b295099 from git://git.code.sf.net/p/mingw-w64/mingw-w64 for detials).
465                         } else {
466                                 name = strings.TrimPrefix(name, "__imp_") // __imp_Name => Name
467                         }
468                         if name[0] == '_' {
469                                 name = name[1:] // _Name => Name
470                         }
471                 }
472         }
473
474         // remove last @XXX
475         if i := strings.LastIndex(name, "@"); i >= 0 {
476                 name = name[:i]
477         }
478
479         var s *sym.Symbol
480         switch pesym.Type {
481         default:
482                 return nil, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type)
483
484         case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
485                 switch pesym.StorageClass {
486                 case IMAGE_SYM_CLASS_EXTERNAL: //global
487                         s = lookup(name, 0)
488
489                 case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
490                         s = lookup(name, localSymVersion)
491                         s.Attr |= sym.AttrDuplicateOK
492
493                 default:
494                         return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass)
495                 }
496         }
497
498         if s != nil && s.Type == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) {
499                 s.Type = sym.SXREF
500         }
501         if strings.HasPrefix(symname, "__imp_") {
502                 s.SetGot(-2) // flag for __imp_
503         }
504
505         return s, nil
506 }