Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2922-DataCompletenessChartPerf/HeuristicLab.ExtLibs/HeuristicLab.Cecil/0.9.5/Mono.Cecil-0.9.5/Mono.Cecil/Mono.Cecil.PE/ImageWriter.cs @ 18242

Last change on this file since 18242 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

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