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