~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/Mono.Cecil/Mono.Cecil/Mono.Cecil.PE/ImageWriter.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// ImageWriter.cs
 
3
//
 
4
// Author:
 
5
//   Jb Evain (jbevain@gmail.com)
 
6
//
 
7
// Copyright (c) 2008 - 2010 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
 
 
29
using System;
 
30
using System.IO;
 
31
 
 
32
#if !READ_ONLY
 
33
 
 
34
using Mono.Cecil.Cil;
 
35
using Mono.Cecil.Metadata;
 
36
 
 
37
using RVA = System.UInt32;
 
38
 
 
39
namespace 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