github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 "cmd/internal/sys" 10 "encoding/binary" 11 "fmt" 12 "os" 13 "sort" 14 "strconv" 15 "strings" 16 ) 17 18 type IMAGE_FILE_HEADER struct { 19 Machine uint16 20 NumberOfSections uint16 21 TimeDateStamp uint32 22 PointerToSymbolTable uint32 23 NumberOfSymbols uint32 24 SizeOfOptionalHeader uint16 25 Characteristics uint16 26 } 27 28 type IMAGE_DATA_DIRECTORY struct { 29 VirtualAddress uint32 30 Size uint32 31 } 32 33 type IMAGE_OPTIONAL_HEADER struct { 34 Magic uint16 35 MajorLinkerVersion uint8 36 MinorLinkerVersion uint8 37 SizeOfCode uint32 38 SizeOfInitializedData uint32 39 SizeOfUninitializedData uint32 40 AddressOfEntryPoint uint32 41 BaseOfCode uint32 42 BaseOfData uint32 43 ImageBase uint32 44 SectionAlignment uint32 45 FileAlignment uint32 46 MajorOperatingSystemVersion uint16 47 MinorOperatingSystemVersion uint16 48 MajorImageVersion uint16 49 MinorImageVersion uint16 50 MajorSubsystemVersion uint16 51 MinorSubsystemVersion uint16 52 Win32VersionValue uint32 53 SizeOfImage uint32 54 SizeOfHeaders uint32 55 CheckSum uint32 56 Subsystem uint16 57 DllCharacteristics uint16 58 SizeOfStackReserve uint32 59 SizeOfStackCommit uint32 60 SizeOfHeapReserve uint32 61 SizeOfHeapCommit uint32 62 LoaderFlags uint32 63 NumberOfRvaAndSizes uint32 64 DataDirectory [16]IMAGE_DATA_DIRECTORY 65 } 66 67 type IMAGE_SECTION_HEADER struct { 68 Name [8]uint8 69 VirtualSize uint32 70 VirtualAddress uint32 71 SizeOfRawData uint32 72 PointerToRawData uint32 73 PointerToRelocations uint32 74 PointerToLineNumbers uint32 75 NumberOfRelocations uint16 76 NumberOfLineNumbers uint16 77 Characteristics uint32 78 } 79 80 type IMAGE_IMPORT_DESCRIPTOR struct { 81 OriginalFirstThunk uint32 82 TimeDateStamp uint32 83 ForwarderChain uint32 84 Name uint32 85 FirstThunk uint32 86 } 87 88 type IMAGE_EXPORT_DIRECTORY struct { 89 Characteristics uint32 90 TimeDateStamp uint32 91 MajorVersion uint16 92 MinorVersion uint16 93 Name uint32 94 Base uint32 95 NumberOfFunctions uint32 96 NumberOfNames uint32 97 AddressOfFunctions uint32 98 AddressOfNames uint32 99 AddressOfNameOrdinals uint32 100 } 101 102 const ( 103 PEBASE = 0x00400000 104 105 // 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 func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER { 381 if pensect == 16 { 382 Diag("too many sections") 383 errorexit() 384 } 385 386 h := &sh[pensect] 387 pensect++ 388 copy(h.Name[:], name) 389 h.VirtualSize = uint32(sectsize) 390 h.VirtualAddress = uint32(nextsectoff) 391 nextsectoff = int(Rnd(int64(nextsectoff)+int64(sectsize), PESECTALIGN)) 392 h.PointerToRawData = uint32(nextfileoff) 393 if filesize > 0 { 394 h.SizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN)) 395 nextfileoff += int(h.SizeOfRawData) 396 } 397 398 return h 399 } 400 401 func chksectoff(h *IMAGE_SECTION_HEADER, off int64) { 402 if off != int64(h.PointerToRawData) { 403 Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off)) 404 errorexit() 405 } 406 } 407 408 func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) { 409 if s.Vaddr-PEBASE != uint64(h.VirtualAddress) { 410 Diag("%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE))) 411 errorexit() 412 } 413 414 if s.Fileoff != uint64(h.PointerToRawData) { 415 Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff))) 416 errorexit() 417 } 418 } 419 420 func Peinit() { 421 var l int 422 423 switch SysArch.Family { 424 // 64-bit architectures 425 case sys.AMD64: 426 pe64 = 1 427 428 l = binary.Size(&oh64) 429 dd = oh64.DataDirectory[:] 430 431 // 32-bit architectures 432 default: 433 l = binary.Size(&oh) 434 435 dd = oh.DataDirectory[:] 436 } 437 438 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN)) 439 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN)) 440 nextsectoff = int(PESECTHEADR) 441 nextfileoff = int(PEFILEHEADR) 442 443 // some mingw libs depend on this symbol, for example, FindPESectionByName 444 xdefine("__image_base__", obj.SDATA, PEBASE) 445 446 xdefine("_image_base__", obj.SDATA, PEBASE) 447 } 448 449 func pewrite() { 450 Cseek(0) 451 if Linkmode != LinkExternal { 452 Cwrite(dosstub) 453 strnput("PE", 4) 454 } 455 456 binary.Write(&coutbuf, binary.LittleEndian, &fh) 457 458 if pe64 != 0 { 459 binary.Write(&coutbuf, binary.LittleEndian, &oh64) 460 } else { 461 binary.Write(&coutbuf, binary.LittleEndian, &oh) 462 } 463 binary.Write(&coutbuf, binary.LittleEndian, sh[:pensect]) 464 } 465 466 func strput(s string) { 467 coutbuf.WriteString(s) 468 Cput(0) 469 // string must be padded to even size 470 if (len(s)+1)%2 != 0 { 471 Cput(0) 472 } 473 } 474 475 func initdynimport() *Dll { 476 var d *Dll 477 478 dr = nil 479 var m *Imp 480 for _, s := range Ctxt.Allsym { 481 if !s.Attr.Reachable() || s.Type != obj.SDYNIMPORT { 482 continue 483 } 484 for d = dr; d != nil; d = d.next { 485 if d.name == s.Dynimplib { 486 m = new(Imp) 487 break 488 } 489 } 490 491 if d == nil { 492 d = new(Dll) 493 d.name = s.Dynimplib 494 d.next = dr 495 dr = d 496 m = new(Imp) 497 } 498 499 // Because external link requires properly stdcall decorated name, 500 // all external symbols in runtime use %n to denote that the number 501 // of uinptrs this function consumes. Store the argsize and discard 502 // the %n suffix if any. 503 m.argsize = -1 504 if i := strings.IndexByte(s.Extname, '%'); i >= 0 { 505 var err error 506 m.argsize, err = strconv.Atoi(s.Extname[i+1:]) 507 if err != nil { 508 Diag("failed to parse stdcall decoration: %v", err) 509 } 510 m.argsize *= SysArch.PtrSize 511 s.Extname = s.Extname[:i] 512 } 513 514 m.s = s 515 m.next = d.ms 516 d.ms = m 517 } 518 519 if Linkmode == LinkExternal { 520 // Add real symbol name 521 for d := dr; d != nil; d = d.next { 522 for m = d.ms; m != nil; m = m.next { 523 m.s.Type = obj.SDATA 524 Symgrow(Ctxt, m.s, int64(SysArch.PtrSize)) 525 dynName := m.s.Extname 526 // only windows/386 requires stdcall decoration 527 if SysArch.Family == sys.I386 && m.argsize >= 0 { 528 dynName += fmt.Sprintf("@%d", m.argsize) 529 } 530 dynSym := Linklookup(Ctxt, dynName, 0) 531 dynSym.Attr |= AttrReachable 532 dynSym.Type = obj.SHOSTOBJ 533 r := Addrel(m.s) 534 r.Sym = dynSym 535 r.Off = 0 536 r.Siz = uint8(SysArch.PtrSize) 537 r.Type = obj.R_ADDR 538 } 539 } 540 } else { 541 dynamic := Linklookup(Ctxt, ".windynamic", 0) 542 dynamic.Attr |= AttrReachable 543 dynamic.Type = obj.SWINDOWS 544 for d := dr; d != nil; d = d.next { 545 for m = d.ms; m != nil; m = m.next { 546 m.s.Type = obj.SWINDOWS | obj.SSUB 547 m.s.Sub = dynamic.Sub 548 dynamic.Sub = m.s 549 m.s.Value = dynamic.Size 550 dynamic.Size += int64(SysArch.PtrSize) 551 } 552 553 dynamic.Size += int64(SysArch.PtrSize) 554 } 555 } 556 557 return dr 558 } 559 560 // peimporteddlls returns the gcc command line argument to link all imported 561 // DLLs. 562 func peimporteddlls() []string { 563 var dlls []string 564 565 for d := dr; d != nil; d = d.next { 566 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll")) 567 } 568 569 return dlls 570 } 571 572 func addimports(datsect *IMAGE_SECTION_HEADER) { 573 startoff := Cpos() 574 dynamic := Linklookup(Ctxt, ".windynamic", 0) 575 576 // skip import descriptor table (will write it later) 577 n := uint64(0) 578 579 for d := dr; d != nil; d = d.next { 580 n++ 581 } 582 Cseek(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1)) 583 584 // write dll names 585 for d := dr; d != nil; d = d.next { 586 d.nameoff = uint64(Cpos()) - uint64(startoff) 587 strput(d.name) 588 } 589 590 // write function names 591 var m *Imp 592 for d := dr; d != nil; d = d.next { 593 for m = d.ms; m != nil; m = m.next { 594 m.off = uint64(nextsectoff) + uint64(Cpos()) - uint64(startoff) 595 Wputl(0) // hint 596 strput(m.s.Extname) 597 } 598 } 599 600 // write OriginalFirstThunks 601 oftbase := uint64(Cpos()) - uint64(startoff) 602 603 n = uint64(Cpos()) 604 for d := dr; d != nil; d = d.next { 605 d.thunkoff = uint64(Cpos()) - n 606 for m = d.ms; m != nil; m = m.next { 607 if pe64 != 0 { 608 Vputl(m.off) 609 } else { 610 Lputl(uint32(m.off)) 611 } 612 } 613 614 if pe64 != 0 { 615 Vputl(0) 616 } else { 617 Lputl(0) 618 } 619 } 620 621 // add pe section and pad it at the end 622 n = uint64(Cpos()) - uint64(startoff) 623 624 isect := addpesection(".idata", int(n), int(n)) 625 isect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 626 chksectoff(isect, startoff) 627 strnput("", int(uint64(isect.SizeOfRawData)-n)) 628 endoff := Cpos() 629 630 // write FirstThunks (allocated in .data section) 631 ftbase := uint64(dynamic.Value) - uint64(datsect.VirtualAddress) - PEBASE 632 633 Cseek(int64(uint64(datsect.PointerToRawData) + ftbase)) 634 for d := dr; d != nil; d = d.next { 635 for m = d.ms; m != nil; m = m.next { 636 if pe64 != 0 { 637 Vputl(m.off) 638 } else { 639 Lputl(uint32(m.off)) 640 } 641 } 642 643 if pe64 != 0 { 644 Vputl(0) 645 } else { 646 Lputl(0) 647 } 648 } 649 650 // finally write import descriptor table 651 Cseek(startoff) 652 653 for d := dr; d != nil; d = d.next { 654 Lputl(uint32(uint64(isect.VirtualAddress) + oftbase + d.thunkoff)) 655 Lputl(0) 656 Lputl(0) 657 Lputl(uint32(uint64(isect.VirtualAddress) + d.nameoff)) 658 Lputl(uint32(uint64(datsect.VirtualAddress) + ftbase + d.thunkoff)) 659 } 660 661 Lputl(0) //end 662 Lputl(0) 663 Lputl(0) 664 Lputl(0) 665 Lputl(0) 666 667 // update data directory 668 dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.VirtualAddress 669 670 dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.VirtualSize 671 dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE) 672 dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size) 673 674 Cseek(endoff) 675 } 676 677 type byExtname []*LSym 678 679 func (s byExtname) Len() int { return len(s) } 680 func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 681 func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname } 682 683 func initdynexport() { 684 nexport = 0 685 for _, s := range Ctxt.Allsym { 686 if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() { 687 continue 688 } 689 if nexport+1 > len(dexport) { 690 Diag("pe dynexport table is full") 691 errorexit() 692 } 693 694 dexport[nexport] = s 695 nexport++ 696 } 697 698 sort.Sort(byExtname(dexport[:nexport])) 699 } 700 701 func addexports() { 702 var e IMAGE_EXPORT_DIRECTORY 703 704 size := binary.Size(&e) + 10*nexport + len(outfile) + 1 705 for i := 0; i < nexport; i++ { 706 size += len(dexport[i].Extname) + 1 707 } 708 709 if nexport == 0 { 710 return 711 } 712 713 sect := addpesection(".edata", size, size) 714 sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 715 chksectoff(sect, Cpos()) 716 va := int(sect.VirtualAddress) 717 dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va) 718 dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.VirtualSize 719 720 va_name := va + binary.Size(&e) + nexport*4 721 va_addr := va + binary.Size(&e) 722 va_na := va + binary.Size(&e) + nexport*8 723 724 e.Characteristics = 0 725 e.MajorVersion = 0 726 e.MinorVersion = 0 727 e.NumberOfFunctions = uint32(nexport) 728 e.NumberOfNames = uint32(nexport) 729 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names. 730 e.Base = 1 731 e.AddressOfFunctions = uint32(va_addr) 732 e.AddressOfNames = uint32(va_name) 733 e.AddressOfNameOrdinals = uint32(va_na) 734 735 // put IMAGE_EXPORT_DIRECTORY 736 binary.Write(&coutbuf, binary.LittleEndian, &e) 737 738 // put EXPORT Address Table 739 for i := 0; i < nexport; i++ { 740 Lputl(uint32(dexport[i].Value - PEBASE)) 741 } 742 743 // put EXPORT Name Pointer Table 744 v := int(e.Name + uint32(len(outfile)) + 1) 745 746 for i := 0; i < nexport; i++ { 747 Lputl(uint32(v)) 748 v += len(dexport[i].Extname) + 1 749 } 750 751 // put EXPORT Ordinal Table 752 for i := 0; i < nexport; i++ { 753 Wputl(uint16(i)) 754 } 755 756 // put Names 757 strnput(outfile, len(outfile)+1) 758 759 for i := 0; i < nexport; i++ { 760 strnput(dexport[i].Extname, len(dexport[i].Extname)+1) 761 } 762 strnput("", int(sect.SizeOfRawData-uint32(size))) 763 } 764 765 // perelocsect relocates symbols from first in section sect, and returns 766 // the total number of relocations emitted. 767 func perelocsect(sect *Section, syms []*LSym) int { 768 // If main section has no bits, nothing to relocate. 769 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 770 return 0 771 } 772 773 relocs := 0 774 775 sect.Reloff = uint64(Cpos()) 776 for i, s := range syms { 777 if !s.Attr.Reachable() { 778 continue 779 } 780 if uint64(s.Value) >= sect.Vaddr { 781 syms = syms[i:] 782 break 783 } 784 } 785 786 eaddr := int32(sect.Vaddr + sect.Length) 787 for _, sym := range syms { 788 if !sym.Attr.Reachable() { 789 continue 790 } 791 if sym.Value >= int64(eaddr) { 792 break 793 } 794 Ctxt.Cursym = sym 795 796 for ri := 0; ri < len(sym.R); ri++ { 797 r := &sym.R[ri] 798 if r.Done != 0 { 799 continue 800 } 801 if r.Xsym == nil { 802 Diag("missing xsym in relocation") 803 continue 804 } 805 806 if r.Xsym.Dynid < 0 { 807 Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type) 808 } 809 if !Thearch.PEreloc1(r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) { 810 Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name) 811 } 812 813 relocs++ 814 } 815 } 816 817 sect.Rellen = uint64(Cpos()) - sect.Reloff 818 819 return relocs 820 } 821 822 // peemitreloc emits relocation entries for go.o in external linking. 823 func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) { 824 for Cpos()&7 != 0 { 825 Cput(0) 826 } 827 828 text.PointerToRelocations = uint32(Cpos()) 829 // first entry: extended relocs 830 Lputl(0) // placeholder for number of relocation + 1 831 Lputl(0) 832 Wputl(0) 833 834 n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1 835 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { 836 n += perelocsect(sect, datap) 837 } 838 839 cpos := Cpos() 840 Cseek(int64(text.PointerToRelocations)) 841 Lputl(uint32(n)) 842 Cseek(cpos) 843 if n > 0x10000 { 844 n = 0x10000 845 text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 846 } else { 847 text.PointerToRelocations += 10 // skip the extend reloc entry 848 } 849 text.NumberOfRelocations = uint16(n - 1) 850 851 data.PointerToRelocations = uint32(cpos) 852 // first entry: extended relocs 853 Lputl(0) // placeholder for number of relocation + 1 854 Lputl(0) 855 Wputl(0) 856 857 n = 1 858 for sect := Segdata.Sect; sect != nil; sect = sect.Next { 859 n += perelocsect(sect, datap) 860 } 861 862 cpos = Cpos() 863 Cseek(int64(data.PointerToRelocations)) 864 Lputl(uint32(n)) 865 Cseek(cpos) 866 if n > 0x10000 { 867 n = 0x10000 868 data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 869 } else { 870 data.PointerToRelocations += 10 // skip the extend reloc entry 871 } 872 data.NumberOfRelocations = uint16(n - 1) 873 874 dottext := Linklookup(Ctxt, ".text", 0) 875 ctors.NumberOfRelocations = 1 876 ctors.PointerToRelocations = uint32(Cpos()) 877 sectoff := ctors.VirtualAddress 878 Lputl(sectoff) 879 Lputl(uint32(dottext.Dynid)) 880 switch obj.Getgoarch() { 881 default: 882 fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch()) 883 os.Exit(2) 884 case "386": 885 Wputl(IMAGE_REL_I386_DIR32) 886 case "amd64": 887 Wputl(IMAGE_REL_AMD64_ADDR64) 888 } 889 } 890 891 func dope() { 892 /* relocation table */ 893 rel := Linklookup(Ctxt, ".rel", 0) 894 895 rel.Attr |= AttrReachable 896 rel.Type = obj.SELFROSECT 897 898 initdynimport() 899 initdynexport() 900 } 901 902 func strtbladd(name string) int { 903 off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table 904 strtbl = append(strtbl, name...) 905 strtbl = append(strtbl, 0) 906 return off 907 } 908 909 /* 910 * For more than 8 characters section names, name contains a slash (/) that is 911 * followed by an ASCII representation of a decimal number that is an offset into 912 * the string table. 913 * reference: pecoff_v8.docx Page 24. 914 * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx> 915 */ 916 func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER { 917 if size == 0 { 918 return nil 919 } 920 921 off := strtbladd(name) 922 s := fmt.Sprintf("/%d", off) 923 h := addpesection(s, int(size), int(size)) 924 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 925 926 return h 927 } 928 929 // writePESymTableRecords writes all COFF symbol table records. 930 // It returns number of records written. 931 func writePESymTableRecords() int { 932 var symcnt int 933 934 put := func(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) { 935 if s == nil { 936 return 937 } 938 if s.Sect == nil && type_ != 'U' { 939 return 940 } 941 switch type_ { 942 default: 943 return 944 case 'D', 'B', 'T', 'U': 945 } 946 947 // only windows/386 requires underscore prefix on external symbols 948 if SysArch.Family == sys.I386 && 949 Linkmode == LinkExternal && 950 (s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) && 951 s.Name == s.Extname && 952 s.Name != "_main" { 953 s.Name = "_" + s.Name 954 } 955 956 var typ uint16 957 var sect int 958 var value int64 959 // Note: although address of runtime.edata (type SDATA) is at the start of .bss section 960 // it still belongs to the .data section, not the .bss section. 961 if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal { 962 value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen) 963 sect = bsssect 964 } else if uint64(s.Value) >= Segdata.Vaddr { 965 value = int64(uint64(s.Value) - Segdata.Vaddr) 966 sect = datasect 967 } else if uint64(s.Value) >= Segtext.Vaddr { 968 value = int64(uint64(s.Value) - Segtext.Vaddr) 969 sect = textsect 970 } else if type_ == 'U' { 971 typ = IMAGE_SYM_DTYPE_FUNCTION 972 } else { 973 Diag("addpesym %#x", addr) 974 } 975 976 // write COFF symbol table record 977 if len(s.Name) > 8 { 978 Lputl(0) 979 Lputl(uint32(strtbladd(s.Name))) 980 } else { 981 strnput(s.Name, 8) 982 } 983 Lputl(uint32(value)) 984 Wputl(uint16(sect)) 985 if typ != 0 { 986 Wputl(typ) 987 } else if Linkmode == LinkExternal { 988 Wputl(0) 989 } else { 990 Wputl(0x0308) // "array of structs" 991 } 992 Cput(2) // storage class: external 993 Cput(0) // no aux entries 994 995 s.Dynid = int32(symcnt) 996 997 symcnt++ 998 } 999 1000 if Linkmode == LinkExternal { 1001 for d := dr; d != nil; d = d.next { 1002 for m := d.ms; m != nil; m = m.next { 1003 s := m.s.R[0].Xsym 1004 put(s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil) 1005 } 1006 } 1007 1008 s := Linklookup(Ctxt, ".text", 0) 1009 if s.Type == obj.STEXT { 1010 put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil) 1011 } 1012 } 1013 1014 genasmsym(put) 1015 1016 return symcnt 1017 } 1018 1019 func addpesymtable() { 1020 symtabStartPos := Cpos() 1021 1022 // write COFF symbol table 1023 var symcnt int 1024 if Debug['s'] == 0 || Linkmode == LinkExternal { 1025 symcnt = writePESymTableRecords() 1026 } 1027 1028 // update COFF file header and section table 1029 size := len(strtbl) + 4 + 18*symcnt 1030 var h *IMAGE_SECTION_HEADER 1031 if Linkmode != LinkExternal { 1032 // We do not really need .symtab for go.o, and if we have one, ld 1033 // will also include it in the exe, and that will confuse windows. 1034 h = addpesection(".symtab", size, size) 1035 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 1036 chksectoff(h, symtabStartPos) 1037 } 1038 fh.PointerToSymbolTable = uint32(symtabStartPos) 1039 fh.NumberOfSymbols = uint32(symcnt) 1040 1041 // write COFF string table 1042 Lputl(uint32(len(strtbl)) + 4) 1043 for i := 0; i < len(strtbl); i++ { 1044 Cput(strtbl[i]) 1045 } 1046 if Linkmode != LinkExternal { 1047 strnput("", int(h.SizeOfRawData-uint32(size))) 1048 } 1049 } 1050 1051 func setpersrc(sym *LSym) { 1052 if rsrcsym != nil { 1053 Diag("too many .rsrc sections") 1054 } 1055 1056 rsrcsym = sym 1057 } 1058 1059 func addpersrc() { 1060 if rsrcsym == nil { 1061 return 1062 } 1063 1064 h := addpesection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size)) 1065 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA 1066 chksectoff(h, Cpos()) 1067 1068 // relocation 1069 var p []byte 1070 var r *Reloc 1071 var val uint32 1072 for ri := 0; ri < len(rsrcsym.R); ri++ { 1073 r = &rsrcsym.R[ri] 1074 p = rsrcsym.P[r.Off:] 1075 val = uint32(int64(h.VirtualAddress) + r.Add) 1076 1077 // 32-bit little-endian 1078 p[0] = byte(val) 1079 1080 p[1] = byte(val >> 8) 1081 p[2] = byte(val >> 16) 1082 p[3] = byte(val >> 24) 1083 } 1084 1085 Cwrite(rsrcsym.P) 1086 strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size)) 1087 1088 // update data directory 1089 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress 1090 1091 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize 1092 } 1093 1094 func addinitarray() (c *IMAGE_SECTION_HEADER) { 1095 // The size below was determined by the specification for array relocations, 1096 // and by observing what GCC writes here. If the initarray section grows to 1097 // contain more than one constructor entry, the size will need to be 8 * constructor_count. 1098 // However, the entire Go runtime is initialized from just one function, so it is unlikely 1099 // that this will need to grow in the future. 1100 var size int 1101 switch obj.Getgoarch() { 1102 default: 1103 fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch()) 1104 os.Exit(2) 1105 case "386": 1106 size = 4 1107 case "amd64": 1108 size = 8 1109 } 1110 1111 c = addpesection(".ctors", size, size) 1112 c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1113 c.SizeOfRawData = uint32(size) 1114 1115 Cseek(int64(c.PointerToRawData)) 1116 chksectoff(c, Cpos()) 1117 init_entry := Linklookup(Ctxt, INITENTRY, 0) 1118 addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr 1119 1120 switch obj.Getgoarch() { 1121 case "386": 1122 Lputl(uint32(addr)) 1123 case "amd64": 1124 Vputl(addr) 1125 } 1126 1127 return c 1128 } 1129 1130 func Asmbpe() { 1131 switch SysArch.Family { 1132 default: 1133 Exitf("unknown PE architecture: %v", SysArch.Family) 1134 case sys.AMD64: 1135 fh.Machine = IMAGE_FILE_MACHINE_AMD64 1136 case sys.I386: 1137 fh.Machine = IMAGE_FILE_MACHINE_I386 1138 } 1139 1140 t := addpesection(".text", int(Segtext.Length), int(Segtext.Length)) 1141 t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ 1142 if Linkmode == LinkExternal { 1143 // some data symbols (e.g. masks) end up in the .text section, and they normally 1144 // expect larger alignment requirement than the default text section alignment. 1145 t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES 1146 } 1147 chksectseg(t, &Segtext) 1148 textsect = pensect 1149 1150 var d *IMAGE_SECTION_HEADER 1151 var c *IMAGE_SECTION_HEADER 1152 if Linkmode != LinkExternal { 1153 d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen)) 1154 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1155 chksectseg(d, &Segdata) 1156 datasect = pensect 1157 } else { 1158 d = addpesection(".data", int(Segdata.Filelen), int(Segdata.Filelen)) 1159 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1160 chksectseg(d, &Segdata) 1161 datasect = pensect 1162 1163 b := addpesection(".bss", int(Segdata.Length-Segdata.Filelen), 0) 1164 b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1165 b.PointerToRawData = 0 1166 bsssect = pensect 1167 1168 c = addinitarray() 1169 } 1170 1171 if Debug['s'] == 0 { 1172 dwarfaddpeheaders() 1173 } 1174 1175 Cseek(int64(nextfileoff)) 1176 if Linkmode != LinkExternal { 1177 addimports(d) 1178 addexports() 1179 } 1180 addpesymtable() 1181 addpersrc() 1182 if Linkmode == LinkExternal { 1183 peemitreloc(t, d, c) 1184 } 1185 1186 fh.NumberOfSections = uint16(pensect) 1187 1188 // Being able to produce identical output for identical input is 1189 // much more beneficial than having build timestamp in the header. 1190 fh.TimeDateStamp = 0 1191 1192 if Linkmode == LinkExternal { 1193 fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED 1194 } else { 1195 fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED 1196 } 1197 if pe64 != 0 { 1198 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) 1199 fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE 1200 oh64.Magic = 0x20b // PE32+ 1201 } else { 1202 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh)) 1203 fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE 1204 oh.Magic = 0x10b // PE32 1205 oh.BaseOfData = d.VirtualAddress 1206 } 1207 1208 // Fill out both oh64 and oh. We only use one. Oh well. 1209 oh64.MajorLinkerVersion = 3 1210 1211 oh.MajorLinkerVersion = 3 1212 oh64.MinorLinkerVersion = 0 1213 oh.MinorLinkerVersion = 0 1214 oh64.SizeOfCode = t.SizeOfRawData 1215 oh.SizeOfCode = t.SizeOfRawData 1216 oh64.SizeOfInitializedData = d.SizeOfRawData 1217 oh.SizeOfInitializedData = d.SizeOfRawData 1218 oh64.SizeOfUninitializedData = 0 1219 oh.SizeOfUninitializedData = 0 1220 if Linkmode != LinkExternal { 1221 oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE) 1222 oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE) 1223 } 1224 oh64.BaseOfCode = t.VirtualAddress 1225 oh.BaseOfCode = t.VirtualAddress 1226 oh64.ImageBase = PEBASE 1227 oh.ImageBase = PEBASE 1228 oh64.SectionAlignment = PESECTALIGN 1229 oh.SectionAlignment = PESECTALIGN 1230 oh64.FileAlignment = PEFILEALIGN 1231 oh.FileAlignment = PEFILEALIGN 1232 oh64.MajorOperatingSystemVersion = 4 1233 oh.MajorOperatingSystemVersion = 4 1234 oh64.MinorOperatingSystemVersion = 0 1235 oh.MinorOperatingSystemVersion = 0 1236 oh64.MajorImageVersion = 1 1237 oh.MajorImageVersion = 1 1238 oh64.MinorImageVersion = 0 1239 oh.MinorImageVersion = 0 1240 oh64.MajorSubsystemVersion = 4 1241 oh.MajorSubsystemVersion = 4 1242 oh64.MinorSubsystemVersion = 0 1243 oh.MinorSubsystemVersion = 0 1244 oh64.SizeOfImage = uint32(nextsectoff) 1245 oh.SizeOfImage = uint32(nextsectoff) 1246 oh64.SizeOfHeaders = uint32(PEFILEHEADR) 1247 oh.SizeOfHeaders = uint32(PEFILEHEADR) 1248 if headstring == "windowsgui" { 1249 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1250 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1251 } else { 1252 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1253 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1254 } 1255 1256 // Disable stack growth as we don't want Windows to 1257 // fiddle with the thread stack limits, which we set 1258 // ourselves to circumvent the stack checks in the 1259 // Windows exception dispatcher. 1260 // Commit size must be strictly less than reserve 1261 // size otherwise reserve will be rounded up to a 1262 // larger size, as verified with VMMap. 1263 1264 // Go code would be OK with 64k stacks, but we need larger stacks for cgo. 1265 // 1266 // The default stack reserve size affects only the main 1267 // thread, ctrlhandler thread, and profileloop thread. For 1268 // these, it must be greater than the stack size assumed by 1269 // externalthreadhandler. 1270 // 1271 // For other threads we specify stack size in runtime explicitly 1272 // (runtime knows whether cgo is enabled or not). 1273 // For these, the reserve must match STACKSIZE in 1274 // runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent 1275 // CreateThread parameter in runtime.newosproc. 1276 if !iscgo { 1277 oh64.SizeOfStackReserve = 0x00020000 1278 oh.SizeOfStackReserve = 0x00020000 1279 oh64.SizeOfStackCommit = 0x00001000 1280 oh.SizeOfStackCommit = 0x00001000 1281 } else { 1282 oh64.SizeOfStackReserve = 0x00200000 1283 oh.SizeOfStackReserve = 0x00100000 1284 1285 // account for 2 guard pages 1286 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 1287 1288 oh.SizeOfStackCommit = 0x00100000 - 0x2000 1289 } 1290 1291 oh64.SizeOfHeapReserve = 0x00100000 1292 oh.SizeOfHeapReserve = 0x00100000 1293 oh64.SizeOfHeapCommit = 0x00001000 1294 oh.SizeOfHeapCommit = 0x00001000 1295 oh64.NumberOfRvaAndSizes = 16 1296 oh.NumberOfRvaAndSizes = 16 1297 1298 pewrite() 1299 }