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