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