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