github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 if SysArch.Family == sys.I386 && 946 Linkmode == LinkExternal && 947 (s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) && 948 s.Name == s.Extname && 949 s.Name != "_main" { 950 s.Name = "_" + s.Name 951 } 952 953 var typ uint16 954 var sect int 955 var value int64 956 // Note: although address of runtime.edata (type SDATA) is at the start of .bss section 957 // it still belongs to the .data section, not the .bss section. 958 if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal { 959 value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen) 960 sect = bsssect 961 } else if uint64(s.Value) >= Segdata.Vaddr { 962 value = int64(uint64(s.Value) - Segdata.Vaddr) 963 sect = datasect 964 } else if uint64(s.Value) >= Segtext.Vaddr { 965 value = int64(uint64(s.Value) - Segtext.Vaddr) 966 sect = textsect 967 } else if type_ == UndefinedSym { 968 typ = IMAGE_SYM_DTYPE_FUNCTION 969 } else { 970 Errorf(s, "addpesym %#x", addr) 971 } 972 973 // write COFF symbol table record 974 if len(s.Name) > 8 { 975 Lputl(0) 976 Lputl(uint32(strtbladd(s.Name))) 977 } else { 978 strnput(s.Name, 8) 979 } 980 Lputl(uint32(value)) 981 Wputl(uint16(sect)) 982 if typ != 0 { 983 Wputl(typ) 984 } else if Linkmode == LinkExternal { 985 Wputl(0) 986 } else { 987 Wputl(0x0308) // "array of structs" 988 } 989 Cput(2) // storage class: external 990 Cput(0) // no aux entries 991 992 s.Dynid = int32(symcnt) 993 994 symcnt++ 995 } 996 997 if Linkmode == LinkExternal { 998 for d := dr; d != nil; d = d.next { 999 for m := d.ms; m != nil; m = m.next { 1000 s := m.s.R[0].Xsym 1001 put(ctxt, s, s.Name, UndefinedSym, 0, nil) 1002 } 1003 } 1004 1005 s := ctxt.Syms.Lookup(".text", 0) 1006 if s.Type == obj.STEXT { 1007 put(ctxt, s, s.Name, TextSym, s.Value, nil) 1008 } 1009 } 1010 1011 genasmsym(ctxt, put) 1012 1013 return symcnt 1014 } 1015 1016 func addpesymtable(ctxt *Link) { 1017 symtabStartPos := coutbuf.Offset() 1018 1019 // write COFF symbol table 1020 var symcnt int 1021 if !*FlagS || Linkmode == LinkExternal { 1022 symcnt = writePESymTableRecords(ctxt) 1023 } 1024 1025 // update COFF file header and section table 1026 size := len(strtbl) + 4 + 18*symcnt 1027 var h *IMAGE_SECTION_HEADER 1028 if Linkmode != LinkExternal { 1029 // We do not really need .symtab for go.o, and if we have one, ld 1030 // will also include it in the exe, and that will confuse windows. 1031 h = addpesection(ctxt, ".symtab", size, size) 1032 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 1033 chksectoff(ctxt, h, symtabStartPos) 1034 } 1035 fh.PointerToSymbolTable = uint32(symtabStartPos) 1036 fh.NumberOfSymbols = uint32(symcnt) 1037 1038 // write COFF string table 1039 Lputl(uint32(len(strtbl)) + 4) 1040 for i := 0; i < len(strtbl); i++ { 1041 Cput(strtbl[i]) 1042 } 1043 if Linkmode != LinkExternal { 1044 strnput("", int(h.SizeOfRawData-uint32(size))) 1045 } 1046 } 1047 1048 func setpersrc(ctxt *Link, sym *Symbol) { 1049 if rsrcsym != nil { 1050 Errorf(sym, "too many .rsrc sections") 1051 } 1052 1053 rsrcsym = sym 1054 } 1055 1056 func addpersrc(ctxt *Link) { 1057 if rsrcsym == nil { 1058 return 1059 } 1060 1061 h := addpesection(ctxt, ".rsrc", int(rsrcsym.Size), int(rsrcsym.Size)) 1062 h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA 1063 chksectoff(ctxt, h, coutbuf.Offset()) 1064 1065 // relocation 1066 var p []byte 1067 var r *Reloc 1068 var val uint32 1069 for ri := 0; ri < len(rsrcsym.R); ri++ { 1070 r = &rsrcsym.R[ri] 1071 p = rsrcsym.P[r.Off:] 1072 val = uint32(int64(h.VirtualAddress) + r.Add) 1073 1074 // 32-bit little-endian 1075 p[0] = byte(val) 1076 1077 p[1] = byte(val >> 8) 1078 p[2] = byte(val >> 16) 1079 p[3] = byte(val >> 24) 1080 } 1081 1082 Cwrite(rsrcsym.P) 1083 strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size)) 1084 1085 // update data directory 1086 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress 1087 1088 dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize 1089 } 1090 1091 func addinitarray(ctxt *Link) (c *IMAGE_SECTION_HEADER) { 1092 // The size below was determined by the specification for array relocations, 1093 // and by observing what GCC writes here. If the initarray section grows to 1094 // contain more than one constructor entry, the size will need to be 8 * constructor_count. 1095 // However, the entire Go runtime is initialized from just one function, so it is unlikely 1096 // that this will need to grow in the future. 1097 var size int 1098 switch obj.GOARCH { 1099 default: 1100 fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.GOARCH) 1101 os.Exit(2) 1102 case "386": 1103 size = 4 1104 case "amd64": 1105 size = 8 1106 } 1107 1108 c = addpesection(ctxt, ".ctors", size, size) 1109 c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1110 c.SizeOfRawData = uint32(size) 1111 1112 Cseek(int64(c.PointerToRawData)) 1113 chksectoff(ctxt, c, coutbuf.Offset()) 1114 init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0) 1115 addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr 1116 1117 switch obj.GOARCH { 1118 case "386": 1119 Lputl(uint32(addr)) 1120 case "amd64": 1121 Vputl(addr) 1122 } 1123 1124 return c 1125 } 1126 1127 func Asmbpe(ctxt *Link) { 1128 switch SysArch.Family { 1129 default: 1130 Exitf("unknown PE architecture: %v", SysArch.Family) 1131 case sys.AMD64: 1132 fh.Machine = IMAGE_FILE_MACHINE_AMD64 1133 case sys.I386: 1134 fh.Machine = IMAGE_FILE_MACHINE_I386 1135 } 1136 1137 t := addpesection(ctxt, ".text", int(Segtext.Length), int(Segtext.Length)) 1138 t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ 1139 if Linkmode == LinkExternal { 1140 // some data symbols (e.g. masks) end up in the .text section, and they normally 1141 // expect larger alignment requirement than the default text section alignment. 1142 t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES 1143 } 1144 chksectseg(ctxt, t, &Segtext) 1145 textsect = pensect 1146 1147 var d *IMAGE_SECTION_HEADER 1148 var c *IMAGE_SECTION_HEADER 1149 if Linkmode != LinkExternal { 1150 d = addpesection(ctxt, ".data", int(Segdata.Length), int(Segdata.Filelen)) 1151 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1152 chksectseg(ctxt, d, &Segdata) 1153 datasect = pensect 1154 } else { 1155 d = addpesection(ctxt, ".data", int(Segdata.Filelen), int(Segdata.Filelen)) 1156 d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1157 chksectseg(ctxt, d, &Segdata) 1158 datasect = pensect 1159 1160 b := addpesection(ctxt, ".bss", int(Segdata.Length-Segdata.Filelen), 0) 1161 b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1162 b.PointerToRawData = 0 1163 bsssect = pensect 1164 1165 c = addinitarray(ctxt) 1166 } 1167 1168 if !*FlagS { 1169 dwarfaddpeheaders(ctxt) 1170 } 1171 1172 Cseek(int64(nextfileoff)) 1173 if Linkmode != LinkExternal { 1174 addimports(ctxt, d) 1175 addexports(ctxt) 1176 } 1177 addpesymtable(ctxt) 1178 addpersrc(ctxt) 1179 if Linkmode == LinkExternal { 1180 peemitreloc(ctxt, t, d, c) 1181 } 1182 1183 fh.NumberOfSections = uint16(pensect) 1184 1185 // Being able to produce identical output for identical input is 1186 // much more beneficial than having build timestamp in the header. 1187 fh.TimeDateStamp = 0 1188 1189 if Linkmode == LinkExternal { 1190 fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED 1191 } else { 1192 fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED 1193 } 1194 if pe64 != 0 { 1195 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) 1196 fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE 1197 oh64.Magic = 0x20b // PE32+ 1198 } else { 1199 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh)) 1200 fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE 1201 oh.Magic = 0x10b // PE32 1202 oh.BaseOfData = d.VirtualAddress 1203 } 1204 1205 // Fill out both oh64 and oh. We only use one. Oh well. 1206 oh64.MajorLinkerVersion = 3 1207 1208 oh.MajorLinkerVersion = 3 1209 oh64.MinorLinkerVersion = 0 1210 oh.MinorLinkerVersion = 0 1211 oh64.SizeOfCode = t.SizeOfRawData 1212 oh.SizeOfCode = t.SizeOfRawData 1213 oh64.SizeOfInitializedData = d.SizeOfRawData 1214 oh.SizeOfInitializedData = d.SizeOfRawData 1215 oh64.SizeOfUninitializedData = 0 1216 oh.SizeOfUninitializedData = 0 1217 if Linkmode != LinkExternal { 1218 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 1219 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 1220 } 1221 oh64.BaseOfCode = t.VirtualAddress 1222 oh.BaseOfCode = t.VirtualAddress 1223 oh64.ImageBase = PEBASE 1224 oh.ImageBase = PEBASE 1225 oh64.SectionAlignment = PESECTALIGN 1226 oh.SectionAlignment = PESECTALIGN 1227 oh64.FileAlignment = PEFILEALIGN 1228 oh.FileAlignment = PEFILEALIGN 1229 oh64.MajorOperatingSystemVersion = 4 1230 oh.MajorOperatingSystemVersion = 4 1231 oh64.MinorOperatingSystemVersion = 0 1232 oh.MinorOperatingSystemVersion = 0 1233 oh64.MajorImageVersion = 1 1234 oh.MajorImageVersion = 1 1235 oh64.MinorImageVersion = 0 1236 oh.MinorImageVersion = 0 1237 oh64.MajorSubsystemVersion = 4 1238 oh.MajorSubsystemVersion = 4 1239 oh64.MinorSubsystemVersion = 0 1240 oh.MinorSubsystemVersion = 0 1241 oh64.SizeOfImage = uint32(nextsectoff) 1242 oh.SizeOfImage = uint32(nextsectoff) 1243 oh64.SizeOfHeaders = uint32(PEFILEHEADR) 1244 oh.SizeOfHeaders = uint32(PEFILEHEADR) 1245 if Headtype == obj.Hwindowsgui { 1246 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1247 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 1248 } else { 1249 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1250 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 1251 } 1252 1253 // Disable stack growth as we don't want Windows to 1254 // fiddle with the thread stack limits, which we set 1255 // ourselves to circumvent the stack checks in the 1256 // Windows exception dispatcher. 1257 // Commit size must be strictly less than reserve 1258 // size otherwise reserve will be rounded up to a 1259 // larger size, as verified with VMMap. 1260 1261 // Go code would be OK with 64k stacks, but we need larger stacks for cgo. 1262 // 1263 // The default stack reserve size affects only the main 1264 // thread, ctrlhandler thread, and profileloop thread. For 1265 // these, it must be greater than the stack size assumed by 1266 // externalthreadhandler. 1267 // 1268 // For other threads we specify stack size in runtime explicitly 1269 // (runtime knows whether cgo is enabled or not). 1270 // For these, the reserve must match STACKSIZE in 1271 // runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent 1272 // CreateThread parameter in runtime.newosproc. 1273 if !iscgo { 1274 oh64.SizeOfStackReserve = 0x00020000 1275 oh.SizeOfStackReserve = 0x00020000 1276 oh64.SizeOfStackCommit = 0x00001000 1277 oh.SizeOfStackCommit = 0x00001000 1278 } else { 1279 oh64.SizeOfStackReserve = 0x00200000 1280 oh.SizeOfStackReserve = 0x00100000 1281 1282 // account for 2 guard pages 1283 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 1284 1285 oh.SizeOfStackCommit = 0x00100000 - 0x2000 1286 } 1287 1288 oh64.SizeOfHeapReserve = 0x00100000 1289 oh.SizeOfHeapReserve = 0x00100000 1290 oh64.SizeOfHeapCommit = 0x00001000 1291 oh.SizeOfHeapCommit = 0x00001000 1292 oh64.NumberOfRvaAndSizes = 16 1293 oh.NumberOfRvaAndSizes = 16 1294 1295 pewrite() 1296 }