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