github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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 *Symbol 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 *Symbol 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]*Symbol 377 378 var nexport int 379 380 func addpesection(ctxt *Link, name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER { 381 if pensect == 16 { 382 ctxt.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(ctxt *Link, h *IMAGE_SECTION_HEADER, off int64) { 402 if off != int64(h.PointerToRawData) { 403 ctxt.Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off)) 404 errorexit() 405 } 406 } 407 408 func chksectseg(ctxt *Link, h *IMAGE_SECTION_HEADER, s *Segment) { 409 if s.Vaddr-PEBASE != uint64(h.VirtualAddress) { 410 ctxt.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 ctxt.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(ctxt *Link) { 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 ctxt.xdefine("__image_base__", obj.SDATA, PEBASE) 445 446 ctxt.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(ctxt *Link) *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 ctxt.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(ctxt *Link, datsect *IMAGE_SECTION_HEADER) { 573 startoff := coutbuf.Offset() 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(coutbuf.Offset()) - 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(coutbuf.Offset()) - uint64(startoff) 595 Wputl(0) // hint 596 strput(m.s.Extname) 597 } 598 } 599 600 // write OriginalFirstThunks 601 oftbase := uint64(coutbuf.Offset()) - uint64(startoff) 602 603 n = uint64(coutbuf.Offset()) 604 for d := dr; d != nil; d = d.next { 605 d.thunkoff = uint64(coutbuf.Offset()) - 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(coutbuf.Offset()) - uint64(startoff) 623 624 isect := addpesection(ctxt, ".idata", int(n), int(n)) 625 isect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 626 chksectoff(ctxt, isect, startoff) 627 strnput("", int(uint64(isect.SizeOfRawData)-n)) 628 endoff := coutbuf.Offset() 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 dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.VirtualSize 670 dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE) 671 dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size) 672 673 Cseek(endoff) 674 } 675 676 type byExtname []*Symbol 677 678 func (s byExtname) Len() int { return len(s) } 679 func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 680 func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname } 681 682 func initdynexport(ctxt *Link) { 683 nexport = 0 684 for _, s := range ctxt.Allsym { 685 if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() { 686 continue 687 } 688 if nexport+1 > len(dexport) { 689 ctxt.Diag("pe dynexport table is full") 690 errorexit() 691 } 692 693 dexport[nexport] = s 694 nexport++ 695 } 696 697 sort.Sort(byExtname(dexport[:nexport])) 698 } 699 700 func addexports(ctxt *Link) { 701 var e IMAGE_EXPORT_DIRECTORY 702 703 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1 704 for i := 0; i < nexport; i++ { 705 size += len(dexport[i].Extname) + 1 706 } 707 708 if nexport == 0 { 709 return 710 } 711 712 sect := addpesection(ctxt, ".edata", size, size) 713 sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 714 chksectoff(ctxt, sect, coutbuf.Offset()) 715 va := int(sect.VirtualAddress) 716 dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va) 717 dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.VirtualSize 718 719 vaName := va + binary.Size(&e) + nexport*4 720 vaAddr := va + binary.Size(&e) 721 vaNa := va + binary.Size(&e) + nexport*8 722 723 e.Characteristics = 0 724 e.MajorVersion = 0 725 e.MinorVersion = 0 726 e.NumberOfFunctions = uint32(nexport) 727 e.NumberOfNames = uint32(nexport) 728 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names. 729 e.Base = 1 730 e.AddressOfFunctions = uint32(vaAddr) 731 e.AddressOfNames = uint32(vaName) 732 e.AddressOfNameOrdinals = uint32(vaNa) 733 734 // put IMAGE_EXPORT_DIRECTORY 735 binary.Write(&coutbuf, binary.LittleEndian, &e) 736 737 // put EXPORT Address Table 738 for i := 0; i < nexport; i++ { 739 Lputl(uint32(dexport[i].Value - PEBASE)) 740 } 741 742 // put EXPORT Name Pointer Table 743 v := int(e.Name + uint32(len(*flagOutfile)) + 1) 744 745 for i := 0; i < nexport; i++ { 746 Lputl(uint32(v)) 747 v += len(dexport[i].Extname) + 1 748 } 749 750 // put EXPORT Ordinal Table 751 for i := 0; i < nexport; i++ { 752 Wputl(uint16(i)) 753 } 754 755 // put Names 756 strnput(*flagOutfile, len(*flagOutfile)+1) 757 758 for i := 0; i < nexport; i++ { 759 strnput(dexport[i].Extname, len(dexport[i].Extname)+1) 760 } 761 strnput("", int(sect.SizeOfRawData-uint32(size))) 762 } 763 764 // perelocsect relocates symbols from first in section sect, and returns 765 // the total number of relocations emitted. 766 func perelocsect(ctxt *Link, sect *Section, syms []*Symbol) int { 767 // If main section has no bits, nothing to relocate. 768 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 769 return 0 770 } 771 772 relocs := 0 773 774 sect.Reloff = uint64(coutbuf.Offset()) 775 for i, s := range syms { 776 if !s.Attr.Reachable() { 777 continue 778 } 779 if uint64(s.Value) >= sect.Vaddr { 780 syms = syms[i:] 781 break 782 } 783 } 784 785 eaddr := int32(sect.Vaddr + sect.Length) 786 for _, sym := range syms { 787 if !sym.Attr.Reachable() { 788 continue 789 } 790 if sym.Value >= int64(eaddr) { 791 break 792 } 793 ctxt.Cursym = sym 794 795 for ri := 0; ri < len(sym.R); ri++ { 796 r := &sym.R[ri] 797 if r.Done != 0 { 798 continue 799 } 800 if r.Xsym == nil { 801 ctxt.Diag("missing xsym in relocation") 802 continue 803 } 804 805 if r.Xsym.Dynid < 0 { 806 ctxt.Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type) 807 } 808 if !Thearch.PEreloc1(ctxt, r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) { 809 ctxt.Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name) 810 } 811 812 relocs++ 813 } 814 } 815 816 sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff 817 818 return relocs 819 } 820 821 // peemitreloc emits relocation entries for go.o in external linking. 822 func peemitreloc(ctxt *Link, text, data, ctors *IMAGE_SECTION_HEADER) { 823 for coutbuf.Offset()&7 != 0 { 824 Cput(0) 825 } 826 827 text.PointerToRelocations = uint32(coutbuf.Offset()) 828 // first entry: extended relocs 829 Lputl(0) // placeholder for number of relocation + 1 830 Lputl(0) 831 Wputl(0) 832 833 n := perelocsect(ctxt, Segtext.Sect, ctxt.Textp) + 1 834 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { 835 n += perelocsect(ctxt, sect, datap) 836 } 837 838 cpos := coutbuf.Offset() 839 Cseek(int64(text.PointerToRelocations)) 840 Lputl(uint32(n)) 841 Cseek(cpos) 842 if n > 0x10000 { 843 n = 0x10000 844 text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 845 } else { 846 text.PointerToRelocations += 10 // skip the extend reloc entry 847 } 848 text.NumberOfRelocations = uint16(n - 1) 849 850 data.PointerToRelocations = uint32(cpos) 851 // first entry: extended relocs 852 Lputl(0) // placeholder for number of relocation + 1 853 Lputl(0) 854 Wputl(0) 855 856 n = 1 857 for sect := Segdata.Sect; sect != nil; sect = sect.Next { 858 n += perelocsect(ctxt, sect, datap) 859 } 860 861 cpos = coutbuf.Offset() 862 Cseek(int64(data.PointerToRelocations)) 863 Lputl(uint32(n)) 864 Cseek(cpos) 865 if n > 0x10000 { 866 n = 0x10000 867 data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 868 } else { 869 data.PointerToRelocations += 10 // skip the extend reloc entry 870 } 871 data.NumberOfRelocations = uint16(n - 1) 872 873 dottext := Linklookup(ctxt, ".text", 0) 874 ctors.NumberOfRelocations = 1 875 ctors.PointerToRelocations = uint32(coutbuf.Offset()) 876 sectoff := ctors.VirtualAddress 877 Lputl(sectoff) 878 Lputl(uint32(dottext.Dynid)) 879 switch obj.Getgoarch() { 880 default: 881 fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch()) 882 os.Exit(2) 883 case "386": 884 Wputl(IMAGE_REL_I386_DIR32) 885 case "amd64": 886 Wputl(IMAGE_REL_AMD64_ADDR64) 887 } 888 } 889 890 func (ctxt *Link) dope() { 891 /* relocation table */ 892 rel := Linklookup(ctxt, ".rel", 0) 893 894 rel.Attr |= AttrReachable 895 rel.Type = obj.SELFROSECT 896 897 initdynimport(ctxt) 898 initdynexport(ctxt) 899 } 900 901 func strtbladd(name string) int { 902 off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table 903 strtbl = append(strtbl, name...) 904 strtbl = append(strtbl, 0) 905 return off 906 } 907 908 /* 909 * For more than 8 characters section names, name contains a slash (/) that is 910 * followed by an ASCII representation of a decimal number that is an offset into 911 * the string table. 912 * reference: pecoff_v8.docx Page 24. 913 * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx> 914 */ 915 func newPEDWARFSection(ctxt *Link, name string, size int64) *IMAGE_SECTION_HEADER { 916 if size == 0 { 917 return nil 918 } 919 920 off := strtbladd(name) 921 s := fmt.Sprintf("/%d", off) 922 h := addpesection(ctxt, s, int(size), int(size)) 923 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 924 925 return h 926 } 927 928 // writePESymTableRecords writes all COFF symbol table records. 929 // It returns number of records written. 930 func writePESymTableRecords(ctxt *Link) int { 931 var symcnt int 932 933 put := func(ctxt *Link, s *Symbol, name string, type_ int, addr int64, size int64, ver int, gotype *Symbol) { 934 if s == nil { 935 return 936 } 937 if s.Sect == nil && type_ != 'U' { 938 return 939 } 940 switch type_ { 941 default: 942 return 943 case 'D', 'B', 'T', 'U': 944 } 945 946 // only windows/386 requires underscore prefix on external symbols 947 if SysArch.Family == sys.I386 && 948 Linkmode == LinkExternal && 949 (s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) && 950 s.Name == s.Extname && 951 s.Name != "_main" { 952 s.Name = "_" + s.Name 953 } 954 955 var typ uint16 956 var sect int 957 var value int64 958 // Note: although address of runtime.edata (type SDATA) is at the start of .bss section 959 // it still belongs to the .data section, not the .bss section. 960 if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal { 961 value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen) 962 sect = bsssect 963 } else if uint64(s.Value) >= Segdata.Vaddr { 964 value = int64(uint64(s.Value) - Segdata.Vaddr) 965 sect = datasect 966 } else if uint64(s.Value) >= Segtext.Vaddr { 967 value = int64(uint64(s.Value) - Segtext.Vaddr) 968 sect = textsect 969 } else if type_ == 'U' { 970 typ = IMAGE_SYM_DTYPE_FUNCTION 971 } else { 972 ctxt.Diag("addpesym %#x", addr) 973 } 974 975 // write COFF symbol table record 976 if len(s.Name) > 8 { 977 Lputl(0) 978 Lputl(uint32(strtbladd(s.Name))) 979 } else { 980 strnput(s.Name, 8) 981 } 982 Lputl(uint32(value)) 983 Wputl(uint16(sect)) 984 if typ != 0 { 985 Wputl(typ) 986 } else if Linkmode == LinkExternal { 987 Wputl(0) 988 } else { 989 Wputl(0x0308) // "array of structs" 990 } 991 Cput(2) // storage class: external 992 Cput(0) // no aux entries 993 994 s.Dynid = int32(symcnt) 995 996 symcnt++ 997 } 998 999 if Linkmode == LinkExternal { 1000 for d := dr; d != nil; d = d.next { 1001 for m := d.ms; m != nil; m = m.next { 1002 s := m.s.R[0].Xsym 1003 put(ctxt, s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil) 1004 } 1005 } 1006 1007 s := Linklookup(ctxt, ".text", 0) 1008 if s.Type == obj.STEXT { 1009 put(ctxt, s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil) 1010 } 1011 } 1012 1013 genasmsym(ctxt, put) 1014 1015 return symcnt 1016 } 1017 1018 func addpesymtable(ctxt *Link) { 1019 symtabStartPos := coutbuf.Offset() 1020 1021 // write COFF symbol table 1022 var symcnt int 1023 if !*FlagS || Linkmode == LinkExternal { 1024 symcnt = writePESymTableRecords(ctxt) 1025 } 1026 1027 // update COFF file header and section table 1028 size := len(strtbl) + 4 + 18*symcnt 1029 var h *IMAGE_SECTION_HEADER 1030 if Linkmode != LinkExternal { 1031 // We do not really need .symtab for go.o, and if we have one, ld 1032 // will also include it in the exe, and that will confuse windows. 1033 h = addpesection(ctxt, ".symtab", size, size) 1034 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 1035 chksectoff(ctxt, h, symtabStartPos) 1036 } 1037 fh.PointerToSymbolTable = uint32(symtabStartPos) 1038 fh.NumberOfSymbols = uint32(symcnt) 1039 1040 // write COFF string table 1041 Lputl(uint32(len(strtbl)) + 4) 1042 for i := 0; i < len(strtbl); i++ { 1043 Cput(strtbl[i]) 1044 } 1045 if Linkmode != LinkExternal { 1046 strnput("", int(h.SizeOfRawData-uint32(size))) 1047 } 1048 } 1049 1050 func setpersrc(ctxt *Link, sym *Symbol) { 1051 if rsrcsym != nil { 1052 ctxt.Diag("too many .rsrc sections") 1053 } 1054 1055 rsrcsym = sym 1056 } 1057 1058 func addpersrc(ctxt *Link) { 1059 if rsrcsym == nil { 1060 return 1061 } 1062 1063 h := addpesection(ctxt, ".rsrc", int(rsrcsym.Size), int(rsrcsym.Size)) 1064 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA 1065 chksectoff(ctxt, h, coutbuf.Offset()) 1066 1067 // relocation 1068 var p []byte 1069 var r *Reloc 1070 var val uint32 1071 for ri := 0; ri < len(rsrcsym.R); ri++ { 1072 r = &rsrcsym.R[ri] 1073 p = rsrcsym.P[r.Off:] 1074 val = uint32(int64(h.VirtualAddress) + r.Add) 1075 1076 // 32-bit little-endian 1077 p[0] = byte(val) 1078 1079 p[1] = byte(val >> 8) 1080 p[2] = byte(val >> 16) 1081 p[3] = byte(val >> 24) 1082 } 1083 1084 Cwrite(rsrcsym.P) 1085 strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size)) 1086 1087 // update data directory 1088 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress 1089 1090 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize 1091 } 1092 1093 func addinitarray(ctxt *Link) (c *IMAGE_SECTION_HEADER) { 1094 // The size below was determined by the specification for array relocations, 1095 // and by observing what GCC writes here. If the initarray section grows to 1096 // contain more than one constructor entry, the size will need to be 8 * constructor_count. 1097 // However, the entire Go runtime is initialized from just one function, so it is unlikely 1098 // that this will need to grow in the future. 1099 var size int 1100 switch obj.Getgoarch() { 1101 default: 1102 fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch()) 1103 os.Exit(2) 1104 case "386": 1105 size = 4 1106 case "amd64": 1107 size = 8 1108 } 1109 1110 c = addpesection(ctxt, ".ctors", size, size) 1111 c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1112 c.SizeOfRawData = uint32(size) 1113 1114 Cseek(int64(c.PointerToRawData)) 1115 chksectoff(ctxt, c, coutbuf.Offset()) 1116 init_entry := Linklookup(ctxt, *flagEntrySymbol, 0) 1117 addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr 1118 1119 switch obj.Getgoarch() { 1120 case "386": 1121 Lputl(uint32(addr)) 1122 case "amd64": 1123 Vputl(addr) 1124 } 1125 1126 return c 1127 } 1128 1129 func Asmbpe(ctxt *Link) { 1130 switch SysArch.Family { 1131 default: 1132 Exitf("unknown PE architecture: %v", SysArch.Family) 1133 case sys.AMD64: 1134 fh.Machine = IMAGE_FILE_MACHINE_AMD64 1135 case sys.I386: 1136 fh.Machine = IMAGE_FILE_MACHINE_I386 1137 } 1138 1139 t := addpesection(ctxt, ".text", int(Segtext.Length), int(Segtext.Length)) 1140 t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ 1141 if Linkmode == LinkExternal { 1142 // some data symbols (e.g. masks) end up in the .text section, and they normally 1143 // expect larger alignment requirement than the default text section alignment. 1144 t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES 1145 } 1146 chksectseg(ctxt, t, &Segtext) 1147 textsect = pensect 1148 1149 var d *IMAGE_SECTION_HEADER 1150 var c *IMAGE_SECTION_HEADER 1151 if Linkmode != LinkExternal { 1152 d = addpesection(ctxt, ".data", int(Segdata.Length), int(Segdata.Filelen)) 1153 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1154 chksectseg(ctxt, d, &Segdata) 1155 datasect = pensect 1156 } else { 1157 d = addpesection(ctxt, ".data", int(Segdata.Filelen), int(Segdata.Filelen)) 1158 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1159 chksectseg(ctxt, d, &Segdata) 1160 datasect = pensect 1161 1162 b := addpesection(ctxt, ".bss", int(Segdata.Length-Segdata.Filelen), 0) 1163 b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1164 b.PointerToRawData = 0 1165 bsssect = pensect 1166 1167 c = addinitarray(ctxt) 1168 } 1169 1170 if !*FlagS { 1171 dwarfaddpeheaders(ctxt) 1172 } 1173 1174 Cseek(int64(nextfileoff)) 1175 if Linkmode != LinkExternal { 1176 addimports(ctxt, d) 1177 addexports(ctxt) 1178 } 1179 addpesymtable(ctxt) 1180 addpersrc(ctxt) 1181 if Linkmode == LinkExternal { 1182 peemitreloc(ctxt, t, d, c) 1183 } 1184 1185 fh.NumberOfSections = uint16(pensect) 1186 1187 // Being able to produce identical output for identical input is 1188 // much more beneficial than having build timestamp in the header. 1189 fh.TimeDateStamp = 0 1190 1191 if Linkmode == LinkExternal { 1192 fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED 1193 } else { 1194 fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED 1195 } 1196 if pe64 != 0 { 1197 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) 1198 fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE 1199 oh64.Magic = 0x20b // PE32+ 1200 } else { 1201 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh)) 1202 fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE 1203 oh.Magic = 0x10b // PE32 1204 oh.BaseOfData = d.VirtualAddress 1205 } 1206 1207 // Fill out both oh64 and oh. We only use one. Oh well. 1208 oh64.MajorLinkerVersion = 3 1209 1210 oh.MajorLinkerVersion = 3 1211 oh64.MinorLinkerVersion = 0 1212 oh.MinorLinkerVersion = 0 1213 oh64.SizeOfCode = t.SizeOfRawData 1214 oh.SizeOfCode = t.SizeOfRawData 1215 oh64.SizeOfInitializedData = d.SizeOfRawData 1216 oh.SizeOfInitializedData = d.SizeOfRawData 1217 oh64.SizeOfUninitializedData = 0 1218 oh.SizeOfUninitializedData = 0 1219 if Linkmode != LinkExternal { 1220 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 1221 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 1222 } 1223 oh64.BaseOfCode = t.VirtualAddress 1224 oh.BaseOfCode = t.VirtualAddress 1225 oh64.ImageBase = PEBASE 1226 oh.ImageBase = PEBASE 1227 oh64.SectionAlignment = PESECTALIGN 1228 oh.SectionAlignment = PESECTALIGN 1229 oh64.FileAlignment = PEFILEALIGN 1230 oh.FileAlignment = PEFILEALIGN 1231 oh64.MajorOperatingSystemVersion = 4 1232 oh.MajorOperatingSystemVersion = 4 1233 oh64.MinorOperatingSystemVersion = 0 1234 oh.MinorOperatingSystemVersion = 0 1235 oh64.MajorImageVersion = 1 1236 oh.MajorImageVersion = 1 1237 oh64.MinorImageVersion = 0 1238 oh.MinorImageVersion = 0 1239 oh64.MajorSubsystemVersion = 4 1240 oh.MajorSubsystemVersion = 4 1241 oh64.MinorSubsystemVersion = 0 1242 oh.MinorSubsystemVersion = 0 1243 oh64.SizeOfImage = uint32(nextsectoff) 1244 oh.SizeOfImage = uint32(nextsectoff) 1245 oh64.SizeOfHeaders = uint32(PEFILEHEADR) 1246 oh.SizeOfHeaders = uint32(PEFILEHEADR) 1247 if headstring == "windowsgui" { 1248 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1249 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1250 } else { 1251 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1252 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1253 } 1254 1255 // Disable stack growth as we don't want Windows to 1256 // fiddle with the thread stack limits, which we set 1257 // ourselves to circumvent the stack checks in the 1258 // Windows exception dispatcher. 1259 // Commit size must be strictly less than reserve 1260 // size otherwise reserve will be rounded up to a 1261 // larger size, as verified with VMMap. 1262 1263 // Go code would be OK with 64k stacks, but we need larger stacks for cgo. 1264 // 1265 // The default stack reserve size affects only the main 1266 // thread, ctrlhandler thread, and profileloop thread. For 1267 // these, it must be greater than the stack size assumed by 1268 // externalthreadhandler. 1269 // 1270 // For other threads we specify stack size in runtime explicitly 1271 // (runtime knows whether cgo is enabled or not). 1272 // For these, the reserve must match STACKSIZE in 1273 // runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent 1274 // CreateThread parameter in runtime.newosproc. 1275 if !iscgo { 1276 oh64.SizeOfStackReserve = 0x00020000 1277 oh.SizeOfStackReserve = 0x00020000 1278 oh64.SizeOfStackCommit = 0x00001000 1279 oh.SizeOfStackCommit = 0x00001000 1280 } else { 1281 oh64.SizeOfStackReserve = 0x00200000 1282 oh.SizeOfStackReserve = 0x00100000 1283 1284 // account for 2 guard pages 1285 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 1286 1287 oh.SizeOfStackCommit = 0x00100000 - 0x2000 1288 } 1289 1290 oh64.SizeOfHeapReserve = 0x00100000 1291 oh.SizeOfHeapReserve = 0x00100000 1292 oh64.SizeOfHeapCommit = 0x00001000 1293 oh.SizeOfHeapCommit = 0x00001000 1294 oh64.NumberOfRvaAndSizes = 16 1295 oh.NumberOfRvaAndSizes = 16 1296 1297 pewrite() 1298 }