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