github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/link/internal/ld/pe.go (about) 1 // Copyright 2009 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/objabi" 9 "cmd/internal/sys" 10 "cmd/link/internal/sym" 11 "debug/pe" 12 "encoding/binary" 13 "fmt" 14 "sort" 15 "strconv" 16 "strings" 17 ) 18 19 type IMAGE_IMPORT_DESCRIPTOR struct { 20 OriginalFirstThunk uint32 21 TimeDateStamp uint32 22 ForwarderChain uint32 23 Name uint32 24 FirstThunk uint32 25 } 26 27 type IMAGE_EXPORT_DIRECTORY struct { 28 Characteristics uint32 29 TimeDateStamp uint32 30 MajorVersion uint16 31 MinorVersion uint16 32 Name uint32 33 Base uint32 34 NumberOfFunctions uint32 35 NumberOfNames uint32 36 AddressOfFunctions uint32 37 AddressOfNames uint32 38 AddressOfNameOrdinals uint32 39 } 40 41 const ( 42 PEBASE = 0x00400000 43 ) 44 45 var ( 46 // SectionAlignment must be greater than or equal to FileAlignment. 47 // The default is the page size for the architecture. 48 PESECTALIGN int64 = 0x1000 49 50 // FileAlignment should be a power of 2 between 512 and 64 K, inclusive. 51 // The default is 512. If the SectionAlignment is less than 52 // the architecture's page size, then FileAlignment must match SectionAlignment. 53 PEFILEALIGN int64 = 2 << 8 54 ) 55 56 const ( 57 IMAGE_FILE_MACHINE_I386 = 0x14c 58 IMAGE_FILE_MACHINE_AMD64 = 0x8664 59 IMAGE_FILE_MACHINE_ARM = 0x1c0 60 IMAGE_FILE_MACHINE_ARMNT = 0x1c4 61 IMAGE_FILE_RELOCS_STRIPPED = 0x0001 62 IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 63 IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 64 IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 65 IMAGE_FILE_32BIT_MACHINE = 0x0100 66 IMAGE_FILE_DEBUG_STRIPPED = 0x0200 67 IMAGE_SCN_CNT_CODE = 0x00000020 68 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 69 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 70 IMAGE_SCN_MEM_EXECUTE = 0x20000000 71 IMAGE_SCN_MEM_READ = 0x40000000 72 IMAGE_SCN_MEM_WRITE = 0x80000000 73 IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 74 IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 75 IMAGE_SCN_ALIGN_32BYTES = 0x600000 76 IMAGE_DIRECTORY_ENTRY_EXPORT = 0 77 IMAGE_DIRECTORY_ENTRY_IMPORT = 1 78 IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 79 IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 80 IMAGE_DIRECTORY_ENTRY_SECURITY = 4 81 IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 82 IMAGE_DIRECTORY_ENTRY_DEBUG = 6 83 IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7 84 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 85 IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 86 IMAGE_DIRECTORY_ENTRY_TLS = 9 87 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 88 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 89 IMAGE_DIRECTORY_ENTRY_IAT = 12 90 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 91 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 92 IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 93 IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 94 IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 95 IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100 96 ) 97 98 // TODO(crawshaw): add these constants to debug/pe. 99 const ( 100 // TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 and IMAGE_SYM_DTYPE_FUNCTION is 2 101 IMAGE_SYM_TYPE_NULL = 0 102 IMAGE_SYM_TYPE_STRUCT = 8 103 IMAGE_SYM_DTYPE_FUNCTION = 0x20 104 IMAGE_SYM_DTYPE_ARRAY = 0x30 105 IMAGE_SYM_CLASS_EXTERNAL = 2 106 IMAGE_SYM_CLASS_STATIC = 3 107 108 IMAGE_REL_I386_DIR32 = 0x0006 109 IMAGE_REL_I386_SECREL = 0x000B 110 IMAGE_REL_I386_REL32 = 0x0014 111 112 IMAGE_REL_AMD64_ADDR64 = 0x0001 113 IMAGE_REL_AMD64_ADDR32 = 0x0002 114 IMAGE_REL_AMD64_REL32 = 0x0004 115 IMAGE_REL_AMD64_SECREL = 0x000B 116 117 IMAGE_REL_ARM_ABSOLUTE = 0x0000 118 IMAGE_REL_ARM_ADDR32 = 0x0001 119 IMAGE_REL_ARM_ADDR32NB = 0x0002 120 IMAGE_REL_ARM_BRANCH24 = 0x0003 121 IMAGE_REL_ARM_BRANCH11 = 0x0004 122 IMAGE_REL_ARM_SECREL = 0x000F 123 124 IMAGE_REL_BASED_HIGHLOW = 3 125 ) 126 127 // Copyright 2009 The Go Authors. All rights reserved. 128 // Use of this source code is governed by a BSD-style 129 // license that can be found in the LICENSE file. 130 131 // PE (Portable Executable) file writing 132 // https://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx 133 134 // DOS stub that prints out 135 // "This program cannot be run in DOS mode." 136 var dosstub = []uint8{ 137 0x4d, 138 0x5a, 139 0x90, 140 0x00, 141 0x03, 142 0x00, 143 0x04, 144 0x00, 145 0x00, 146 0x00, 147 0x00, 148 0x00, 149 0xff, 150 0xff, 151 0x00, 152 0x00, 153 0x8b, 154 0x00, 155 0x00, 156 0x00, 157 0x00, 158 0x00, 159 0x00, 160 0x00, 161 0x40, 162 0x00, 163 0x00, 164 0x00, 165 0x00, 166 0x00, 167 0x00, 168 0x00, 169 0x00, 170 0x00, 171 0x00, 172 0x00, 173 0x00, 174 0x00, 175 0x00, 176 0x00, 177 0x00, 178 0x00, 179 0x00, 180 0x00, 181 0x00, 182 0x00, 183 0x00, 184 0x00, 185 0x00, 186 0x00, 187 0x00, 188 0x00, 189 0x00, 190 0x00, 191 0x00, 192 0x00, 193 0x00, 194 0x00, 195 0x00, 196 0x00, 197 0x80, 198 0x00, 199 0x00, 200 0x00, 201 0x0e, 202 0x1f, 203 0xba, 204 0x0e, 205 0x00, 206 0xb4, 207 0x09, 208 0xcd, 209 0x21, 210 0xb8, 211 0x01, 212 0x4c, 213 0xcd, 214 0x21, 215 0x54, 216 0x68, 217 0x69, 218 0x73, 219 0x20, 220 0x70, 221 0x72, 222 0x6f, 223 0x67, 224 0x72, 225 0x61, 226 0x6d, 227 0x20, 228 0x63, 229 0x61, 230 0x6e, 231 0x6e, 232 0x6f, 233 0x74, 234 0x20, 235 0x62, 236 0x65, 237 0x20, 238 0x72, 239 0x75, 240 0x6e, 241 0x20, 242 0x69, 243 0x6e, 244 0x20, 245 0x44, 246 0x4f, 247 0x53, 248 0x20, 249 0x6d, 250 0x6f, 251 0x64, 252 0x65, 253 0x2e, 254 0x0d, 255 0x0d, 256 0x0a, 257 0x24, 258 0x00, 259 0x00, 260 0x00, 261 0x00, 262 0x00, 263 0x00, 264 0x00, 265 } 266 267 type Imp struct { 268 s *sym.Symbol 269 off uint64 270 next *Imp 271 argsize int 272 } 273 274 type Dll struct { 275 name string 276 nameoff uint64 277 thunkoff uint64 278 ms *Imp 279 next *Dll 280 } 281 282 var ( 283 rsrcsym *sym.Symbol 284 PESECTHEADR int32 285 PEFILEHEADR int32 286 pe64 int 287 dr *Dll 288 dexport [1024]*sym.Symbol 289 nexport int 290 ) 291 292 // peStringTable is a COFF string table. 293 type peStringTable struct { 294 strings []string 295 stringsLen int 296 } 297 298 // size resturns size of string table t. 299 func (t *peStringTable) size() int { 300 // string table starts with 4-byte length at the beginning 301 return t.stringsLen + 4 302 } 303 304 // add adds string str to string table t. 305 func (t *peStringTable) add(str string) int { 306 off := t.size() 307 t.strings = append(t.strings, str) 308 t.stringsLen += len(str) + 1 // each string will have 0 appended to it 309 return off 310 } 311 312 // write writes string table t into the output file. 313 func (t *peStringTable) write(out *OutBuf) { 314 out.Write32(uint32(t.size())) 315 for _, s := range t.strings { 316 out.WriteString(s) 317 out.Write8(0) 318 } 319 } 320 321 // peSection represents section from COFF section table. 322 type peSection struct { 323 name string 324 shortName string 325 index int // one-based index into the Section Table 326 virtualSize uint32 327 virtualAddress uint32 328 sizeOfRawData uint32 329 pointerToRawData uint32 330 pointerToRelocations uint32 331 numberOfRelocations uint16 332 characteristics uint32 333 } 334 335 // checkOffset verifies COFF section sect offset in the file. 336 func (sect *peSection) checkOffset(off int64) { 337 if off != int64(sect.pointerToRawData) { 338 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(off)) 339 errorexit() 340 } 341 } 342 343 // checkSegment verifies COFF section sect matches address 344 // and file offset provided in segment seg. 345 func (sect *peSection) checkSegment(seg *sym.Segment) { 346 if seg.Vaddr-PEBASE != uint64(sect.virtualAddress) { 347 Errorf(nil, "%s.VirtualAddress = %#x, want %#x", sect.name, uint64(int64(sect.virtualAddress)), uint64(int64(seg.Vaddr-PEBASE))) 348 errorexit() 349 } 350 if seg.Fileoff != uint64(sect.pointerToRawData) { 351 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(int64(seg.Fileoff))) 352 errorexit() 353 } 354 } 355 356 // pad adds zeros to the section sect. It writes as many bytes 357 // as necessary to make section sect.SizeOfRawData bytes long. 358 // It assumes that n bytes are already written to the file. 359 func (sect *peSection) pad(out *OutBuf, n uint32) { 360 out.WriteStringN("", int(sect.sizeOfRawData-n)) 361 } 362 363 // write writes COFF section sect into the output file. 364 func (sect *peSection) write(out *OutBuf, linkmode LinkMode) error { 365 h := pe.SectionHeader32{ 366 VirtualSize: sect.virtualSize, 367 SizeOfRawData: sect.sizeOfRawData, 368 PointerToRawData: sect.pointerToRawData, 369 PointerToRelocations: sect.pointerToRelocations, 370 NumberOfRelocations: sect.numberOfRelocations, 371 Characteristics: sect.characteristics, 372 } 373 if linkmode != LinkExternal { 374 h.VirtualAddress = sect.virtualAddress 375 } 376 copy(h.Name[:], sect.shortName) 377 return binary.Write(out, binary.LittleEndian, h) 378 } 379 380 // emitRelocations emits the relocation entries for the sect. 381 // The actual relocations are emitted by relocfn. 382 // This updates the corresponding PE section table entry 383 // with the relocation offset and count. 384 func (sect *peSection) emitRelocations(out *OutBuf, relocfn func() int) { 385 sect.pointerToRelocations = uint32(out.Offset()) 386 // first entry: extended relocs 387 out.Write32(0) // placeholder for number of relocation + 1 388 out.Write32(0) 389 out.Write16(0) 390 391 n := relocfn() + 1 392 393 cpos := out.Offset() 394 out.SeekSet(int64(sect.pointerToRelocations)) 395 out.Write32(uint32(n)) 396 out.SeekSet(cpos) 397 if n > 0x10000 { 398 n = 0x10000 399 sect.characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 400 } else { 401 sect.pointerToRelocations += 10 // skip the extend reloc entry 402 } 403 sect.numberOfRelocations = uint16(n - 1) 404 } 405 406 // peFile is used to build COFF file. 407 type peFile struct { 408 sections []*peSection 409 stringTable peStringTable 410 textSect *peSection 411 rdataSect *peSection 412 dataSect *peSection 413 bssSect *peSection 414 ctorsSect *peSection 415 nextSectOffset uint32 416 nextFileOffset uint32 417 symtabOffset int64 // offset to the start of symbol table 418 symbolCount int // number of symbol table records written 419 dataDirectory [16]pe.DataDirectory 420 } 421 422 // addSection adds section to the COFF file f. 423 func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection { 424 sect := &peSection{ 425 name: name, 426 shortName: name, 427 index: len(f.sections) + 1, 428 virtualSize: uint32(sectsize), 429 virtualAddress: f.nextSectOffset, 430 pointerToRawData: f.nextFileOffset, 431 } 432 f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN)) 433 if filesize > 0 { 434 sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN)) 435 f.nextFileOffset += sect.sizeOfRawData 436 } 437 f.sections = append(f.sections, sect) 438 return sect 439 } 440 441 // addDWARFSection adds DWARF section to the COFF file f. 442 // This function is similar to addSection, but DWARF section names are 443 // longer than 8 characters, so they need to be stored in the string table. 444 func (f *peFile) addDWARFSection(name string, size int) *peSection { 445 if size == 0 { 446 Exitf("DWARF section %q is empty", name) 447 } 448 // DWARF section names are longer than 8 characters. 449 // PE format requires such names to be stored in string table, 450 // and section names replaced with slash (/) followed by 451 // correspondent string table index. 452 // see http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx 453 // for details 454 off := f.stringTable.add(name) 455 h := f.addSection(name, size, size) 456 h.shortName = fmt.Sprintf("/%d", off) 457 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 458 return h 459 } 460 461 // addDWARF adds DWARF information to the COFF file f. 462 func (f *peFile) addDWARF() { 463 if *FlagS { // disable symbol table 464 return 465 } 466 if *FlagW { // disable dwarf 467 return 468 } 469 for _, sect := range Segdwarf.Sections { 470 h := f.addDWARFSection(sect.Name, int(sect.Length)) 471 fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff 472 if uint64(h.pointerToRawData) != fileoff { 473 Exitf("%s.PointerToRawData = %#x, want %#x", sect.Name, h.pointerToRawData, fileoff) 474 } 475 } 476 } 477 478 // addInitArray adds .ctors COFF section to the file f. 479 func (f *peFile) addInitArray(ctxt *Link) *peSection { 480 // The size below was determined by the specification for array relocations, 481 // and by observing what GCC writes here. If the initarray section grows to 482 // contain more than one constructor entry, the size will need to be 8 * constructor_count. 483 // However, the entire Go runtime is initialized from just one function, so it is unlikely 484 // that this will need to grow in the future. 485 var size int 486 switch objabi.GOARCH { 487 default: 488 Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", objabi.GOARCH) 489 case "386": 490 size = 4 491 case "amd64": 492 size = 8 493 case "arm": 494 size = 4 495 } 496 sect := f.addSection(".ctors", size, size) 497 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 498 sect.sizeOfRawData = uint32(size) 499 ctxt.Out.SeekSet(int64(sect.pointerToRawData)) 500 sect.checkOffset(ctxt.Out.Offset()) 501 502 init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0) 503 addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr 504 switch objabi.GOARCH { 505 case "386", "arm": 506 ctxt.Out.Write32(uint32(addr)) 507 case "amd64": 508 ctxt.Out.Write64(addr) 509 } 510 return sect 511 } 512 513 // emitRelocations emits relocation entries for go.o in external linking. 514 func (f *peFile) emitRelocations(ctxt *Link) { 515 for ctxt.Out.Offset()&7 != 0 { 516 ctxt.Out.Write8(0) 517 } 518 519 // relocsect relocates symbols from first in section sect, and returns 520 // the total number of relocations emitted. 521 relocsect := func(sect *sym.Section, syms []*sym.Symbol, base uint64) int { 522 // If main section has no bits, nothing to relocate. 523 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 524 return 0 525 } 526 relocs := 0 527 sect.Reloff = uint64(ctxt.Out.Offset()) 528 for i, s := range syms { 529 if !s.Attr.Reachable() { 530 continue 531 } 532 if uint64(s.Value) >= sect.Vaddr { 533 syms = syms[i:] 534 break 535 } 536 } 537 eaddr := int32(sect.Vaddr + sect.Length) 538 for _, sym := range syms { 539 if !sym.Attr.Reachable() { 540 continue 541 } 542 if sym.Value >= int64(eaddr) { 543 break 544 } 545 for ri := range sym.R { 546 r := &sym.R[ri] 547 if r.Done { 548 continue 549 } 550 if r.Xsym == nil { 551 Errorf(sym, "missing xsym in relocation") 552 continue 553 } 554 if r.Xsym.Dynid < 0 { 555 Errorf(sym, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type) 556 } 557 if !thearch.PEreloc1(ctxt.Arch, ctxt.Out, sym, r, int64(uint64(sym.Value+int64(r.Off))-base)) { 558 Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name) 559 } 560 relocs++ 561 } 562 } 563 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff 564 return relocs 565 } 566 567 sects := []struct { 568 peSect *peSection 569 seg *sym.Segment 570 syms []*sym.Symbol 571 }{ 572 {f.textSect, &Segtext, ctxt.Textp}, 573 {f.rdataSect, &Segrodata, datap}, 574 {f.dataSect, &Segdata, datap}, 575 } 576 for _, s := range sects { 577 s.peSect.emitRelocations(ctxt.Out, func() int { 578 var n int 579 for _, sect := range s.seg.Sections { 580 n += relocsect(sect, s.syms, s.seg.Vaddr) 581 } 582 return n 583 }) 584 } 585 586 dwarfLoop: 587 for _, sect := range Segdwarf.Sections { 588 for _, pesect := range f.sections { 589 if sect.Name == pesect.name { 590 pesect.emitRelocations(ctxt.Out, func() int { 591 return relocsect(sect, dwarfp, sect.Vaddr) 592 }) 593 continue dwarfLoop 594 } 595 } 596 Errorf(nil, "emitRelocations: could not find %q section", sect.Name) 597 } 598 599 f.ctorsSect.emitRelocations(ctxt.Out, func() int { 600 dottext := ctxt.Syms.Lookup(".text", 0) 601 ctxt.Out.Write32(0) 602 ctxt.Out.Write32(uint32(dottext.Dynid)) 603 switch objabi.GOARCH { 604 default: 605 Errorf(dottext, "unknown architecture for PE: %q\n", objabi.GOARCH) 606 case "386": 607 ctxt.Out.Write16(IMAGE_REL_I386_DIR32) 608 case "amd64": 609 ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64) 610 case "arm": 611 ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32) 612 } 613 return 1 614 }) 615 } 616 617 // writeSymbol appends symbol s to file f symbol table. 618 // It also sets s.Dynid to written symbol number. 619 func (f *peFile) writeSymbol(out *OutBuf, s *sym.Symbol, value int64, sectidx int, typ uint16, class uint8) { 620 if len(s.Name) > 8 { 621 out.Write32(0) 622 out.Write32(uint32(f.stringTable.add(s.Name))) 623 } else { 624 out.WriteStringN(s.Name, 8) 625 } 626 out.Write32(uint32(value)) 627 out.Write16(uint16(sectidx)) 628 out.Write16(typ) 629 out.Write8(class) 630 out.Write8(0) // no aux entries 631 632 s.Dynid = int32(f.symbolCount) 633 634 f.symbolCount++ 635 } 636 637 // mapToPESection searches peFile f for s symbol's location. 638 // It returns PE section index, and offset within that section. 639 func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int, offset int64, err error) { 640 if s.Sect == nil { 641 return 0, 0, fmt.Errorf("could not map %s symbol with no section", s.Name) 642 } 643 if s.Sect.Seg == &Segtext { 644 return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil 645 } 646 if s.Sect.Seg == &Segrodata { 647 return f.rdataSect.index, int64(uint64(s.Value) - Segrodata.Vaddr), nil 648 } 649 if s.Sect.Seg != &Segdata { 650 return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", s.Name) 651 } 652 v := uint64(s.Value) - Segdata.Vaddr 653 if linkmode != LinkExternal { 654 return f.dataSect.index, int64(v), nil 655 } 656 if s.Type == sym.SDATA { 657 return f.dataSect.index, int64(v), nil 658 } 659 // Note: although address of runtime.edata (type sym.SDATA) is at the start of .bss section 660 // it still belongs to the .data section, not the .bss section. 661 if v < Segdata.Filelen { 662 return f.dataSect.index, int64(v), nil 663 } 664 return f.bssSect.index, int64(v - Segdata.Filelen), nil 665 } 666 667 // writeSymbols writes all COFF symbol table records. 668 func (f *peFile) writeSymbols(ctxt *Link) { 669 670 put := func(ctxt *Link, s *sym.Symbol, name string, type_ SymbolType, addr int64, gotype *sym.Symbol) { 671 if s == nil { 672 return 673 } 674 if s.Sect == nil && type_ != UndefinedSym { 675 return 676 } 677 switch type_ { 678 default: 679 return 680 case DataSym, BSSSym, TextSym, UndefinedSym: 681 } 682 683 // Only windows/386 requires underscore prefix on external symbols. 684 if ctxt.Arch.Family == sys.I386 && 685 ctxt.LinkMode == LinkExternal && 686 (s.Type == sym.SHOSTOBJ || s.Attr.CgoExport()) { 687 s.Name = "_" + s.Name 688 } 689 690 var typ uint16 691 if ctxt.LinkMode == LinkExternal { 692 typ = IMAGE_SYM_TYPE_NULL 693 } else { 694 // TODO: fix IMAGE_SYM_DTYPE_ARRAY value and use following expression, instead of 0x0308 695 typ = IMAGE_SYM_DTYPE_ARRAY<<8 + IMAGE_SYM_TYPE_STRUCT 696 typ = 0x0308 // "array of structs" 697 } 698 sect, value, err := f.mapToPESection(s, ctxt.LinkMode) 699 if err != nil { 700 if type_ == UndefinedSym { 701 typ = IMAGE_SYM_DTYPE_FUNCTION 702 } else { 703 Errorf(s, "addpesym: %v", err) 704 } 705 } 706 class := IMAGE_SYM_CLASS_EXTERNAL 707 if s.IsFileLocal() || s.Attr.VisibilityHidden() || s.Attr.Local() { 708 class = IMAGE_SYM_CLASS_STATIC 709 } 710 f.writeSymbol(ctxt.Out, s, value, sect, typ, uint8(class)) 711 } 712 713 if ctxt.LinkMode == LinkExternal { 714 // Include section symbols as external, because 715 // .ctors and .debug_* section relocations refer to it. 716 for _, pesect := range f.sections { 717 sym := ctxt.Syms.Lookup(pesect.name, 0) 718 f.writeSymbol(ctxt.Out, sym, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC) 719 } 720 } 721 722 genasmsym(ctxt, put) 723 } 724 725 // writeSymbolTableAndStringTable writes out symbol and string tables for peFile f. 726 func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) { 727 f.symtabOffset = ctxt.Out.Offset() 728 729 // write COFF symbol table 730 if !*FlagS || ctxt.LinkMode == LinkExternal { 731 f.writeSymbols(ctxt) 732 } 733 734 // update COFF file header and section table 735 size := f.stringTable.size() + 18*f.symbolCount 736 var h *peSection 737 if ctxt.LinkMode != LinkExternal { 738 // We do not really need .symtab for go.o, and if we have one, ld 739 // will also include it in the exe, and that will confuse windows. 740 h = f.addSection(".symtab", size, size) 741 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 742 h.checkOffset(f.symtabOffset) 743 } 744 745 // write COFF string table 746 f.stringTable.write(ctxt.Out) 747 if ctxt.LinkMode != LinkExternal { 748 h.pad(ctxt.Out, uint32(size)) 749 } 750 } 751 752 // writeFileHeader writes COFF file header for peFile f. 753 func (f *peFile) writeFileHeader(arch *sys.Arch, out *OutBuf, linkmode LinkMode) { 754 var fh pe.FileHeader 755 756 switch arch.Family { 757 default: 758 Exitf("unknown PE architecture: %v", arch.Family) 759 case sys.AMD64: 760 fh.Machine = IMAGE_FILE_MACHINE_AMD64 761 case sys.I386: 762 fh.Machine = IMAGE_FILE_MACHINE_I386 763 case sys.ARM: 764 fh.Machine = IMAGE_FILE_MACHINE_ARMNT 765 } 766 767 fh.NumberOfSections = uint16(len(f.sections)) 768 769 // Being able to produce identical output for identical input is 770 // much more beneficial than having build timestamp in the header. 771 fh.TimeDateStamp = 0 772 773 if linkmode == LinkExternal { 774 fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED 775 } else { 776 switch arch.Family { 777 default: 778 Exitf("write COFF(ext): unknown PE architecture: %v", arch.Family) 779 case sys.AMD64, sys.I386: 780 fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED 781 case sys.ARM: 782 fh.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED 783 } 784 } 785 if pe64 != 0 { 786 var oh64 pe.OptionalHeader64 787 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) 788 fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE 789 } else { 790 var oh pe.OptionalHeader32 791 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh)) 792 fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE 793 } 794 795 fh.PointerToSymbolTable = uint32(f.symtabOffset) 796 fh.NumberOfSymbols = uint32(f.symbolCount) 797 798 binary.Write(out, binary.LittleEndian, &fh) 799 } 800 801 // writeOptionalHeader writes COFF optional header for peFile f. 802 func (f *peFile) writeOptionalHeader(ctxt *Link) { 803 var oh pe.OptionalHeader32 804 var oh64 pe.OptionalHeader64 805 806 if pe64 != 0 { 807 oh64.Magic = 0x20b // PE32+ 808 } else { 809 oh.Magic = 0x10b // PE32 810 oh.BaseOfData = f.dataSect.virtualAddress 811 } 812 813 // Fill out both oh64 and oh. We only use one. Oh well. 814 oh64.MajorLinkerVersion = 3 815 oh.MajorLinkerVersion = 3 816 oh64.MinorLinkerVersion = 0 817 oh.MinorLinkerVersion = 0 818 oh64.SizeOfCode = f.textSect.sizeOfRawData 819 oh.SizeOfCode = f.textSect.sizeOfRawData 820 oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData 821 oh.SizeOfInitializedData = f.dataSect.sizeOfRawData 822 oh64.SizeOfUninitializedData = 0 823 oh.SizeOfUninitializedData = 0 824 if ctxt.LinkMode != LinkExternal { 825 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 826 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 827 } 828 oh64.BaseOfCode = f.textSect.virtualAddress 829 oh.BaseOfCode = f.textSect.virtualAddress 830 oh64.ImageBase = PEBASE 831 oh.ImageBase = PEBASE 832 oh64.SectionAlignment = uint32(PESECTALIGN) 833 oh.SectionAlignment = uint32(PESECTALIGN) 834 oh64.FileAlignment = uint32(PEFILEALIGN) 835 oh.FileAlignment = uint32(PEFILEALIGN) 836 oh64.MajorOperatingSystemVersion = 4 837 oh.MajorOperatingSystemVersion = 4 838 oh64.MinorOperatingSystemVersion = 0 839 oh.MinorOperatingSystemVersion = 0 840 oh64.MajorImageVersion = 1 841 oh.MajorImageVersion = 1 842 oh64.MinorImageVersion = 0 843 oh.MinorImageVersion = 0 844 oh64.MajorSubsystemVersion = 4 845 oh.MajorSubsystemVersion = 4 846 oh64.MinorSubsystemVersion = 0 847 oh.MinorSubsystemVersion = 0 848 oh64.SizeOfImage = f.nextSectOffset 849 oh.SizeOfImage = f.nextSectOffset 850 oh64.SizeOfHeaders = uint32(PEFILEHEADR) 851 oh.SizeOfHeaders = uint32(PEFILEHEADR) 852 if windowsgui { 853 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 854 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 855 } else { 856 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 857 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 858 } 859 860 switch ctxt.Arch.Family { 861 case sys.ARM: 862 oh64.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT 863 oh.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT 864 } 865 866 // Disable stack growth as we don't want Windows to 867 // fiddle with the thread stack limits, which we set 868 // ourselves to circumvent the stack checks in the 869 // Windows exception dispatcher. 870 // Commit size must be strictly less than reserve 871 // size otherwise reserve will be rounded up to a 872 // larger size, as verified with VMMap. 873 874 // On 64-bit, we always reserve 2MB stacks. "Pure" Go code is 875 // okay with much smaller stacks, but the syscall package 876 // makes it easy to call into arbitrary C code without cgo, 877 // and system calls even in "pure" Go code are actually C 878 // calls that may need more stack than we think. 879 // 880 // The default stack reserve size directly affects only the main 881 // thread, ctrlhandler thread, and profileloop thread. For 882 // these, it must be greater than the stack size assumed by 883 // externalthreadhandler. 884 // 885 // For other threads, the runtime explicitly asks the kernel 886 // to use the default stack size so that all stacks are 887 // consistent. 888 // 889 // At thread start, in minit, the runtime queries the OS for 890 // the actual stack bounds so that the stack size doesn't need 891 // to be hard-coded into the runtime. 892 oh64.SizeOfStackReserve = 0x00200000 893 if !iscgo { 894 oh64.SizeOfStackCommit = 0x00001000 895 } else { 896 // TODO(brainman): Maybe remove optional header writing altogether for cgo. 897 // For cgo it is the external linker that is building final executable. 898 // And it probably does not use any information stored in optional header. 899 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages 900 } 901 902 oh.SizeOfStackReserve = 0x00100000 903 if !iscgo { 904 oh.SizeOfStackCommit = 0x00001000 905 } else { 906 oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages 907 } 908 909 oh64.SizeOfHeapReserve = 0x00100000 910 oh.SizeOfHeapReserve = 0x00100000 911 oh64.SizeOfHeapCommit = 0x00001000 912 oh.SizeOfHeapCommit = 0x00001000 913 oh64.NumberOfRvaAndSizes = 16 914 oh.NumberOfRvaAndSizes = 16 915 916 if pe64 != 0 { 917 oh64.DataDirectory = f.dataDirectory 918 } else { 919 oh.DataDirectory = f.dataDirectory 920 } 921 922 if pe64 != 0 { 923 binary.Write(ctxt.Out, binary.LittleEndian, &oh64) 924 } else { 925 binary.Write(ctxt.Out, binary.LittleEndian, &oh) 926 } 927 } 928 929 var pefile peFile 930 931 func Peinit(ctxt *Link) { 932 var l int 933 934 switch ctxt.Arch.Family { 935 // 64-bit architectures 936 case sys.AMD64: 937 pe64 = 1 938 var oh64 pe.OptionalHeader64 939 l = binary.Size(&oh64) 940 941 // 32-bit architectures 942 default: 943 var oh pe.OptionalHeader32 944 l = binary.Size(&oh) 945 946 } 947 948 if ctxt.LinkMode == LinkExternal { 949 // .rdata section will contain "masks" and "shifts" symbols, and they 950 // need to be aligned to 16-bytes. So make all sections aligned 951 // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external 952 // linker will honour that requirement. 953 PESECTALIGN = 32 954 PEFILEALIGN = 0 955 } 956 957 var sh [16]pe.SectionHeader32 958 var fh pe.FileHeader 959 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN)) 960 if ctxt.LinkMode != LinkExternal { 961 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN)) 962 } else { 963 PESECTHEADR = 0 964 } 965 pefile.nextSectOffset = uint32(PESECTHEADR) 966 pefile.nextFileOffset = uint32(PEFILEHEADR) 967 968 if ctxt.LinkMode == LinkInternal { 969 // some mingw libs depend on this symbol, for example, FindPESectionByName 970 ctxt.xdefine("__image_base__", sym.SDATA, PEBASE) 971 ctxt.xdefine("_image_base__", sym.SDATA, PEBASE) 972 } 973 974 HEADR = PEFILEHEADR 975 if *FlagTextAddr == -1 { 976 *FlagTextAddr = PEBASE + int64(PESECTHEADR) 977 } 978 if *FlagDataAddr == -1 { 979 *FlagDataAddr = 0 980 } 981 if *FlagRound == -1 { 982 *FlagRound = int(PESECTALIGN) 983 } 984 if *FlagDataAddr != 0 && *FlagRound != 0 { 985 fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*FlagDataAddr), uint32(*FlagRound)) 986 } 987 } 988 989 func pewrite(ctxt *Link) { 990 ctxt.Out.SeekSet(0) 991 if ctxt.LinkMode != LinkExternal { 992 ctxt.Out.Write(dosstub) 993 ctxt.Out.WriteStringN("PE", 4) 994 } 995 996 pefile.writeFileHeader(ctxt.Arch, ctxt.Out, ctxt.LinkMode) 997 998 pefile.writeOptionalHeader(ctxt) 999 1000 for _, sect := range pefile.sections { 1001 sect.write(ctxt.Out, ctxt.LinkMode) 1002 } 1003 } 1004 1005 func strput(out *OutBuf, s string) { 1006 out.WriteString(s) 1007 out.Write8(0) 1008 // string must be padded to even size 1009 if (len(s)+1)%2 != 0 { 1010 out.Write8(0) 1011 } 1012 } 1013 1014 func initdynimport(ctxt *Link) *Dll { 1015 var d *Dll 1016 1017 dr = nil 1018 var m *Imp 1019 for _, s := range ctxt.Syms.Allsym { 1020 if !s.Attr.Reachable() || s.Type != sym.SDYNIMPORT { 1021 continue 1022 } 1023 for d = dr; d != nil; d = d.next { 1024 if d.name == s.Dynimplib() { 1025 m = new(Imp) 1026 break 1027 } 1028 } 1029 1030 if d == nil { 1031 d = new(Dll) 1032 d.name = s.Dynimplib() 1033 d.next = dr 1034 dr = d 1035 m = new(Imp) 1036 } 1037 1038 // Because external link requires properly stdcall decorated name, 1039 // all external symbols in runtime use %n to denote that the number 1040 // of uinptrs this function consumes. Store the argsize and discard 1041 // the %n suffix if any. 1042 m.argsize = -1 1043 extName := s.Extname() 1044 if i := strings.IndexByte(extName, '%'); i >= 0 { 1045 var err error 1046 m.argsize, err = strconv.Atoi(extName[i+1:]) 1047 if err != nil { 1048 Errorf(s, "failed to parse stdcall decoration: %v", err) 1049 } 1050 m.argsize *= ctxt.Arch.PtrSize 1051 s.SetExtname(extName[:i]) 1052 } 1053 1054 m.s = s 1055 m.next = d.ms 1056 d.ms = m 1057 } 1058 1059 if ctxt.LinkMode == LinkExternal { 1060 // Add real symbol name 1061 for d := dr; d != nil; d = d.next { 1062 for m = d.ms; m != nil; m = m.next { 1063 m.s.Type = sym.SDATA 1064 m.s.Grow(int64(ctxt.Arch.PtrSize)) 1065 dynName := m.s.Extname() 1066 // only windows/386 requires stdcall decoration 1067 if ctxt.Arch.Family == sys.I386 && m.argsize >= 0 { 1068 dynName += fmt.Sprintf("@%d", m.argsize) 1069 } 1070 dynSym := ctxt.Syms.Lookup(dynName, 0) 1071 dynSym.Attr |= sym.AttrReachable 1072 dynSym.Type = sym.SHOSTOBJ 1073 r := m.s.AddRel() 1074 r.Sym = dynSym 1075 r.Off = 0 1076 r.Siz = uint8(ctxt.Arch.PtrSize) 1077 r.Type = objabi.R_ADDR 1078 } 1079 } 1080 } else { 1081 dynamic := ctxt.Syms.Lookup(".windynamic", 0) 1082 dynamic.Attr |= sym.AttrReachable 1083 dynamic.Type = sym.SWINDOWS 1084 for d := dr; d != nil; d = d.next { 1085 for m = d.ms; m != nil; m = m.next { 1086 m.s.Type = sym.SWINDOWS 1087 m.s.Attr |= sym.AttrSubSymbol 1088 m.s.Sub = dynamic.Sub 1089 dynamic.Sub = m.s 1090 m.s.Value = dynamic.Size 1091 dynamic.Size += int64(ctxt.Arch.PtrSize) 1092 } 1093 1094 dynamic.Size += int64(ctxt.Arch.PtrSize) 1095 } 1096 } 1097 1098 return dr 1099 } 1100 1101 // peimporteddlls returns the gcc command line argument to link all imported 1102 // DLLs. 1103 func peimporteddlls() []string { 1104 var dlls []string 1105 1106 for d := dr; d != nil; d = d.next { 1107 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll")) 1108 } 1109 1110 return dlls 1111 } 1112 1113 func addimports(ctxt *Link, datsect *peSection) { 1114 startoff := ctxt.Out.Offset() 1115 dynamic := ctxt.Syms.Lookup(".windynamic", 0) 1116 1117 // skip import descriptor table (will write it later) 1118 n := uint64(0) 1119 1120 for d := dr; d != nil; d = d.next { 1121 n++ 1122 } 1123 ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1)) 1124 1125 // write dll names 1126 for d := dr; d != nil; d = d.next { 1127 d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff) 1128 strput(ctxt.Out, d.name) 1129 } 1130 1131 // write function names 1132 for d := dr; d != nil; d = d.next { 1133 for m := d.ms; m != nil; m = m.next { 1134 m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff) 1135 ctxt.Out.Write16(0) // hint 1136 strput(ctxt.Out, m.s.Extname()) 1137 } 1138 } 1139 1140 // write OriginalFirstThunks 1141 oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff) 1142 1143 n = uint64(ctxt.Out.Offset()) 1144 for d := dr; d != nil; d = d.next { 1145 d.thunkoff = uint64(ctxt.Out.Offset()) - n 1146 for m := d.ms; m != nil; m = m.next { 1147 if pe64 != 0 { 1148 ctxt.Out.Write64(m.off) 1149 } else { 1150 ctxt.Out.Write32(uint32(m.off)) 1151 } 1152 } 1153 1154 if pe64 != 0 { 1155 ctxt.Out.Write64(0) 1156 } else { 1157 ctxt.Out.Write32(0) 1158 } 1159 } 1160 1161 // add pe section and pad it at the end 1162 n = uint64(ctxt.Out.Offset()) - uint64(startoff) 1163 1164 isect := pefile.addSection(".idata", int(n), int(n)) 1165 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1166 isect.checkOffset(startoff) 1167 isect.pad(ctxt.Out, uint32(n)) 1168 endoff := ctxt.Out.Offset() 1169 1170 // write FirstThunks (allocated in .data section) 1171 ftbase := uint64(dynamic.Value) - uint64(datsect.virtualAddress) - PEBASE 1172 1173 ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase)) 1174 for d := dr; d != nil; d = d.next { 1175 for m := d.ms; m != nil; m = m.next { 1176 if pe64 != 0 { 1177 ctxt.Out.Write64(m.off) 1178 } else { 1179 ctxt.Out.Write32(uint32(m.off)) 1180 } 1181 } 1182 1183 if pe64 != 0 { 1184 ctxt.Out.Write64(0) 1185 } else { 1186 ctxt.Out.Write32(0) 1187 } 1188 } 1189 1190 // finally write import descriptor table 1191 out := ctxt.Out 1192 out.SeekSet(startoff) 1193 1194 for d := dr; d != nil; d = d.next { 1195 out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff)) 1196 out.Write32(0) 1197 out.Write32(0) 1198 out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff)) 1199 out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff)) 1200 } 1201 1202 out.Write32(0) //end 1203 out.Write32(0) 1204 out.Write32(0) 1205 out.Write32(0) 1206 out.Write32(0) 1207 1208 // update data directory 1209 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress 1210 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize 1211 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE) 1212 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size) 1213 1214 out.SeekSet(endoff) 1215 } 1216 1217 type byExtname []*sym.Symbol 1218 1219 func (s byExtname) Len() int { return len(s) } 1220 func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 1221 func (s byExtname) Less(i, j int) bool { return s[i].Extname() < s[j].Extname() } 1222 1223 func initdynexport(ctxt *Link) { 1224 nexport = 0 1225 for _, s := range ctxt.Syms.Allsym { 1226 if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() { 1227 continue 1228 } 1229 if nexport+1 > len(dexport) { 1230 Errorf(s, "pe dynexport table is full") 1231 errorexit() 1232 } 1233 1234 dexport[nexport] = s 1235 nexport++ 1236 } 1237 1238 sort.Sort(byExtname(dexport[:nexport])) 1239 } 1240 1241 func addexports(ctxt *Link) { 1242 var e IMAGE_EXPORT_DIRECTORY 1243 1244 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1 1245 for i := 0; i < nexport; i++ { 1246 size += len(dexport[i].Extname()) + 1 1247 } 1248 1249 if nexport == 0 { 1250 return 1251 } 1252 1253 sect := pefile.addSection(".edata", size, size) 1254 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1255 sect.checkOffset(ctxt.Out.Offset()) 1256 va := int(sect.virtualAddress) 1257 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va) 1258 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize 1259 1260 vaName := va + binary.Size(&e) + nexport*4 1261 vaAddr := va + binary.Size(&e) 1262 vaNa := va + binary.Size(&e) + nexport*8 1263 1264 e.Characteristics = 0 1265 e.MajorVersion = 0 1266 e.MinorVersion = 0 1267 e.NumberOfFunctions = uint32(nexport) 1268 e.NumberOfNames = uint32(nexport) 1269 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names. 1270 e.Base = 1 1271 e.AddressOfFunctions = uint32(vaAddr) 1272 e.AddressOfNames = uint32(vaName) 1273 e.AddressOfNameOrdinals = uint32(vaNa) 1274 1275 out := ctxt.Out 1276 1277 // put IMAGE_EXPORT_DIRECTORY 1278 binary.Write(out, binary.LittleEndian, &e) 1279 1280 // put EXPORT Address Table 1281 for i := 0; i < nexport; i++ { 1282 out.Write32(uint32(dexport[i].Value - PEBASE)) 1283 } 1284 1285 // put EXPORT Name Pointer Table 1286 v := int(e.Name + uint32(len(*flagOutfile)) + 1) 1287 1288 for i := 0; i < nexport; i++ { 1289 out.Write32(uint32(v)) 1290 v += len(dexport[i].Extname()) + 1 1291 } 1292 1293 // put EXPORT Ordinal Table 1294 for i := 0; i < nexport; i++ { 1295 out.Write16(uint16(i)) 1296 } 1297 1298 // put Names 1299 out.WriteStringN(*flagOutfile, len(*flagOutfile)+1) 1300 1301 for i := 0; i < nexport; i++ { 1302 out.WriteStringN(dexport[i].Extname(), len(dexport[i].Extname())+1) 1303 } 1304 sect.pad(out, uint32(size)) 1305 } 1306 1307 // peBaseRelocEntry represents a single relocation entry. 1308 type peBaseRelocEntry struct { 1309 typeOff uint16 1310 rel *sym.Reloc 1311 sym *sym.Symbol // For debug 1312 } 1313 1314 // peBaseRelocBlock represents a Base Relocation Block. A block 1315 // is a collection of relocation entries in a page, where each 1316 // entry describes a single relocation. 1317 // The block page RVA (Relative Virtual Address) is the index 1318 // into peBaseRelocTable.blocks. 1319 type peBaseRelocBlock struct { 1320 entries []peBaseRelocEntry 1321 } 1322 1323 // pePages is a type used to store the list of pages for which there 1324 // are base relocation blocks. This is defined as a type so that 1325 // it can be sorted. 1326 type pePages []uint32 1327 1328 func (p pePages) Len() int { return len(p) } 1329 func (p pePages) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 1330 func (p pePages) Less(i, j int) bool { return p[i] < p[j] } 1331 1332 // A PE base relocation table is a list of blocks, where each block 1333 // contains relocation information for a single page. The blocks 1334 // must be emitted in order of page virtual address. 1335 // See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only 1336 type peBaseRelocTable struct { 1337 blocks map[uint32]peBaseRelocBlock 1338 1339 // pePages is a list of keys into blocks map. 1340 // It is stored separately for ease of sorting. 1341 pages pePages 1342 } 1343 1344 func (rt *peBaseRelocTable) init(ctxt *Link) { 1345 rt.blocks = make(map[uint32]peBaseRelocBlock) 1346 } 1347 1348 func (rt *peBaseRelocTable) addentry(ctxt *Link, s *sym.Symbol, r *sym.Reloc) { 1349 // pageSize is the size in bytes of a page 1350 // described by a base relocation block. 1351 const pageSize = 0x1000 1352 const pageMask = pageSize - 1 1353 1354 addr := s.Value + int64(r.Off) - int64(PEBASE) 1355 page := uint32(addr &^ pageMask) 1356 off := uint32(addr & pageMask) 1357 1358 b, ok := rt.blocks[page] 1359 if !ok { 1360 rt.pages = append(rt.pages, page) 1361 } 1362 1363 e := peBaseRelocEntry{ 1364 typeOff: uint16(off & 0xFFF), 1365 rel: r, 1366 sym: s, 1367 } 1368 1369 // Set entry type 1370 switch r.Siz { 1371 default: 1372 Exitf("unsupported relocation size %d\n", r.Siz) 1373 case 4: 1374 e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12) 1375 } 1376 1377 b.entries = append(b.entries, e) 1378 rt.blocks[page] = b 1379 } 1380 1381 func (rt *peBaseRelocTable) write(ctxt *Link) { 1382 out := ctxt.Out 1383 1384 // sort the pages array 1385 sort.Sort(rt.pages) 1386 1387 for _, p := range rt.pages { 1388 b := rt.blocks[p] 1389 const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32) 1390 blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2) 1391 out.Write32(p) 1392 out.Write32(blockSize) 1393 1394 for _, e := range b.entries { 1395 out.Write16(e.typeOff) 1396 } 1397 } 1398 } 1399 1400 func addPEBaseRelocSym(ctxt *Link, s *sym.Symbol, rt *peBaseRelocTable) { 1401 for ri := 0; ri < len(s.R); ri++ { 1402 r := &s.R[ri] 1403 1404 if r.Sym == nil { 1405 continue 1406 } 1407 if !r.Sym.Attr.Reachable() { 1408 continue 1409 } 1410 if r.Type >= 256 { 1411 continue 1412 } 1413 if r.Siz == 0 { // informational relocation 1414 continue 1415 } 1416 if r.Type == objabi.R_DWARFFILEREF { 1417 continue 1418 } 1419 1420 switch r.Type { 1421 default: 1422 case objabi.R_ADDR: 1423 rt.addentry(ctxt, s, r) 1424 } 1425 } 1426 } 1427 1428 func addPEBaseReloc(ctxt *Link) { 1429 // We only generate base relocation table for ARM (and ... ARM64), x86, and AMD64 are marked as legacy 1430 // archs and can use fixed base with no base relocation information 1431 switch ctxt.Arch.Family { 1432 default: 1433 return 1434 case sys.ARM: 1435 } 1436 1437 var rt peBaseRelocTable 1438 rt.init(ctxt) 1439 1440 // Get relocation information 1441 for _, s := range ctxt.Textp { 1442 addPEBaseRelocSym(ctxt, s, &rt) 1443 } 1444 for _, s := range datap { 1445 addPEBaseRelocSym(ctxt, s, &rt) 1446 } 1447 1448 // Write relocation information 1449 startoff := ctxt.Out.Offset() 1450 rt.write(ctxt) 1451 size := ctxt.Out.Offset() - startoff 1452 1453 // Add a PE section and pad it at the end 1454 rsect := pefile.addSection(".reloc", int(size), int(size)) 1455 rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 1456 rsect.checkOffset(startoff) 1457 rsect.pad(ctxt.Out, uint32(size)) 1458 1459 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress 1460 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize 1461 } 1462 1463 func (ctxt *Link) dope() { 1464 initdynimport(ctxt) 1465 initdynexport(ctxt) 1466 } 1467 1468 func setpersrc(ctxt *Link, sym *sym.Symbol) { 1469 if rsrcsym != nil { 1470 Errorf(sym, "too many .rsrc sections") 1471 } 1472 1473 rsrcsym = sym 1474 } 1475 1476 func addpersrc(ctxt *Link) { 1477 if rsrcsym == nil { 1478 return 1479 } 1480 1481 h := pefile.addSection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size)) 1482 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA 1483 h.checkOffset(ctxt.Out.Offset()) 1484 1485 // relocation 1486 for ri := range rsrcsym.R { 1487 r := &rsrcsym.R[ri] 1488 p := rsrcsym.P[r.Off:] 1489 val := uint32(int64(h.virtualAddress) + r.Add) 1490 1491 // 32-bit little-endian 1492 p[0] = byte(val) 1493 1494 p[1] = byte(val >> 8) 1495 p[2] = byte(val >> 16) 1496 p[3] = byte(val >> 24) 1497 } 1498 1499 ctxt.Out.Write(rsrcsym.P) 1500 h.pad(ctxt.Out, uint32(rsrcsym.Size)) 1501 1502 // update data directory 1503 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress 1504 1505 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize 1506 } 1507 1508 func Asmbpe(ctxt *Link) { 1509 switch ctxt.Arch.Family { 1510 default: 1511 Exitf("unknown PE architecture: %v", ctxt.Arch.Family) 1512 case sys.AMD64, sys.I386, sys.ARM: 1513 } 1514 1515 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length)) 1516 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ 1517 if ctxt.LinkMode == LinkExternal { 1518 // some data symbols (e.g. masks) end up in the .text section, and they normally 1519 // expect larger alignment requirement than the default text section alignment. 1520 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES 1521 } 1522 t.checkSegment(&Segtext) 1523 pefile.textSect = t 1524 1525 ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length)) 1526 ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1527 if ctxt.LinkMode == LinkExternal { 1528 // some data symbols (e.g. masks) end up in the .rdata section, and they normally 1529 // expect larger alignment requirement than the default text section alignment. 1530 ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES 1531 } 1532 ro.checkSegment(&Segrodata) 1533 pefile.rdataSect = ro 1534 1535 var d *peSection 1536 if ctxt.LinkMode != LinkExternal { 1537 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen)) 1538 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1539 d.checkSegment(&Segdata) 1540 pefile.dataSect = d 1541 } else { 1542 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen)) 1543 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1544 d.checkSegment(&Segdata) 1545 pefile.dataSect = d 1546 1547 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0) 1548 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1549 b.pointerToRawData = 0 1550 pefile.bssSect = b 1551 } 1552 1553 pefile.addDWARF() 1554 1555 if ctxt.LinkMode == LinkExternal { 1556 pefile.ctorsSect = pefile.addInitArray(ctxt) 1557 } 1558 1559 ctxt.Out.SeekSet(int64(pefile.nextFileOffset)) 1560 if ctxt.LinkMode != LinkExternal { 1561 addimports(ctxt, d) 1562 addexports(ctxt) 1563 addPEBaseReloc(ctxt) 1564 } 1565 pefile.writeSymbolTableAndStringTable(ctxt) 1566 addpersrc(ctxt) 1567 if ctxt.LinkMode == LinkExternal { 1568 pefile.emitRelocations(ctxt) 1569 } 1570 1571 pewrite(ctxt) 1572 }