/Mono.Cecil/Mono.Cecil.PE/ImageWriter.cs

http://github.com/icsharpcode/ILSpy · C# · 824 lines · 624 code · 145 blank · 55 comment · 71 complexity · e70d2b7260d08936e17502d92a4c24e2 MD5 · raw file

  1. //
  2. // ImageWriter.cs
  3. //
  4. // Author:
  5. // Jb Evain (jbevain@gmail.com)
  6. //
  7. // Copyright (c) 2008 - 2011 Jb Evain
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.IO;
  30. #if !READ_ONLY
  31. using Mono.Cecil.Cil;
  32. using Mono.Cecil.Metadata;
  33. using RVA = System.UInt32;
  34. namespace Mono.Cecil.PE {
  35. sealed class ImageWriter : BinaryStreamWriter {
  36. readonly ModuleDefinition module;
  37. readonly MetadataBuilder metadata;
  38. readonly TextMap text_map;
  39. ImageDebugDirectory debug_directory;
  40. byte [] debug_data;
  41. ByteBuffer win32_resources;
  42. const uint pe_header_size = 0x178u;
  43. const uint section_header_size = 0x28u;
  44. const uint file_alignment = 0x200;
  45. const uint section_alignment = 0x2000;
  46. const ulong image_base = 0x00400000;
  47. internal const RVA text_rva = 0x2000;
  48. readonly bool pe64;
  49. readonly uint time_stamp;
  50. internal Section text;
  51. internal Section rsrc;
  52. internal Section reloc;
  53. ushort sections;
  54. ImageWriter (ModuleDefinition module, MetadataBuilder metadata, Stream stream)
  55. : base (stream)
  56. {
  57. this.module = module;
  58. this.metadata = metadata;
  59. this.pe64 = module.Architecture != TargetArchitecture.I386;
  60. this.GetDebugHeader ();
  61. this.GetWin32Resources ();
  62. this.text_map = BuildTextMap ();
  63. this.sections = (ushort) (pe64 ? 1 : 2); // text + reloc
  64. this.time_stamp = (uint) DateTime.UtcNow.Subtract (new DateTime (1970, 1, 1)).TotalSeconds;
  65. }
  66. void GetDebugHeader ()
  67. {
  68. var symbol_writer = metadata.symbol_writer;
  69. if (symbol_writer == null)
  70. return;
  71. if (!symbol_writer.GetDebugHeader (out debug_directory, out debug_data))
  72. debug_data = Empty<byte>.Array;
  73. }
  74. void GetWin32Resources ()
  75. {
  76. var rsrc = GetImageResourceSection ();
  77. if (rsrc == null)
  78. return;
  79. var raw_resources = new byte [rsrc.Data.Length];
  80. Buffer.BlockCopy (rsrc.Data, 0, raw_resources, 0, rsrc.Data.Length);
  81. win32_resources = new ByteBuffer (raw_resources);
  82. }
  83. Section GetImageResourceSection ()
  84. {
  85. if (!module.HasImage)
  86. return null;
  87. const string rsrc_section = ".rsrc";
  88. return module.Image.GetSection (rsrc_section);
  89. }
  90. public static ImageWriter CreateWriter (ModuleDefinition module, MetadataBuilder metadata, Stream stream)
  91. {
  92. var writer = new ImageWriter (module, metadata, stream);
  93. writer.BuildSections ();
  94. return writer;
  95. }
  96. void BuildSections ()
  97. {
  98. var has_win32_resources = win32_resources != null;
  99. if (has_win32_resources)
  100. sections++;
  101. text = CreateSection (".text", text_map.GetLength (), null);
  102. var previous = text;
  103. if (has_win32_resources) {
  104. rsrc = CreateSection (".rsrc", (uint) win32_resources.length, previous);
  105. PatchWin32Resources (win32_resources);
  106. previous = rsrc;
  107. }
  108. if (!pe64)
  109. reloc = CreateSection (".reloc", 12u, previous);
  110. }
  111. Section CreateSection (string name, uint size, Section previous)
  112. {
  113. return new Section {
  114. Name = name,
  115. VirtualAddress = previous != null
  116. ? previous.VirtualAddress + Align (previous.VirtualSize, section_alignment)
  117. : text_rva,
  118. VirtualSize = size,
  119. PointerToRawData = previous != null
  120. ? previous.PointerToRawData + previous.SizeOfRawData
  121. : Align (GetHeaderSize (), file_alignment),
  122. SizeOfRawData = Align (size, file_alignment)
  123. };
  124. }
  125. static uint Align (uint value, uint align)
  126. {
  127. align--;
  128. return (value + align) & ~align;
  129. }
  130. void WriteDOSHeader ()
  131. {
  132. Write (new byte [] {
  133. // dos header start
  134. 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00,
  135. 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff,
  136. 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00,
  137. 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  138. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  139. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  140. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  141. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  142. 0x00, 0x00, 0x00, 0x00,
  143. // lfanew
  144. 0x80, 0x00, 0x00, 0x00,
  145. // dos header end
  146. 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09,
  147. 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21,
  148. 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72,
  149. 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63,
  150. 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62,
  151. 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69,
  152. 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d,
  153. 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
  154. 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  155. 0x00
  156. });
  157. }
  158. void WritePEFileHeader ()
  159. {
  160. WriteUInt32 (0x00004550); // Magic
  161. WriteUInt16 (GetMachine ()); // Machine
  162. WriteUInt16 (sections); // NumberOfSections
  163. WriteUInt32 (time_stamp);
  164. WriteUInt32 (0); // PointerToSymbolTable
  165. WriteUInt32 (0); // NumberOfSymbols
  166. WriteUInt16 ((ushort) (!pe64 ? 0xe0 : 0xf0)); // SizeOfOptionalHeader
  167. // ExecutableImage | (pe64 ? 32BitsMachine : LargeAddressAware)
  168. var characteristics = (ushort) (0x0002 | (!pe64 ? 0x0100 : 0x0020));
  169. if (module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule)
  170. characteristics |= 0x2000;
  171. WriteUInt16 (characteristics); // Characteristics
  172. }
  173. ushort GetMachine ()
  174. {
  175. switch (module.Architecture) {
  176. case TargetArchitecture.I386:
  177. return 0x014c;
  178. case TargetArchitecture.AMD64:
  179. return 0x8664;
  180. case TargetArchitecture.IA64:
  181. return 0x0200;
  182. }
  183. throw new NotSupportedException ();
  184. }
  185. Section LastSection ()
  186. {
  187. if (reloc != null)
  188. return reloc;
  189. if (rsrc != null)
  190. return rsrc;
  191. return text;
  192. }
  193. void WriteOptionalHeaders ()
  194. {
  195. WriteUInt16 ((ushort) (!pe64 ? 0x10b : 0x20b)); // Magic
  196. WriteByte (8); // LMajor
  197. WriteByte (0); // LMinor
  198. WriteUInt32 (text.SizeOfRawData); // CodeSize
  199. WriteUInt32 ((reloc != null ? reloc.SizeOfRawData : 0)
  200. + (rsrc != null ? rsrc.SizeOfRawData : 0)); // InitializedDataSize
  201. WriteUInt32 (0); // UninitializedDataSize
  202. var startub_stub = text_map.GetRange (TextSegment.StartupStub);
  203. WriteUInt32 (startub_stub.Length > 0 ? startub_stub.Start : 0); // EntryPointRVA
  204. WriteUInt32 (text_rva); // BaseOfCode
  205. if (!pe64) {
  206. WriteUInt32 (0); // BaseOfData
  207. WriteUInt32 ((uint) image_base); // ImageBase
  208. } else {
  209. WriteUInt64 (image_base); // ImageBase
  210. }
  211. WriteUInt32 (section_alignment); // SectionAlignment
  212. WriteUInt32 (file_alignment); // FileAlignment
  213. WriteUInt16 (4); // OSMajor
  214. WriteUInt16 (0); // OSMinor
  215. WriteUInt16 (0); // UserMajor
  216. WriteUInt16 (0); // UserMinor
  217. WriteUInt16 (4); // SubSysMajor
  218. WriteUInt16 (0); // SubSysMinor
  219. WriteUInt32 (0); // Reserved
  220. var last_section = LastSection();
  221. WriteUInt32 (last_section.VirtualAddress + Align (last_section.VirtualSize, section_alignment)); // ImageSize
  222. WriteUInt32 (text.PointerToRawData); // HeaderSize
  223. WriteUInt32 (0); // Checksum
  224. WriteUInt16 (GetSubSystem ()); // SubSystem
  225. WriteUInt16 ((ushort) module.Characteristics); // DLLFlags
  226. const ulong stack_reserve = 0x100000;
  227. const ulong stack_commit = 0x1000;
  228. const ulong heap_reserve = 0x100000;
  229. const ulong heap_commit = 0x1000;
  230. if (!pe64) {
  231. WriteUInt32 ((uint) stack_reserve);
  232. WriteUInt32 ((uint) stack_commit);
  233. WriteUInt32 ((uint) heap_reserve);
  234. WriteUInt32 ((uint) heap_commit);
  235. } else {
  236. WriteUInt64 (stack_reserve);
  237. WriteUInt64 (stack_commit);
  238. WriteUInt64 (heap_reserve);
  239. WriteUInt64 (heap_commit);
  240. }
  241. WriteUInt32 (0); // LoaderFlags
  242. WriteUInt32 (16); // NumberOfDataDir
  243. WriteZeroDataDirectory (); // ExportTable
  244. WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportDirectory)); // ImportTable
  245. if (rsrc != null) { // ResourceTable
  246. WriteUInt32 (rsrc.VirtualAddress);
  247. WriteUInt32 (rsrc.VirtualSize);
  248. } else
  249. WriteZeroDataDirectory ();
  250. WriteZeroDataDirectory (); // ExceptionTable
  251. WriteZeroDataDirectory (); // CertificateTable
  252. WriteUInt32 (reloc != null ? reloc.VirtualAddress : 0); // BaseRelocationTable
  253. WriteUInt32 (reloc != null ? reloc.VirtualSize : 0);
  254. if (text_map.GetLength (TextSegment.DebugDirectory) > 0) {
  255. WriteUInt32 (text_map.GetRVA (TextSegment.DebugDirectory));
  256. WriteUInt32 (28u);
  257. } else
  258. WriteZeroDataDirectory ();
  259. WriteZeroDataDirectory (); // Copyright
  260. WriteZeroDataDirectory (); // GlobalPtr
  261. WriteZeroDataDirectory (); // TLSTable
  262. WriteZeroDataDirectory (); // LoadConfigTable
  263. WriteZeroDataDirectory (); // BoundImport
  264. WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportAddressTable)); // IAT
  265. WriteZeroDataDirectory (); // DelayImportDesc
  266. WriteDataDirectory (text_map.GetDataDirectory (TextSegment.CLIHeader)); // CLIHeader
  267. WriteZeroDataDirectory (); // Reserved
  268. }
  269. void WriteZeroDataDirectory ()
  270. {
  271. WriteUInt32 (0);
  272. WriteUInt32 (0);
  273. }
  274. ushort GetSubSystem ()
  275. {
  276. switch (module.Kind) {
  277. case ModuleKind.Console:
  278. case ModuleKind.Dll:
  279. case ModuleKind.NetModule:
  280. return 0x3;
  281. case ModuleKind.Windows:
  282. return 0x2;
  283. default:
  284. throw new ArgumentOutOfRangeException ();
  285. }
  286. }
  287. void WriteSectionHeaders ()
  288. {
  289. WriteSection (text, 0x60000020);
  290. if (rsrc != null)
  291. WriteSection (rsrc, 0x40000040);
  292. if (reloc != null)
  293. WriteSection (reloc, 0x42000040);
  294. }
  295. void WriteSection (Section section, uint characteristics)
  296. {
  297. var name = new byte [8];
  298. var sect_name = section.Name;
  299. for (int i = 0; i < sect_name.Length; i++)
  300. name [i] = (byte) sect_name [i];
  301. WriteBytes (name);
  302. WriteUInt32 (section.VirtualSize);
  303. WriteUInt32 (section.VirtualAddress);
  304. WriteUInt32 (section.SizeOfRawData);
  305. WriteUInt32 (section.PointerToRawData);
  306. WriteUInt32 (0); // PointerToRelocations
  307. WriteUInt32 (0); // PointerToLineNumbers
  308. WriteUInt16 (0); // NumberOfRelocations
  309. WriteUInt16 (0); // NumberOfLineNumbers
  310. WriteUInt32 (characteristics);
  311. }
  312. void MoveTo (uint pointer)
  313. {
  314. BaseStream.Seek (pointer, SeekOrigin.Begin);
  315. }
  316. void MoveToRVA (Section section, RVA rva)
  317. {
  318. BaseStream.Seek (section.PointerToRawData + rva - section.VirtualAddress, SeekOrigin.Begin);
  319. }
  320. void MoveToRVA (TextSegment segment)
  321. {
  322. MoveToRVA (text, text_map.GetRVA (segment));
  323. }
  324. void WriteRVA (RVA rva)
  325. {
  326. if (!pe64)
  327. WriteUInt32 (rva);
  328. else
  329. WriteUInt64 (rva);
  330. }
  331. void WriteText ()
  332. {
  333. MoveTo (text.PointerToRawData);
  334. // ImportAddressTable
  335. if (!pe64) {
  336. WriteRVA (text_map.GetRVA (TextSegment.ImportHintNameTable));
  337. WriteRVA (0);
  338. }
  339. // CLIHeader
  340. WriteUInt32 (0x48);
  341. WriteUInt16 (2);
  342. WriteUInt16 ((ushort) ((module.Runtime <= TargetRuntime.Net_1_1) ? 0 : 5));
  343. WriteUInt32 (text_map.GetRVA (TextSegment.MetadataHeader));
  344. WriteUInt32 (GetMetadataLength ());
  345. WriteUInt32 ((uint) module.Attributes);
  346. WriteUInt32 (metadata.entry_point.ToUInt32 ());
  347. WriteDataDirectory (text_map.GetDataDirectory (TextSegment.Resources));
  348. WriteDataDirectory (text_map.GetDataDirectory (TextSegment.StrongNameSignature));
  349. WriteZeroDataDirectory (); // CodeManagerTable
  350. WriteZeroDataDirectory (); // VTableFixups
  351. WriteZeroDataDirectory (); // ExportAddressTableJumps
  352. WriteZeroDataDirectory (); // ManagedNativeHeader
  353. // Code
  354. MoveToRVA (TextSegment.Code);
  355. WriteBuffer (metadata.code);
  356. // Resources
  357. MoveToRVA (TextSegment.Resources);
  358. WriteBuffer (metadata.resources);
  359. // Data
  360. if (metadata.data.length > 0) {
  361. MoveToRVA (TextSegment.Data);
  362. WriteBuffer (metadata.data);
  363. }
  364. // StrongNameSignature
  365. // stays blank
  366. // MetadataHeader
  367. MoveToRVA (TextSegment.MetadataHeader);
  368. WriteMetadataHeader ();
  369. WriteMetadata ();
  370. // DebugDirectory
  371. if (text_map.GetLength (TextSegment.DebugDirectory) > 0) {
  372. MoveToRVA (TextSegment.DebugDirectory);
  373. WriteDebugDirectory ();
  374. }
  375. if (pe64)
  376. return;
  377. // ImportDirectory
  378. MoveToRVA (TextSegment.ImportDirectory);
  379. WriteImportDirectory ();
  380. // StartupStub
  381. MoveToRVA (TextSegment.StartupStub);
  382. WriteStartupStub ();
  383. }
  384. uint GetMetadataLength ()
  385. {
  386. return text_map.GetRVA (TextSegment.DebugDirectory) - text_map.GetRVA (TextSegment.MetadataHeader);
  387. }
  388. void WriteMetadataHeader ()
  389. {
  390. WriteUInt32 (0x424a5342); // Signature
  391. WriteUInt16 (1); // MajorVersion
  392. WriteUInt16 (1); // MinorVersion
  393. WriteUInt32 (0); // Reserved
  394. var version = GetZeroTerminatedString (GetVersion ());
  395. WriteUInt32 ((uint) version.Length);
  396. WriteBytes (version);
  397. WriteUInt16 (0); // Flags
  398. WriteUInt16 (GetStreamCount ());
  399. uint offset = text_map.GetRVA (TextSegment.TableHeap) - text_map.GetRVA (TextSegment.MetadataHeader);
  400. WriteStreamHeader (ref offset, TextSegment.TableHeap, "#~");
  401. WriteStreamHeader (ref offset, TextSegment.StringHeap, "#Strings");
  402. WriteStreamHeader (ref offset, TextSegment.UserStringHeap, "#US");
  403. WriteStreamHeader (ref offset, TextSegment.GuidHeap, "#GUID");
  404. WriteStreamHeader (ref offset, TextSegment.BlobHeap, "#Blob");
  405. }
  406. string GetVersion ()
  407. {
  408. switch (module.Runtime) {
  409. case TargetRuntime.Net_1_0:
  410. return "v1.0.3705";
  411. case TargetRuntime.Net_1_1:
  412. return "v1.1.4322";
  413. case TargetRuntime.Net_2_0:
  414. return "v2.0.50727";
  415. case TargetRuntime.Net_4_0:
  416. default:
  417. return "v4.0.30319";
  418. }
  419. }
  420. ushort GetStreamCount ()
  421. {
  422. return (ushort) (
  423. 1 // #~
  424. + 1 // #Strings
  425. + (metadata.user_string_heap.IsEmpty ? 0 : 1) // #US
  426. + 1 // GUID
  427. + (metadata.blob_heap.IsEmpty ? 0 : 1)); // #Blob
  428. }
  429. void WriteStreamHeader (ref uint offset, TextSegment heap, string name)
  430. {
  431. var length = (uint) text_map.GetLength (heap);
  432. if (length == 0)
  433. return;
  434. WriteUInt32 (offset);
  435. WriteUInt32 (length);
  436. WriteBytes (GetZeroTerminatedString (name));
  437. offset += length;
  438. }
  439. static byte [] GetZeroTerminatedString (string @string)
  440. {
  441. return GetString (@string, (@string.Length + 1 + 3) & ~3);
  442. }
  443. static byte [] GetSimpleString (string @string)
  444. {
  445. return GetString (@string, @string.Length);
  446. }
  447. static byte [] GetString (string @string, int length)
  448. {
  449. var bytes = new byte [length];
  450. for (int i = 0; i < @string.Length; i++)
  451. bytes [i] = (byte) @string [i];
  452. return bytes;
  453. }
  454. void WriteMetadata ()
  455. {
  456. WriteHeap (TextSegment.TableHeap, metadata.table_heap);
  457. WriteHeap (TextSegment.StringHeap, metadata.string_heap);
  458. WriteHeap (TextSegment.UserStringHeap, metadata.user_string_heap);
  459. WriteGuidHeap ();
  460. WriteHeap (TextSegment.BlobHeap, metadata.blob_heap);
  461. }
  462. void WriteHeap (TextSegment heap, HeapBuffer buffer)
  463. {
  464. if (buffer.IsEmpty)
  465. return;
  466. MoveToRVA (heap);
  467. WriteBuffer (buffer);
  468. }
  469. void WriteGuidHeap ()
  470. {
  471. MoveToRVA (TextSegment.GuidHeap);
  472. WriteBytes (module.Mvid.ToByteArray ());
  473. }
  474. void WriteDebugDirectory ()
  475. {
  476. WriteInt32 (debug_directory.Characteristics);
  477. WriteUInt32 (time_stamp);
  478. WriteInt16 (debug_directory.MajorVersion);
  479. WriteInt16 (debug_directory.MinorVersion);
  480. WriteInt32 (debug_directory.Type);
  481. WriteInt32 (debug_directory.SizeOfData);
  482. WriteInt32 (debug_directory.AddressOfRawData);
  483. WriteInt32 ((int) BaseStream.Position + 4);
  484. WriteBytes (debug_data);
  485. }
  486. void WriteImportDirectory ()
  487. {
  488. WriteUInt32 (text_map.GetRVA (TextSegment.ImportDirectory) + 40); // ImportLookupTable
  489. WriteUInt32 (0); // DateTimeStamp
  490. WriteUInt32 (0); // ForwarderChain
  491. WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable) + 14);
  492. WriteUInt32 (text_map.GetRVA (TextSegment.ImportAddressTable));
  493. Advance (20);
  494. // ImportLookupTable
  495. WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable));
  496. // ImportHintNameTable
  497. MoveToRVA (TextSegment.ImportHintNameTable);
  498. WriteUInt16 (0); // Hint
  499. WriteBytes (GetRuntimeMain ());
  500. WriteByte (0);
  501. WriteBytes (GetSimpleString ("mscoree.dll"));
  502. WriteUInt16 (0);
  503. }
  504. byte [] GetRuntimeMain ()
  505. {
  506. return module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule
  507. ? GetSimpleString ("_CorDllMain")
  508. : GetSimpleString ("_CorExeMain");
  509. }
  510. void WriteStartupStub ()
  511. {
  512. switch (module.Architecture) {
  513. case TargetArchitecture.I386:
  514. WriteUInt16 (0x25ff);
  515. WriteUInt32 ((uint) image_base + text_map.GetRVA (TextSegment.ImportAddressTable));
  516. return;
  517. default:
  518. throw new NotSupportedException ();
  519. }
  520. }
  521. void WriteRsrc ()
  522. {
  523. MoveTo (rsrc.PointerToRawData);
  524. WriteBuffer (win32_resources);
  525. }
  526. void WriteReloc ()
  527. {
  528. MoveTo (reloc.PointerToRawData);
  529. var reloc_rva = text_map.GetRVA (TextSegment.StartupStub);
  530. reloc_rva += module.Architecture == TargetArchitecture.IA64 ? 0x20u : 2;
  531. var page_rva = reloc_rva & ~0xfffu;
  532. WriteUInt32 (page_rva); // PageRVA
  533. WriteUInt32 (0x000c); // Block Size
  534. switch (module.Architecture) {
  535. case TargetArchitecture.I386:
  536. WriteUInt32 (0x3000 + reloc_rva - page_rva);
  537. break;
  538. default:
  539. throw new NotSupportedException();
  540. }
  541. WriteBytes (new byte [file_alignment - reloc.VirtualSize]);
  542. }
  543. public void WriteImage ()
  544. {
  545. WriteDOSHeader ();
  546. WritePEFileHeader ();
  547. WriteOptionalHeaders ();
  548. WriteSectionHeaders ();
  549. WriteText ();
  550. if (rsrc != null)
  551. WriteRsrc ();
  552. if (reloc != null)
  553. WriteReloc ();
  554. }
  555. TextMap BuildTextMap ()
  556. {
  557. var map = metadata.text_map;
  558. map.AddMap (TextSegment.Code, metadata.code.length, !pe64 ? 4 : 16);
  559. map.AddMap (TextSegment.Resources, metadata.resources.length, 8);
  560. map.AddMap (TextSegment.Data, metadata.data.length, 4);
  561. if (metadata.data.length > 0)
  562. metadata.table_heap.FixupData (map.GetRVA (TextSegment.Data));
  563. map.AddMap (TextSegment.StrongNameSignature, GetStrongNameLength (), 4);
  564. map.AddMap (TextSegment.MetadataHeader, GetMetadataHeaderLength ());
  565. map.AddMap (TextSegment.TableHeap, metadata.table_heap.length, 4);
  566. map.AddMap (TextSegment.StringHeap, metadata.string_heap.length, 4);
  567. map.AddMap (TextSegment.UserStringHeap, metadata.user_string_heap.IsEmpty ? 0 : metadata.user_string_heap.length, 4);
  568. map.AddMap (TextSegment.GuidHeap, 16);
  569. map.AddMap (TextSegment.BlobHeap, metadata.blob_heap.IsEmpty ? 0 : metadata.blob_heap.length, 4);
  570. int debug_dir_len = 0;
  571. if (!debug_data.IsNullOrEmpty ()) {
  572. const int debug_dir_header_len = 28;
  573. debug_directory.AddressOfRawData = (int) map.GetNextRVA (TextSegment.BlobHeap) + debug_dir_header_len;
  574. debug_dir_len = debug_data.Length + debug_dir_header_len;
  575. }
  576. map.AddMap (TextSegment.DebugDirectory, debug_dir_len, 4);
  577. if (pe64) {
  578. var start = map.GetNextRVA (TextSegment.DebugDirectory);
  579. map.AddMap (TextSegment.ImportDirectory, new Range (start, 0));
  580. map.AddMap (TextSegment.ImportHintNameTable, new Range (start, 0));
  581. map.AddMap (TextSegment.StartupStub, new Range (start, 0));
  582. return map;
  583. }
  584. RVA import_dir_rva = map.GetNextRVA (TextSegment.DebugDirectory);
  585. RVA import_hnt_rva = import_dir_rva + 48u;
  586. import_hnt_rva = (import_hnt_rva + 15u) & ~15u;
  587. uint import_dir_len = (import_hnt_rva - import_dir_rva) + 27u;
  588. RVA startup_stub_rva = import_dir_rva + import_dir_len;
  589. startup_stub_rva = module.Architecture == TargetArchitecture.IA64
  590. ? (startup_stub_rva + 15u) & ~15u
  591. : 2 + ((startup_stub_rva + 3u) & ~3u);
  592. map.AddMap (TextSegment.ImportDirectory, new Range (import_dir_rva, import_dir_len));
  593. map.AddMap (TextSegment.ImportHintNameTable, new Range (import_hnt_rva, 0));
  594. map.AddMap (TextSegment.StartupStub, new Range (startup_stub_rva, GetStartupStubLength ()));
  595. return map;
  596. }
  597. uint GetStartupStubLength ()
  598. {
  599. switch (module.Architecture) {
  600. case TargetArchitecture.I386:
  601. return 6;
  602. default:
  603. throw new NotSupportedException ();
  604. }
  605. }
  606. int GetMetadataHeaderLength ()
  607. {
  608. return
  609. // MetadataHeader
  610. 40
  611. // #~ header
  612. + 12
  613. // #Strings header
  614. + 20
  615. // #US header
  616. + (metadata.user_string_heap.IsEmpty ? 0 : 12)
  617. // #GUID header
  618. + 16
  619. // #Blob header
  620. + (metadata.blob_heap.IsEmpty ? 0 : 16);
  621. }
  622. int GetStrongNameLength ()
  623. {
  624. if (module.Assembly == null)
  625. return 0;
  626. var public_key = module.Assembly.Name.PublicKey;
  627. if (public_key.IsNullOrEmpty ())
  628. return 0;
  629. // in fx 2.0 the key may be from 384 to 16384 bits
  630. // so we must calculate the signature size based on
  631. // the size of the public key (minus the 32 byte header)
  632. int size = public_key.Length;
  633. if (size > 32)
  634. return size - 32;
  635. // note: size == 16 for the ECMA "key" which is replaced
  636. // by the runtime with a 1024 bits key (128 bytes)
  637. return 128; // default strongname signature size
  638. }
  639. public DataDirectory GetStrongNameSignatureDirectory ()
  640. {
  641. return text_map.GetDataDirectory (TextSegment.StrongNameSignature);
  642. }
  643. public uint GetHeaderSize ()
  644. {
  645. return pe_header_size + (sections * section_header_size);
  646. }
  647. void PatchWin32Resources (ByteBuffer resources)
  648. {
  649. PatchResourceDirectoryTable (resources);
  650. }
  651. void PatchResourceDirectoryTable (ByteBuffer resources)
  652. {
  653. resources.Advance (12);
  654. var entries = resources.ReadUInt16 () + resources.ReadUInt16 ();
  655. for (int i = 0; i < entries; i++)
  656. PatchResourceDirectoryEntry (resources);
  657. }
  658. void PatchResourceDirectoryEntry (ByteBuffer resources)
  659. {
  660. resources.Advance (4);
  661. var child = resources.ReadUInt32 ();
  662. var position = resources.position;
  663. resources.position = (int) child & 0x7fffffff;
  664. if ((child & 0x80000000) != 0)
  665. PatchResourceDirectoryTable (resources);
  666. else
  667. PatchResourceDataEntry (resources);
  668. resources.position = position;
  669. }
  670. void PatchResourceDataEntry (ByteBuffer resources)
  671. {
  672. var old_rsrc = GetImageResourceSection ();
  673. var rva = resources.ReadUInt32 ();
  674. resources.position -= 4;
  675. resources.WriteUInt32 (rva - old_rsrc.VirtualAddress + rsrc.VirtualAddress);
  676. }
  677. }
  678. }
  679. #endif