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