1 // 2 // Author: 3 // Jb Evain (jbevain@gmail.com) 4 // 5 // Copyright (c) 2008 - 2015 Jb Evain 6 // Copyright (c) 2008 - 2011 Novell, Inc. 7 // 8 // Licensed under the MIT/X11 license. 9 // 10 11 using System; 12 using System.IO; 13 14 #if !READ_ONLY 15 16 using Mono.Cecil.Cil; 17 using Mono.Cecil.Metadata; 18 19 using RVA = System.UInt32; 20 21 namespace Mono.Cecil.PE { 22 23 sealed class ImageWriter : BinaryStreamWriter { 24 25 readonly ModuleDefinition module; 26 readonly MetadataBuilder metadata; 27 readonly TextMap text_map; 28 readonly internal Disposable<Stream> stream; 29 30 readonly string runtime_version; 31 32 ImageDebugHeader debug_header; 33 34 ByteBuffer win32_resources; 35 36 const uint pe_header_size = 0x98u; 37 const uint section_header_size = 0x28u; 38 const uint file_alignment = 0x200; 39 const uint section_alignment = 0x2000; 40 const ulong image_base = 0x00400000; 41 42 internal const RVA text_rva = 0x2000; 43 44 readonly bool pe64; 45 readonly bool has_reloc; 46 47 internal Section text; 48 internal Section rsrc; 49 internal Section reloc; 50 51 ushort sections; 52 ImageWriter(ModuleDefinition module, string runtime_version, MetadataBuilder metadata, Disposable<Stream> stream, bool metadataOnly = false)53 ImageWriter (ModuleDefinition module, string runtime_version, MetadataBuilder metadata, Disposable<Stream> stream, bool metadataOnly = false) 54 : base (stream.value) 55 { 56 this.module = module; 57 this.runtime_version = runtime_version; 58 this.text_map = metadata.text_map; 59 this.stream = stream; 60 this.metadata = metadata; 61 if (metadataOnly) 62 return; 63 64 this.pe64 = module.Architecture == TargetArchitecture.AMD64 || module.Architecture == TargetArchitecture.IA64 || module.Architecture == TargetArchitecture.ARM64; 65 this.has_reloc = module.Architecture == TargetArchitecture.I386; 66 this.GetDebugHeader (); 67 this.GetWin32Resources (); 68 this.BuildTextMap (); 69 this.sections = (ushort) (has_reloc ? 2 : 1); // text + reloc? 70 } 71 GetDebugHeader()72 void GetDebugHeader () 73 { 74 var symbol_writer = metadata.symbol_writer; 75 if (symbol_writer != null) 76 debug_header = symbol_writer.GetDebugHeader (); 77 78 if (module.HasDebugHeader) { 79 var header = module.GetDebugHeader (); 80 var deterministic = header.GetDeterministicEntry (); 81 if (deterministic == null) 82 return; 83 84 debug_header = debug_header.AddDeterministicEntry (); 85 } 86 } 87 GetWin32Resources()88 void GetWin32Resources () 89 { 90 if (!module.HasImage) 91 return; 92 93 DataDirectory win32_resources_directory = module.Image.Win32Resources; 94 var size = win32_resources_directory.Size; 95 96 if (size > 0) { 97 win32_resources = module.Image.GetReaderAt (win32_resources_directory.VirtualAddress, size, (s, reader) => new ByteBuffer (reader.ReadBytes ((int) s))); 98 } 99 } 100 CreateWriter(ModuleDefinition module, MetadataBuilder metadata, Disposable<Stream> stream)101 public static ImageWriter CreateWriter (ModuleDefinition module, MetadataBuilder metadata, Disposable<Stream> stream) 102 { 103 var writer = new ImageWriter (module, module.runtime_version, metadata, stream); 104 writer.BuildSections (); 105 return writer; 106 } 107 CreateDebugWriter(ModuleDefinition module, MetadataBuilder metadata, Disposable<Stream> stream)108 public static ImageWriter CreateDebugWriter (ModuleDefinition module, MetadataBuilder metadata, Disposable<Stream> stream) 109 { 110 var writer = new ImageWriter (module, "PDB v1.0", metadata, stream, metadataOnly: true); 111 var length = metadata.text_map.GetLength (); 112 writer.text = new Section { SizeOfRawData = length, VirtualSize = length }; 113 return writer; 114 } 115 BuildSections()116 void BuildSections () 117 { 118 var has_win32_resources = win32_resources != null; 119 if (has_win32_resources) 120 sections++; 121 122 text = CreateSection (".text", text_map.GetLength (), null); 123 var previous = text; 124 125 if (has_win32_resources) { 126 rsrc = CreateSection (".rsrc", (uint) win32_resources.length, previous); 127 128 PatchWin32Resources (win32_resources); 129 previous = rsrc; 130 } 131 132 if (has_reloc) 133 reloc = CreateSection (".reloc", 12u, previous); 134 } 135 CreateSection(string name, uint size, Section previous)136 Section CreateSection (string name, uint size, Section previous) 137 { 138 return new Section { 139 Name = name, 140 VirtualAddress = previous != null 141 ? previous.VirtualAddress + Align (previous.VirtualSize, section_alignment) 142 : text_rva, 143 VirtualSize = size, 144 PointerToRawData = previous != null 145 ? previous.PointerToRawData + previous.SizeOfRawData 146 : Align (GetHeaderSize (), file_alignment), 147 SizeOfRawData = Align (size, file_alignment) 148 }; 149 } 150 Align(uint value, uint align)151 static uint Align (uint value, uint align) 152 { 153 align--; 154 return (value + align) & ~align; 155 } 156 WriteDOSHeader()157 void WriteDOSHeader () 158 { 159 Write (new byte [] { 160 // dos header start 161 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 162 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 163 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 164 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 169 0x00, 0x00, 0x00, 0x00, 170 // lfanew 171 0x80, 0x00, 0x00, 0x00, 172 // dos header end 173 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 174 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 175 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 176 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 177 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 178 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 179 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 180 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 181 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 182 0x00 183 }); 184 } 185 SizeOfOptionalHeader()186 ushort SizeOfOptionalHeader () 187 { 188 return (ushort) (!pe64 ? 0xe0 : 0xf0); 189 } 190 WritePEFileHeader()191 void WritePEFileHeader () 192 { 193 WriteUInt32 (0x00004550); // Magic 194 WriteUInt16 ((ushort) module.Architecture); // Machine 195 WriteUInt16 (sections); // NumberOfSections 196 WriteUInt32 (metadata.timestamp); 197 WriteUInt32 (0); // PointerToSymbolTable 198 WriteUInt32 (0); // NumberOfSymbols 199 WriteUInt16 (SizeOfOptionalHeader ()); // SizeOfOptionalHeader 200 201 // ExecutableImage | (pe64 ? 32BitsMachine : LargeAddressAware) 202 var characteristics = (ushort) (0x0002 | (!pe64 ? 0x0100 : 0x0020)); 203 if (module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule) 204 characteristics |= 0x2000; 205 WriteUInt16 (characteristics); // Characteristics 206 } 207 LastSection()208 Section LastSection () 209 { 210 if (reloc != null) 211 return reloc; 212 213 if (rsrc != null) 214 return rsrc; 215 216 return text; 217 } 218 WriteOptionalHeaders()219 void WriteOptionalHeaders () 220 { 221 WriteUInt16 ((ushort) (!pe64 ? 0x10b : 0x20b)); // Magic 222 WriteByte (8); // LMajor 223 WriteByte (0); // LMinor 224 WriteUInt32 (text.SizeOfRawData); // CodeSize 225 WriteUInt32 ((reloc != null ? reloc.SizeOfRawData : 0) 226 + (rsrc != null ? rsrc.SizeOfRawData : 0)); // InitializedDataSize 227 WriteUInt32 (0); // UninitializedDataSize 228 229 var startub_stub = text_map.GetRange (TextSegment.StartupStub); 230 WriteUInt32 (startub_stub.Length > 0 ? startub_stub.Start : 0); // EntryPointRVA 231 WriteUInt32 (text_rva); // BaseOfCode 232 233 if (!pe64) { 234 WriteUInt32 (0); // BaseOfData 235 WriteUInt32 ((uint) image_base); // ImageBase 236 } else { 237 WriteUInt64 (image_base); // ImageBase 238 } 239 240 WriteUInt32 (section_alignment); // SectionAlignment 241 WriteUInt32 (file_alignment); // FileAlignment 242 243 WriteUInt16 (4); // OSMajor 244 WriteUInt16 (0); // OSMinor 245 WriteUInt16 (0); // UserMajor 246 WriteUInt16 (0); // UserMinor 247 WriteUInt16 (4); // SubSysMajor 248 WriteUInt16 (0); // SubSysMinor 249 WriteUInt32 (0); // Reserved 250 251 var last_section = LastSection(); 252 WriteUInt32 (last_section.VirtualAddress + Align (last_section.VirtualSize, section_alignment)); // ImageSize 253 WriteUInt32 (text.PointerToRawData); // HeaderSize 254 255 WriteUInt32 (0); // Checksum 256 WriteUInt16 (GetSubSystem ()); // SubSystem 257 WriteUInt16 ((ushort) module.Characteristics); // DLLFlags 258 259 const ulong stack_reserve = 0x100000; 260 const ulong stack_commit = 0x1000; 261 const ulong heap_reserve = 0x100000; 262 const ulong heap_commit = 0x1000; 263 264 if (!pe64) { 265 WriteUInt32 ((uint) stack_reserve); 266 WriteUInt32 ((uint) stack_commit); 267 WriteUInt32 ((uint) heap_reserve); 268 WriteUInt32 ((uint) heap_commit); 269 } else { 270 WriteUInt64 (stack_reserve); 271 WriteUInt64 (stack_commit); 272 WriteUInt64 (heap_reserve); 273 WriteUInt64 (heap_commit); 274 } 275 276 WriteUInt32 (0); // LoaderFlags 277 WriteUInt32 (16); // NumberOfDataDir 278 279 WriteZeroDataDirectory (); // ExportTable 280 WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportDirectory)); // ImportTable 281 if (rsrc != null) { // ResourceTable 282 WriteUInt32 (rsrc.VirtualAddress); 283 WriteUInt32 (rsrc.VirtualSize); 284 } else 285 WriteZeroDataDirectory (); 286 287 WriteZeroDataDirectory (); // ExceptionTable 288 WriteZeroDataDirectory (); // CertificateTable 289 WriteUInt32 (reloc != null ? reloc.VirtualAddress : 0); // BaseRelocationTable 290 WriteUInt32 (reloc != null ? reloc.VirtualSize : 0); 291 292 if (text_map.GetLength (TextSegment.DebugDirectory) > 0) { 293 WriteUInt32 (text_map.GetRVA (TextSegment.DebugDirectory)); 294 WriteUInt32 ((uint) (debug_header.Entries.Length * ImageDebugDirectory.Size)); 295 } else 296 WriteZeroDataDirectory (); 297 298 WriteZeroDataDirectory (); // Copyright 299 WriteZeroDataDirectory (); // GlobalPtr 300 WriteZeroDataDirectory (); // TLSTable 301 WriteZeroDataDirectory (); // LoadConfigTable 302 WriteZeroDataDirectory (); // BoundImport 303 WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportAddressTable)); // IAT 304 WriteZeroDataDirectory (); // DelayImportDesc 305 WriteDataDirectory (text_map.GetDataDirectory (TextSegment.CLIHeader)); // CLIHeader 306 WriteZeroDataDirectory (); // Reserved 307 } 308 WriteZeroDataDirectory()309 void WriteZeroDataDirectory () 310 { 311 WriteUInt32 (0); 312 WriteUInt32 (0); 313 } 314 GetSubSystem()315 ushort GetSubSystem () 316 { 317 switch (module.Kind) { 318 case ModuleKind.Console: 319 case ModuleKind.Dll: 320 case ModuleKind.NetModule: 321 return 0x3; 322 case ModuleKind.Windows: 323 return 0x2; 324 default: 325 throw new ArgumentOutOfRangeException (); 326 } 327 } 328 WriteSectionHeaders()329 void WriteSectionHeaders () 330 { 331 WriteSection (text, 0x60000020); 332 333 if (rsrc != null) 334 WriteSection (rsrc, 0x40000040); 335 336 if (reloc != null) 337 WriteSection (reloc, 0x42000040); 338 } 339 WriteSection(Section section, uint characteristics)340 void WriteSection (Section section, uint characteristics) 341 { 342 var name = new byte [8]; 343 var sect_name = section.Name; 344 for (int i = 0; i < sect_name.Length; i++) 345 name [i] = (byte) sect_name [i]; 346 347 WriteBytes (name); 348 WriteUInt32 (section.VirtualSize); 349 WriteUInt32 (section.VirtualAddress); 350 WriteUInt32 (section.SizeOfRawData); 351 WriteUInt32 (section.PointerToRawData); 352 WriteUInt32 (0); // PointerToRelocations 353 WriteUInt32 (0); // PointerToLineNumbers 354 WriteUInt16 (0); // NumberOfRelocations 355 WriteUInt16 (0); // NumberOfLineNumbers 356 WriteUInt32 (characteristics); 357 } 358 MoveTo(uint pointer)359 void MoveTo (uint pointer) 360 { 361 BaseStream.Seek (pointer, SeekOrigin.Begin); 362 } 363 MoveToRVA(Section section, RVA rva)364 void MoveToRVA (Section section, RVA rva) 365 { 366 BaseStream.Seek (section.PointerToRawData + rva - section.VirtualAddress, SeekOrigin.Begin); 367 } 368 MoveToRVA(TextSegment segment)369 void MoveToRVA (TextSegment segment) 370 { 371 MoveToRVA (text, text_map.GetRVA (segment)); 372 } 373 WriteRVA(RVA rva)374 void WriteRVA (RVA rva) 375 { 376 if (!pe64) 377 WriteUInt32 (rva); 378 else 379 WriteUInt64 (rva); 380 } 381 PrepareSection(Section section)382 void PrepareSection (Section section) 383 { 384 MoveTo (section.PointerToRawData); 385 386 const int buffer_size = 4096; 387 388 if (section.SizeOfRawData <= buffer_size) { 389 Write (new byte [section.SizeOfRawData]); 390 MoveTo (section.PointerToRawData); 391 return; 392 } 393 394 var written = 0; 395 var buffer = new byte [buffer_size]; 396 while (written != section.SizeOfRawData) { 397 var write_size = System.Math.Min((int) section.SizeOfRawData - written, buffer_size); 398 Write (buffer, 0, write_size); 399 written += write_size; 400 } 401 402 MoveTo (section.PointerToRawData); 403 } 404 WriteText()405 void WriteText () 406 { 407 PrepareSection (text); 408 409 // ImportAddressTable 410 411 if (has_reloc) { 412 WriteRVA (text_map.GetRVA (TextSegment.ImportHintNameTable)); 413 WriteRVA (0); 414 } 415 416 // CLIHeader 417 418 WriteUInt32 (0x48); 419 WriteUInt16 (2); 420 WriteUInt16 ((ushort) ((module.Runtime <= TargetRuntime.Net_1_1) ? 0 : 5)); 421 422 WriteUInt32 (text_map.GetRVA (TextSegment.MetadataHeader)); 423 WriteUInt32 (GetMetadataLength ()); 424 WriteUInt32 ((uint) module.Attributes); 425 WriteUInt32 (metadata.entry_point.ToUInt32 ()); 426 WriteDataDirectory (text_map.GetDataDirectory (TextSegment.Resources)); 427 WriteDataDirectory (text_map.GetDataDirectory (TextSegment.StrongNameSignature)); 428 WriteZeroDataDirectory (); // CodeManagerTable 429 WriteZeroDataDirectory (); // VTableFixups 430 WriteZeroDataDirectory (); // ExportAddressTableJumps 431 WriteZeroDataDirectory (); // ManagedNativeHeader 432 433 // Code 434 435 MoveToRVA (TextSegment.Code); 436 WriteBuffer (metadata.code); 437 438 // Resources 439 440 MoveToRVA (TextSegment.Resources); 441 WriteBuffer (metadata.resources); 442 443 // Data 444 445 if (metadata.data.length > 0) { 446 MoveToRVA (TextSegment.Data); 447 WriteBuffer (metadata.data); 448 } 449 450 // StrongNameSignature 451 // stays blank 452 453 // MetadataHeader 454 455 MoveToRVA (TextSegment.MetadataHeader); 456 WriteMetadataHeader (); 457 458 WriteMetadata (); 459 460 // DebugDirectory 461 if (text_map.GetLength (TextSegment.DebugDirectory) > 0) { 462 MoveToRVA (TextSegment.DebugDirectory); 463 WriteDebugDirectory (); 464 } 465 466 if (!has_reloc) 467 return; 468 469 // ImportDirectory 470 MoveToRVA (TextSegment.ImportDirectory); 471 WriteImportDirectory (); 472 473 // StartupStub 474 MoveToRVA (TextSegment.StartupStub); 475 WriteStartupStub (); 476 } 477 GetMetadataLength()478 uint GetMetadataLength () 479 { 480 return text_map.GetRVA (TextSegment.DebugDirectory) - text_map.GetRVA (TextSegment.MetadataHeader); 481 } 482 WriteMetadataHeader()483 public void WriteMetadataHeader () 484 { 485 WriteUInt32 (0x424a5342); // Signature 486 WriteUInt16 (1); // MajorVersion 487 WriteUInt16 (1); // MinorVersion 488 WriteUInt32 (0); // Reserved 489 490 var version = GetZeroTerminatedString (runtime_version); 491 WriteUInt32 ((uint) version.Length); 492 WriteBytes (version); 493 WriteUInt16 (0); // Flags 494 WriteUInt16 (GetStreamCount ()); 495 496 uint offset = text_map.GetRVA (TextSegment.TableHeap) - text_map.GetRVA (TextSegment.MetadataHeader); 497 498 WriteStreamHeader (ref offset, TextSegment.TableHeap, "#~"); 499 WriteStreamHeader (ref offset, TextSegment.StringHeap, "#Strings"); 500 WriteStreamHeader (ref offset, TextSegment.UserStringHeap, "#US"); 501 WriteStreamHeader (ref offset, TextSegment.GuidHeap, "#GUID"); 502 WriteStreamHeader (ref offset, TextSegment.BlobHeap, "#Blob"); 503 WriteStreamHeader (ref offset, TextSegment.PdbHeap, "#Pdb"); 504 } 505 GetStreamCount()506 ushort GetStreamCount () 507 { 508 return (ushort) ( 509 1 // #~ 510 + 1 // #Strings 511 + (metadata.user_string_heap.IsEmpty ? 0 : 1) // #US 512 + (metadata.guid_heap.IsEmpty ? 0 : 1) // GUID 513 + (metadata.blob_heap.IsEmpty ? 0 : 1) 514 + (metadata.pdb_heap == null ? 0 : 1)); // #Blob 515 } 516 WriteStreamHeader(ref uint offset, TextSegment heap, string name)517 void WriteStreamHeader (ref uint offset, TextSegment heap, string name) 518 { 519 var length = (uint) text_map.GetLength (heap); 520 if (length == 0) 521 return; 522 523 WriteUInt32 (offset); 524 WriteUInt32 (length); 525 WriteBytes (GetZeroTerminatedString (name)); 526 offset += length; 527 } 528 GetZeroTerminatedStringLength(string @string)529 static int GetZeroTerminatedStringLength (string @string) 530 { 531 return (@string.Length + 1 + 3) & ~3; 532 } 533 GetZeroTerminatedString(string @string)534 static byte [] GetZeroTerminatedString (string @string) 535 { 536 return GetString (@string, GetZeroTerminatedStringLength (@string)); 537 } 538 GetSimpleString(string @string)539 static byte [] GetSimpleString (string @string) 540 { 541 return GetString (@string, @string.Length); 542 } 543 GetString(string @string, int length)544 static byte [] GetString (string @string, int length) 545 { 546 var bytes = new byte [length]; 547 for (int i = 0; i < @string.Length; i++) 548 bytes [i] = (byte) @string [i]; 549 550 return bytes; 551 } 552 WriteMetadata()553 public void WriteMetadata () 554 { 555 WriteHeap (TextSegment.TableHeap, metadata.table_heap); 556 WriteHeap (TextSegment.StringHeap, metadata.string_heap); 557 WriteHeap (TextSegment.UserStringHeap, metadata.user_string_heap); 558 WriteHeap (TextSegment.GuidHeap, metadata.guid_heap); 559 WriteHeap (TextSegment.BlobHeap, metadata.blob_heap); 560 WriteHeap (TextSegment.PdbHeap, metadata.pdb_heap); 561 } 562 WriteHeap(TextSegment heap, HeapBuffer buffer)563 void WriteHeap (TextSegment heap, HeapBuffer buffer) 564 { 565 if (buffer == null || buffer.IsEmpty) 566 return; 567 568 MoveToRVA (heap); 569 WriteBuffer (buffer); 570 } 571 WriteDebugDirectory()572 void WriteDebugDirectory () 573 { 574 var data_start = (int) BaseStream.Position + (debug_header.Entries.Length * ImageDebugDirectory.Size); 575 576 for (var i = 0; i < debug_header.Entries.Length; i++) { 577 var entry = debug_header.Entries [i]; 578 var directory = entry.Directory; 579 WriteInt32 (directory.Characteristics); 580 WriteInt32 (directory.TimeDateStamp); 581 WriteInt16 (directory.MajorVersion); 582 WriteInt16 (directory.MinorVersion); 583 WriteInt32 ((int) directory.Type); 584 WriteInt32 (directory.SizeOfData); 585 WriteInt32 (directory.AddressOfRawData); 586 WriteInt32 (data_start); 587 588 data_start += entry.Data.Length; 589 } 590 591 for (var i = 0; i < debug_header.Entries.Length; i++) { 592 var entry = debug_header.Entries [i]; 593 WriteBytes (entry.Data); 594 } 595 } 596 WriteImportDirectory()597 void WriteImportDirectory () 598 { 599 WriteUInt32 (text_map.GetRVA (TextSegment.ImportDirectory) + 40); // ImportLookupTable 600 WriteUInt32 (0); // DateTimeStamp 601 WriteUInt32 (0); // ForwarderChain 602 WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable) + 14); 603 WriteUInt32 (text_map.GetRVA (TextSegment.ImportAddressTable)); 604 Advance (20); 605 606 // ImportLookupTable 607 WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable)); 608 609 // ImportHintNameTable 610 MoveToRVA (TextSegment.ImportHintNameTable); 611 612 WriteUInt16 (0); // Hint 613 WriteBytes (GetRuntimeMain ()); 614 WriteByte (0); 615 WriteBytes (GetSimpleString ("mscoree.dll")); 616 WriteUInt16 (0); 617 } 618 GetRuntimeMain()619 byte [] GetRuntimeMain () 620 { 621 return module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule 622 ? GetSimpleString ("_CorDllMain") 623 : GetSimpleString ("_CorExeMain"); 624 } 625 WriteStartupStub()626 void WriteStartupStub () 627 { 628 switch (module.Architecture) { 629 case TargetArchitecture.I386: 630 WriteUInt16 (0x25ff); 631 WriteUInt32 ((uint) image_base + text_map.GetRVA (TextSegment.ImportAddressTable)); 632 return; 633 default: 634 throw new NotSupportedException (); 635 } 636 } 637 WriteRsrc()638 void WriteRsrc () 639 { 640 PrepareSection (rsrc); 641 WriteBuffer (win32_resources); 642 } 643 WriteReloc()644 void WriteReloc () 645 { 646 PrepareSection (reloc); 647 648 var reloc_rva = text_map.GetRVA (TextSegment.StartupStub); 649 reloc_rva += module.Architecture == TargetArchitecture.IA64 ? 0x20u : 2; 650 var page_rva = reloc_rva & ~0xfffu; 651 652 WriteUInt32 (page_rva); // PageRVA 653 WriteUInt32 (0x000c); // Block Size 654 655 switch (module.Architecture) { 656 case TargetArchitecture.I386: 657 WriteUInt32 (0x3000 + reloc_rva - page_rva); 658 break; 659 default: 660 throw new NotSupportedException(); 661 } 662 } 663 WriteImage()664 public void WriteImage () 665 { 666 WriteDOSHeader (); 667 WritePEFileHeader (); 668 WriteOptionalHeaders (); 669 WriteSectionHeaders (); 670 WriteText (); 671 if (rsrc != null) 672 WriteRsrc (); 673 if (reloc != null) 674 WriteReloc (); 675 Flush (); 676 } 677 BuildTextMap()678 void BuildTextMap () 679 { 680 var map = text_map; 681 682 map.AddMap (TextSegment.Code, metadata.code.length, !pe64 ? 4 : 16); 683 map.AddMap (TextSegment.Resources, metadata.resources.length, 8); 684 map.AddMap (TextSegment.Data, metadata.data.length, 4); 685 if (metadata.data.length > 0) 686 metadata.table_heap.FixupData (map.GetRVA (TextSegment.Data)); 687 map.AddMap (TextSegment.StrongNameSignature, GetStrongNameLength (), 4); 688 689 BuildMetadataTextMap (); 690 691 int debug_dir_len = 0; 692 if (debug_header != null && debug_header.HasEntries) { 693 var directories_len = debug_header.Entries.Length * ImageDebugDirectory.Size; 694 var data_address = (int) map.GetNextRVA (TextSegment.BlobHeap) + directories_len; 695 var data_len = 0; 696 697 for (var i = 0; i < debug_header.Entries.Length; i++) { 698 var entry = debug_header.Entries [i]; 699 var directory = entry.Directory; 700 701 directory.AddressOfRawData = entry.Data.Length == 0 ? 0 : data_address; 702 entry.Directory = directory; 703 704 data_len += entry.Data.Length; 705 data_address += data_len; 706 } 707 708 debug_dir_len = directories_len + data_len; 709 } 710 711 map.AddMap (TextSegment.DebugDirectory, debug_dir_len, 4); 712 713 if (!has_reloc) { 714 var start = map.GetNextRVA (TextSegment.DebugDirectory); 715 map.AddMap (TextSegment.ImportDirectory, new Range (start, 0)); 716 map.AddMap (TextSegment.ImportHintNameTable, new Range (start, 0)); 717 map.AddMap (TextSegment.StartupStub, new Range (start, 0)); 718 return; 719 } 720 721 RVA import_dir_rva = map.GetNextRVA (TextSegment.DebugDirectory); 722 RVA import_hnt_rva = import_dir_rva + 48u; 723 import_hnt_rva = (import_hnt_rva + 15u) & ~15u; 724 uint import_dir_len = (import_hnt_rva - import_dir_rva) + 27u; 725 726 RVA startup_stub_rva = import_dir_rva + import_dir_len; 727 startup_stub_rva = module.Architecture == TargetArchitecture.IA64 728 ? (startup_stub_rva + 15u) & ~15u 729 : 2 + ((startup_stub_rva + 3u) & ~3u); 730 731 map.AddMap (TextSegment.ImportDirectory, new Range (import_dir_rva, import_dir_len)); 732 map.AddMap (TextSegment.ImportHintNameTable, new Range (import_hnt_rva, 0)); 733 map.AddMap (TextSegment.StartupStub, new Range (startup_stub_rva, GetStartupStubLength ())); 734 } 735 BuildMetadataTextMap()736 public void BuildMetadataTextMap () 737 { 738 var map = text_map; 739 740 map.AddMap (TextSegment.MetadataHeader, GetMetadataHeaderLength (module.RuntimeVersion)); 741 map.AddMap (TextSegment.TableHeap, metadata.table_heap.length, 4); 742 map.AddMap (TextSegment.StringHeap, metadata.string_heap.length, 4); 743 map.AddMap (TextSegment.UserStringHeap, metadata.user_string_heap.IsEmpty ? 0 : metadata.user_string_heap.length, 4); 744 map.AddMap (TextSegment.GuidHeap, metadata.guid_heap.length, 4); 745 map.AddMap (TextSegment.BlobHeap, metadata.blob_heap.IsEmpty ? 0 : metadata.blob_heap.length, 4); 746 map.AddMap (TextSegment.PdbHeap, metadata.pdb_heap == null ? 0 : metadata.pdb_heap.length, 4); 747 } 748 GetStartupStubLength()749 uint GetStartupStubLength () 750 { 751 switch (module.Architecture) { 752 case TargetArchitecture.I386: 753 return 6; 754 default: 755 throw new NotSupportedException (); 756 } 757 } 758 GetMetadataHeaderLength(string runtimeVersion)759 int GetMetadataHeaderLength (string runtimeVersion) 760 { 761 return 762 // MetadataHeader 763 20 + GetZeroTerminatedStringLength (runtimeVersion) 764 // #~ header 765 + 12 766 // #Strings header 767 + 20 768 // #US header 769 + (metadata.user_string_heap.IsEmpty ? 0 : 12) 770 // #GUID header 771 + 16 772 // #Blob header 773 + (metadata.blob_heap.IsEmpty ? 0 : 16) 774 // 775 + (metadata.pdb_heap == null ? 0 : 16); 776 } 777 GetStrongNameLength()778 int GetStrongNameLength () 779 { 780 if (module.Assembly == null) 781 return 0; 782 783 var public_key = module.Assembly.Name.PublicKey; 784 if (public_key.IsNullOrEmpty ()) 785 return 0; 786 787 // in fx 2.0 the key may be from 384 to 16384 bits 788 // so we must calculate the signature size based on 789 // the size of the public key (minus the 32 byte header) 790 int size = public_key.Length; 791 if (size > 32) 792 return size - 32; 793 794 // note: size == 16 for the ECMA "key" which is replaced 795 // by the runtime with a 1024 bits key (128 bytes) 796 797 return 128; // default strongname signature size 798 } 799 GetStrongNameSignatureDirectory()800 public DataDirectory GetStrongNameSignatureDirectory () 801 { 802 return text_map.GetDataDirectory (TextSegment.StrongNameSignature); 803 } 804 GetHeaderSize()805 public uint GetHeaderSize () 806 { 807 return pe_header_size + SizeOfOptionalHeader () + (sections * section_header_size); 808 } 809 PatchWin32Resources(ByteBuffer resources)810 void PatchWin32Resources (ByteBuffer resources) 811 { 812 PatchResourceDirectoryTable (resources); 813 } 814 PatchResourceDirectoryTable(ByteBuffer resources)815 void PatchResourceDirectoryTable (ByteBuffer resources) 816 { 817 resources.Advance (12); 818 819 var entries = resources.ReadUInt16 () + resources.ReadUInt16 (); 820 821 for (int i = 0; i < entries; i++) 822 PatchResourceDirectoryEntry (resources); 823 } 824 PatchResourceDirectoryEntry(ByteBuffer resources)825 void PatchResourceDirectoryEntry (ByteBuffer resources) 826 { 827 resources.Advance (4); 828 var child = resources.ReadUInt32 (); 829 830 var position = resources.position; 831 resources.position = (int) child & 0x7fffffff; 832 833 if ((child & 0x80000000) != 0) 834 PatchResourceDirectoryTable (resources); 835 else 836 PatchResourceDataEntry (resources); 837 838 resources.position = position; 839 } 840 PatchResourceDataEntry(ByteBuffer resources)841 void PatchResourceDataEntry (ByteBuffer resources) 842 { 843 var rva = resources.ReadUInt32 (); 844 resources.position -= 4; 845 846 resources.WriteUInt32 (rva - module.Image.Win32Resources.VirtualAddress + rsrc.VirtualAddress); 847 } 848 } 849 } 850 851 #endif 852