github.com/muesli/go@v0.0.0-20170208044820-e410d2a81ef2/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 Errorf(nil, "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 Errorf(nil, "%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 Errorf(nil, "%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 Errorf(nil, "%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.Syms.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 Errorf(s, "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(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 := ctxt.Syms.Lookup(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 := ctxt.Syms.Lookup(".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 := ctxt.Syms.Lookup(".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.Syms.Allsym { 685 if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() { 686 continue 687 } 688 if nexport+1 > len(dexport) { 689 Errorf(s, "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 for ri := 0; ri < len(sym.R); ri++ { 794 r := &sym.R[ri] 795 if r.Done != 0 { 796 continue 797 } 798 if r.Xsym == nil { 799 Errorf(sym, "missing xsym in relocation") 800 continue 801 } 802 803 if r.Xsym.Dynid < 0 { 804 Errorf(sym, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type) 805 } 806 if !Thearch.PEreloc1(sym, r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) { 807 Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name) 808 } 809 810 relocs++ 811 } 812 } 813 814 sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff 815 816 return relocs 817 } 818 819 // peemitreloc emits relocation entries for go.o in external linking. 820 func peemitreloc(ctxt *Link, text, data, ctors *IMAGE_SECTION_HEADER) { 821 for coutbuf.Offset()&7 != 0 { 822 Cput(0) 823 } 824 825 text.PointerToRelocations = uint32(coutbuf.Offset()) 826 // first entry: extended relocs 827 Lputl(0) // placeholder for number of relocation + 1 828 Lputl(0) 829 Wputl(0) 830 831 n := perelocsect(ctxt, Segtext.Sect, ctxt.Textp) + 1 832 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { 833 n += perelocsect(ctxt, sect, datap) 834 } 835 836 cpos := coutbuf.Offset() 837 Cseek(int64(text.PointerToRelocations)) 838 Lputl(uint32(n)) 839 Cseek(cpos) 840 if n > 0x10000 { 841 n = 0x10000 842 text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 843 } else { 844 text.PointerToRelocations += 10 // skip the extend reloc entry 845 } 846 text.NumberOfRelocations = uint16(n - 1) 847 848 data.PointerToRelocations = uint32(cpos) 849 // first entry: extended relocs 850 Lputl(0) // placeholder for number of relocation + 1 851 Lputl(0) 852 Wputl(0) 853 854 n = 1 855 for sect := Segdata.Sect; sect != nil; sect = sect.Next { 856 n += perelocsect(ctxt, sect, datap) 857 } 858 859 cpos = coutbuf.Offset() 860 Cseek(int64(data.PointerToRelocations)) 861 Lputl(uint32(n)) 862 Cseek(cpos) 863 if n > 0x10000 { 864 n = 0x10000 865 data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 866 } else { 867 data.PointerToRelocations += 10 // skip the extend reloc entry 868 } 869 data.NumberOfRelocations = uint16(n - 1) 870 871 dottext := ctxt.Syms.Lookup(".text", 0) 872 ctors.NumberOfRelocations = 1 873 ctors.PointerToRelocations = uint32(coutbuf.Offset()) 874 sectoff := ctors.VirtualAddress 875 Lputl(sectoff) 876 Lputl(uint32(dottext.Dynid)) 877 switch obj.GOARCH { 878 default: 879 fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.GOARCH) 880 os.Exit(2) 881 case "386": 882 Wputl(IMAGE_REL_I386_DIR32) 883 case "amd64": 884 Wputl(IMAGE_REL_AMD64_ADDR64) 885 } 886 } 887 888 func (ctxt *Link) dope() { 889 /* relocation table */ 890 rel := ctxt.Syms.Lookup(".rel", 0) 891 892 rel.Attr |= AttrReachable 893 rel.Type = obj.SELFROSECT 894 895 initdynimport(ctxt) 896 initdynexport(ctxt) 897 } 898 899 func strtbladd(name string) int { 900 off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table 901 strtbl = append(strtbl, name...) 902 strtbl = append(strtbl, 0) 903 return off 904 } 905 906 /* 907 * For more than 8 characters section names, name contains a slash (/) that is 908 * followed by an ASCII representation of a decimal number that is an offset into 909 * the string table. 910 * reference: pecoff_v8.docx Page 24. 911 * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx> 912 */ 913 func newPEDWARFSection(ctxt *Link, name string, size int64) *IMAGE_SECTION_HEADER { 914 if size == 0 { 915 return nil 916 } 917 918 off := strtbladd(name) 919 s := fmt.Sprintf("/%d", off) 920 h := addpesection(ctxt, s, int(size), int(size)) 921 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 922 923 return h 924 } 925 926 // writePESymTableRecords writes all COFF symbol table records. 927 // It returns number of records written. 928 func writePESymTableRecords(ctxt *Link) int { 929 var symcnt int 930 931 put := func(ctxt *Link, s *Symbol, name string, type_ SymbolType, addr int64, gotype *Symbol) { 932 if s == nil { 933 return 934 } 935 if s.Sect == nil && type_ != UndefinedSym { 936 return 937 } 938 switch type_ { 939 default: 940 return 941 case DataSym, BSSSym, TextSym, UndefinedSym: 942 } 943 944 // Only windows/386 requires underscore prefix on external symbols. 945 // Include .text symbol as external, because .ctors section relocations refer to it. 946 if SysArch.Family == sys.I386 && 947 Linkmode == LinkExternal && 948 (s.Type == obj.SHOSTOBJ || 949 s.Attr.CgoExport() || 950 s.Name == ".text") { 951 s.Name = "_" + s.Name 952 } 953 954 var typ uint16 955 var sect int 956 var value int64 957 // Note: although address of runtime.edata (type SDATA) is at the start of .bss section 958 // it still belongs to the .data section, not the .bss section. 959 // Same for runtime.epclntab (type STEXT), it belongs to .text 960 // section, not the .data 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 && s.Type != obj.STEXT { 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_ == UndefinedSym { 971 typ = IMAGE_SYM_DTYPE_FUNCTION 972 } else { 973 Errorf(s, "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 s := ctxt.Syms.Lookup(".text", 0) 1002 if s.Type == obj.STEXT { 1003 put(ctxt, s, s.Name, TextSym, s.Value, nil) 1004 } 1005 } 1006 1007 genasmsym(ctxt, put) 1008 1009 return symcnt 1010 } 1011 1012 func addpesymtable(ctxt *Link) { 1013 symtabStartPos := coutbuf.Offset() 1014 1015 // write COFF symbol table 1016 var symcnt int 1017 if !*FlagS || Linkmode == LinkExternal { 1018 symcnt = writePESymTableRecords(ctxt) 1019 } 1020 1021 // update COFF file header and section table 1022 size := len(strtbl) + 4 + 18*symcnt 1023 var h *IMAGE_SECTION_HEADER 1024 if Linkmode != LinkExternal { 1025 // We do not really need .symtab for go.o, and if we have one, ld 1026 // will also include it in the exe, and that will confuse windows. 1027 h = addpesection(ctxt, ".symtab", size, size) 1028 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 1029 chksectoff(ctxt, h, symtabStartPos) 1030 } 1031 fh.PointerToSymbolTable = uint32(symtabStartPos) 1032 fh.NumberOfSymbols = uint32(symcnt) 1033 1034 // write COFF string table 1035 Lputl(uint32(len(strtbl)) + 4) 1036 for i := 0; i < len(strtbl); i++ { 1037 Cput(strtbl[i]) 1038 } 1039 if Linkmode != LinkExternal { 1040 strnput("", int(h.SizeOfRawData-uint32(size))) 1041 } 1042 } 1043 1044 func setpersrc(ctxt *Link, sym *Symbol) { 1045 if rsrcsym != nil { 1046 Errorf(sym, "too many .rsrc sections") 1047 } 1048 1049 rsrcsym = sym 1050 } 1051 1052 func addpersrc(ctxt *Link) { 1053 if rsrcsym == nil { 1054 return 1055 } 1056 1057 h := addpesection(ctxt, ".rsrc", int(rsrcsym.Size), int(rsrcsym.Size)) 1058 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA 1059 chksectoff(ctxt, h, coutbuf.Offset()) 1060 1061 // relocation 1062 var p []byte 1063 var r *Reloc 1064 var val uint32 1065 for ri := 0; ri < len(rsrcsym.R); ri++ { 1066 r = &rsrcsym.R[ri] 1067 p = rsrcsym.P[r.Off:] 1068 val = uint32(int64(h.VirtualAddress) + r.Add) 1069 1070 // 32-bit little-endian 1071 p[0] = byte(val) 1072 1073 p[1] = byte(val >> 8) 1074 p[2] = byte(val >> 16) 1075 p[3] = byte(val >> 24) 1076 } 1077 1078 Cwrite(rsrcsym.P) 1079 strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size)) 1080 1081 // update data directory 1082 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress 1083 1084 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize 1085 } 1086 1087 func addinitarray(ctxt *Link) (c *IMAGE_SECTION_HEADER) { 1088 // The size below was determined by the specification for array relocations, 1089 // and by observing what GCC writes here. If the initarray section grows to 1090 // contain more than one constructor entry, the size will need to be 8 * constructor_count. 1091 // However, the entire Go runtime is initialized from just one function, so it is unlikely 1092 // that this will need to grow in the future. 1093 var size int 1094 switch obj.GOARCH { 1095 default: 1096 fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.GOARCH) 1097 os.Exit(2) 1098 case "386": 1099 size = 4 1100 case "amd64": 1101 size = 8 1102 } 1103 1104 c = addpesection(ctxt, ".ctors", size, size) 1105 c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1106 c.SizeOfRawData = uint32(size) 1107 1108 Cseek(int64(c.PointerToRawData)) 1109 chksectoff(ctxt, c, coutbuf.Offset()) 1110 init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0) 1111 addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr 1112 1113 switch obj.GOARCH { 1114 case "386": 1115 Lputl(uint32(addr)) 1116 case "amd64": 1117 Vputl(addr) 1118 } 1119 1120 return c 1121 } 1122 1123 func Asmbpe(ctxt *Link) { 1124 switch SysArch.Family { 1125 default: 1126 Exitf("unknown PE architecture: %v", SysArch.Family) 1127 case sys.AMD64: 1128 fh.Machine = IMAGE_FILE_MACHINE_AMD64 1129 case sys.I386: 1130 fh.Machine = IMAGE_FILE_MACHINE_I386 1131 } 1132 1133 t := addpesection(ctxt, ".text", int(Segtext.Length), int(Segtext.Length)) 1134 t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ 1135 if Linkmode == LinkExternal { 1136 // some data symbols (e.g. masks) end up in the .text section, and they normally 1137 // expect larger alignment requirement than the default text section alignment. 1138 t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES 1139 } 1140 chksectseg(ctxt, t, &Segtext) 1141 textsect = pensect 1142 1143 var d *IMAGE_SECTION_HEADER 1144 var c *IMAGE_SECTION_HEADER 1145 if Linkmode != LinkExternal { 1146 d = addpesection(ctxt, ".data", int(Segdata.Length), int(Segdata.Filelen)) 1147 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1148 chksectseg(ctxt, d, &Segdata) 1149 datasect = pensect 1150 } else { 1151 d = addpesection(ctxt, ".data", int(Segdata.Filelen), int(Segdata.Filelen)) 1152 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1153 chksectseg(ctxt, d, &Segdata) 1154 datasect = pensect 1155 1156 b := addpesection(ctxt, ".bss", int(Segdata.Length-Segdata.Filelen), 0) 1157 b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1158 b.PointerToRawData = 0 1159 bsssect = pensect 1160 1161 c = addinitarray(ctxt) 1162 } 1163 1164 if !*FlagS { 1165 dwarfaddpeheaders(ctxt) 1166 } 1167 1168 Cseek(int64(nextfileoff)) 1169 if Linkmode != LinkExternal { 1170 addimports(ctxt, d) 1171 addexports(ctxt) 1172 } 1173 addpesymtable(ctxt) 1174 addpersrc(ctxt) 1175 if Linkmode == LinkExternal { 1176 peemitreloc(ctxt, t, d, c) 1177 } 1178 1179 fh.NumberOfSections = uint16(pensect) 1180 1181 // Being able to produce identical output for identical input is 1182 // much more beneficial than having build timestamp in the header. 1183 fh.TimeDateStamp = 0 1184 1185 if Linkmode == LinkExternal { 1186 fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED 1187 } else { 1188 fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED 1189 } 1190 if pe64 != 0 { 1191 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) 1192 fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE 1193 oh64.Magic = 0x20b // PE32+ 1194 } else { 1195 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh)) 1196 fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE 1197 oh.Magic = 0x10b // PE32 1198 oh.BaseOfData = d.VirtualAddress 1199 } 1200 1201 // Fill out both oh64 and oh. We only use one. Oh well. 1202 oh64.MajorLinkerVersion = 3 1203 1204 oh.MajorLinkerVersion = 3 1205 oh64.MinorLinkerVersion = 0 1206 oh.MinorLinkerVersion = 0 1207 oh64.SizeOfCode = t.SizeOfRawData 1208 oh.SizeOfCode = t.SizeOfRawData 1209 oh64.SizeOfInitializedData = d.SizeOfRawData 1210 oh.SizeOfInitializedData = d.SizeOfRawData 1211 oh64.SizeOfUninitializedData = 0 1212 oh.SizeOfUninitializedData = 0 1213 if Linkmode != LinkExternal { 1214 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 1215 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 1216 } 1217 oh64.BaseOfCode = t.VirtualAddress 1218 oh.BaseOfCode = t.VirtualAddress 1219 oh64.ImageBase = PEBASE 1220 oh.ImageBase = PEBASE 1221 oh64.SectionAlignment = PESECTALIGN 1222 oh.SectionAlignment = PESECTALIGN 1223 oh64.FileAlignment = PEFILEALIGN 1224 oh.FileAlignment = PEFILEALIGN 1225 oh64.MajorOperatingSystemVersion = 4 1226 oh.MajorOperatingSystemVersion = 4 1227 oh64.MinorOperatingSystemVersion = 0 1228 oh.MinorOperatingSystemVersion = 0 1229 oh64.MajorImageVersion = 1 1230 oh.MajorImageVersion = 1 1231 oh64.MinorImageVersion = 0 1232 oh.MinorImageVersion = 0 1233 oh64.MajorSubsystemVersion = 4 1234 oh.MajorSubsystemVersion = 4 1235 oh64.MinorSubsystemVersion = 0 1236 oh.MinorSubsystemVersion = 0 1237 oh64.SizeOfImage = uint32(nextsectoff) 1238 oh.SizeOfImage = uint32(nextsectoff) 1239 oh64.SizeOfHeaders = uint32(PEFILEHEADR) 1240 oh.SizeOfHeaders = uint32(PEFILEHEADR) 1241 if Headtype == obj.Hwindowsgui { 1242 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1243 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1244 } else { 1245 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1246 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1247 } 1248 1249 // Disable stack growth as we don't want Windows to 1250 // fiddle with the thread stack limits, which we set 1251 // ourselves to circumvent the stack checks in the 1252 // Windows exception dispatcher. 1253 // Commit size must be strictly less than reserve 1254 // size otherwise reserve will be rounded up to a 1255 // larger size, as verified with VMMap. 1256 1257 // Go code would be OK with 64k stacks, but we need larger stacks for cgo. 1258 // 1259 // The default stack reserve size affects only the main 1260 // thread, ctrlhandler thread, and profileloop thread. For 1261 // these, it must be greater than the stack size assumed by 1262 // externalthreadhandler. 1263 // 1264 // For other threads we specify stack size in runtime explicitly 1265 // (runtime knows whether cgo is enabled or not). 1266 // For these, the reserve must match STACKSIZE in 1267 // runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent 1268 // CreateThread parameter in runtime.newosproc. 1269 if !iscgo { 1270 oh64.SizeOfStackReserve = 0x00020000 1271 oh.SizeOfStackReserve = 0x00020000 1272 oh64.SizeOfStackCommit = 0x00001000 1273 oh.SizeOfStackCommit = 0x00001000 1274 } else { 1275 oh64.SizeOfStackReserve = 0x00200000 1276 oh.SizeOfStackReserve = 0x00100000 1277 1278 // account for 2 guard pages 1279 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 1280 1281 oh.SizeOfStackCommit = 0x00100000 - 0x2000 1282 } 1283 1284 oh64.SizeOfHeapReserve = 0x00100000 1285 oh.SizeOfHeapReserve = 0x00100000 1286 oh64.SizeOfHeapCommit = 0x00001000 1287 oh.SizeOfHeapCommit = 0x00001000 1288 oh64.NumberOfRvaAndSizes = 16 1289 oh.NumberOfRvaAndSizes = 16 1290 1291 pewrite() 1292 }