~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/reflect/Writer/TextSection.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2008-2011 Jeroen Frijters
 
3
 
 
4
  This software is provided 'as-is', without any express or implied
 
5
  warranty.  In no event will the authors be held liable for any damages
 
6
  arising from the use of this software.
 
7
 
 
8
  Permission is granted to anyone to use this software for any purpose,
 
9
  including commercial applications, and to alter it and redistribute it
 
10
  freely, subject to the following restrictions:
 
11
 
 
12
  1. The origin of this software must not be misrepresented; you must not
 
13
     claim that you wrote the original software. If you use this software
 
14
     in a product, an acknowledgment in the product documentation would be
 
15
     appreciated but is not required.
 
16
  2. Altered source versions must be plainly marked as such, and must not be
 
17
     misrepresented as being the original software.
 
18
  3. This notice may not be removed or altered from any source distribution.
 
19
 
 
20
  Jeroen Frijters
 
21
  jeroen@frijters.net
 
22
  
 
23
*/
 
24
using System;
 
25
using System.Diagnostics;
 
26
using System.IO;
 
27
using System.Collections.Generic;
 
28
using System.Text;
 
29
using IKVM.Reflection.Emit;
 
30
using IKVM.Reflection.Impl;
 
31
using IKVM.Reflection.Metadata;
 
32
 
 
33
namespace IKVM.Reflection.Writer
 
34
{
 
35
        sealed class TextSection
 
36
        {
 
37
                private readonly PEWriter peWriter;
 
38
                private readonly CliHeader cliHeader;
 
39
                private readonly ModuleBuilder moduleBuilder;
 
40
                private readonly uint strongNameSignatureLength;
 
41
                private readonly ExportTables exportTables;
 
42
 
 
43
                internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, int strongNameSignatureLength)
 
44
                {
 
45
                        this.peWriter = peWriter;
 
46
                        this.cliHeader = cliHeader;
 
47
                        this.moduleBuilder = moduleBuilder;
 
48
                        this.strongNameSignatureLength = (uint)strongNameSignatureLength;
 
49
                        if (moduleBuilder.unmanagedExports.Count != 0)
 
50
                        {
 
51
                                this.exportTables = new ExportTables(this);
 
52
                        }
 
53
                }
 
54
 
 
55
                internal uint PointerToRawData
 
56
                {
 
57
                        get { return peWriter.ToFileAlignment(peWriter.HeaderSize); }
 
58
                }
 
59
 
 
60
                internal uint BaseRVA
 
61
                {
 
62
                        get { return 0x2000; }
 
63
                }
 
64
 
 
65
                internal uint ImportAddressTableRVA
 
66
                {
 
67
                        get { return BaseRVA; }
 
68
                }
 
69
 
 
70
                internal uint ImportAddressTableLength
 
71
                {
 
72
                        get
 
73
                        {
 
74
                                switch (peWriter.Headers.FileHeader.Machine)
 
75
                                {
 
76
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
77
                                                return 8;
 
78
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
 
79
                                                return 0;
 
80
                                        default:
 
81
                                                return 16;
 
82
                                }
 
83
                        }
 
84
                }
 
85
 
 
86
                internal uint ComDescriptorRVA
 
87
                {
 
88
                        get { return ImportAddressTableRVA + ImportAddressTableLength; }
 
89
                }
 
90
 
 
91
                internal uint ComDescriptorLength
 
92
                {
 
93
                        get { return cliHeader.Cb; }
 
94
                }
 
95
 
 
96
                internal uint MethodBodiesRVA
 
97
                {
 
98
                        get { return (ComDescriptorRVA + ComDescriptorLength + 7) & ~7U; }
 
99
                }
 
100
 
 
101
                private uint MethodBodiesLength
 
102
                {
 
103
                        get { return (uint)moduleBuilder.methodBodies.Length; }
 
104
                }
 
105
 
 
106
                private uint ResourcesRVA
 
107
                {
 
108
                        get
 
109
                        {
 
110
                                switch (peWriter.Headers.FileHeader.Machine)
 
111
                                {
 
112
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
113
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
 
114
                                                return (MethodBodiesRVA + MethodBodiesLength + 3) & ~3U;
 
115
                                        default:
 
116
                                                return (MethodBodiesRVA + MethodBodiesLength + 15) & ~15U;
 
117
                                }
 
118
                        }
 
119
                }
 
120
 
 
121
                private uint ResourcesLength
 
122
                {
 
123
                        get { return (uint)moduleBuilder.manifestResources.Length; }
 
124
                }
 
125
 
 
126
                internal uint StrongNameSignatureRVA
 
127
                {
 
128
                        get
 
129
                        {
 
130
                                return (ResourcesRVA + ResourcesLength + 3) & ~3U;
 
131
                        }
 
132
                }
 
133
 
 
134
                internal uint StrongNameSignatureLength
 
135
                {
 
136
                        get
 
137
                        {
 
138
                                return strongNameSignatureLength;
 
139
                        }
 
140
                }
 
141
 
 
142
                private uint MetadataRVA
 
143
                {
 
144
                        get
 
145
                        {
 
146
                                return (StrongNameSignatureRVA + StrongNameSignatureLength + 3) & ~3U;
 
147
                        }
 
148
                }
 
149
 
 
150
                private uint MetadataLength
 
151
                {
 
152
                        get { return (uint)moduleBuilder.MetadataLength; }
 
153
                }
 
154
 
 
155
                private uint VTableFixupsRVA
 
156
                {
 
157
                        get { return (MetadataRVA + MetadataLength + 7) & ~7U; }
 
158
                }
 
159
 
 
160
                private uint VTableFixupsLength
 
161
                {
 
162
                        get { return (uint)moduleBuilder.vtablefixups.Count * 8; }
 
163
                }
 
164
 
 
165
                internal uint DebugDirectoryRVA
 
166
                {
 
167
                        get { return VTableFixupsRVA + VTableFixupsLength; }
 
168
                }
 
169
 
 
170
                internal uint DebugDirectoryLength
 
171
                {
 
172
                        get
 
173
                        {
 
174
                                if (DebugDirectoryContentsLength != 0)
 
175
                                {
 
176
                                        return 28;
 
177
                                }
 
178
                                return 0;
 
179
                        }
 
180
                }
 
181
 
 
182
                private uint DebugDirectoryContentsLength
 
183
                {
 
184
                        get
 
185
                        {
 
186
                                if (moduleBuilder.symbolWriter != null)
 
187
                                {
 
188
                                        IMAGE_DEBUG_DIRECTORY idd = new IMAGE_DEBUG_DIRECTORY();
 
189
                                        return (uint)SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd).Length;
 
190
                                }
 
191
                                return 0;
 
192
                        }
 
193
                }
 
194
 
 
195
                internal uint ExportDirectoryRVA
 
196
                {
 
197
                        get { return (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength + 15) & ~15U; }
 
198
                }
 
199
 
 
200
                internal uint ExportDirectoryLength
 
201
                {
 
202
                        get { return moduleBuilder.unmanagedExports.Count == 0 ? 0U : 40U; }
 
203
                }
 
204
 
 
205
                private uint ExportTablesRVA
 
206
                {
 
207
                        get { return ExportDirectoryRVA + ExportDirectoryLength; }
 
208
                }
 
209
 
 
210
                private uint ExportTablesLength
 
211
                {
 
212
                        get { return exportTables == null ? 0U : exportTables.Length; }
 
213
                }
 
214
 
 
215
                internal uint ImportDirectoryRVA
 
216
                {
 
217
                        // on AMD64 (and probably IA64) the import directory needs to be 16 byte aligned (on I386 4 byte alignment is sufficient)
 
218
                        get { return (ExportTablesRVA + ExportTablesLength + 15) & ~15U; }
 
219
                }
 
220
 
 
221
                internal uint ImportDirectoryLength
 
222
                {
 
223
                        get
 
224
                        {
 
225
                                switch (peWriter.Headers.FileHeader.Machine)
 
226
                                {
 
227
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
 
228
                                                return 0;
 
229
                                        default:
 
230
                                                return (ImportHintNameTableRVA - ImportDirectoryRVA) + 27;
 
231
                                }
 
232
                        }
 
233
                }
 
234
 
 
235
                private uint ImportHintNameTableRVA
 
236
                {
 
237
                        get
 
238
                        {
 
239
                                if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
 
240
                                {
 
241
                                        return (ImportDirectoryRVA + 48 + 15) & ~15U;
 
242
                                }
 
243
                                else
 
244
                                {
 
245
                                        return (ImportDirectoryRVA + 48 + 4 + 15) & ~15U;
 
246
                                }
 
247
                        }
 
248
                }
 
249
 
 
250
                internal uint StartupStubRVA
 
251
                {
 
252
                        get
 
253
                        {
 
254
                                if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
 
255
                                {
 
256
                                        // note that the alignment is driven by the requirement that the two relocation fixups are in a single page
 
257
                                        return (ImportDirectoryRVA + ImportDirectoryLength + 15U) & ~15U;
 
258
                                }
 
259
                                else
 
260
                                {
 
261
                                        // the additional 2 bytes padding are to align the address in the jump (which is a relocation fixup)
 
262
                                        return 2 + ((ImportDirectoryRVA + ImportDirectoryLength + 3U) & ~3U);
 
263
                                }
 
264
                        }
 
265
                }
 
266
 
 
267
                internal uint StartupStubLength
 
268
                {
 
269
                        get
 
270
                        {
 
271
                                switch (peWriter.Headers.FileHeader.Machine)
 
272
                                {
 
273
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
274
                                                return 6;
 
275
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
 
276
                                                return 12;
 
277
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64:
 
278
                                                return 48;
 
279
                                        default:
 
280
                                                return 0;
 
281
                                }
 
282
                        }
 
283
                }
 
284
 
 
285
                private void WriteRVA(MetadataWriter mw, uint rva)
 
286
                {
 
287
                        switch (peWriter.Headers.FileHeader.Machine)
 
288
                        {
 
289
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
290
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM:
 
291
                                        mw.Write(rva);
 
292
                                        break;
 
293
                                default:
 
294
                                        mw.Write((ulong)rva);
 
295
                                        break;
 
296
                        }
 
297
                }
 
298
 
 
299
                internal void Write(MetadataWriter mw, uint sdataRVA)
 
300
                {
 
301
                        // Now that we're ready to start writing, we need to do some fix ups
 
302
                        moduleBuilder.TypeRef.Fixup(moduleBuilder);
 
303
                        moduleBuilder.MethodDef.Fixup(this);
 
304
                        moduleBuilder.MethodImpl.Fixup(moduleBuilder);
 
305
                        moduleBuilder.MethodSemantics.Fixup(moduleBuilder);
 
306
                        moduleBuilder.InterfaceImpl.Fixup();
 
307
                        moduleBuilder.ResolveInterfaceImplPseudoTokens();
 
308
                        moduleBuilder.MemberRef.Fixup(moduleBuilder);
 
309
                        moduleBuilder.Constant.Fixup(moduleBuilder);
 
310
                        moduleBuilder.FieldMarshal.Fixup(moduleBuilder);
 
311
                        moduleBuilder.DeclSecurity.Fixup(moduleBuilder);
 
312
                        moduleBuilder.GenericParam.Fixup(moduleBuilder);
 
313
                        moduleBuilder.CustomAttribute.Fixup(moduleBuilder);
 
314
                        moduleBuilder.FieldLayout.Fixup(moduleBuilder);
 
315
                        moduleBuilder.FieldRVA.Fixup(moduleBuilder, (int)sdataRVA, (int)this.MethodBodiesRVA);
 
316
                        moduleBuilder.ImplMap.Fixup(moduleBuilder);
 
317
                        moduleBuilder.ExportedType.Fixup(moduleBuilder);
 
318
                        moduleBuilder.ManifestResource.Fixup(moduleBuilder);
 
319
                        moduleBuilder.MethodSpec.Fixup(moduleBuilder);
 
320
                        moduleBuilder.GenericParamConstraint.Fixup(moduleBuilder);
 
321
 
 
322
                        // Import Address Table
 
323
                        AssertRVA(mw, ImportAddressTableRVA);
 
324
                        if (ImportAddressTableLength != 0)
 
325
                        {
 
326
                                WriteRVA(mw, ImportHintNameTableRVA);
 
327
                                WriteRVA(mw, 0);
 
328
                        }
 
329
 
 
330
                        // CLI Header
 
331
                        AssertRVA(mw, ComDescriptorRVA);
 
332
                        cliHeader.MetaData.VirtualAddress = MetadataRVA;
 
333
                        cliHeader.MetaData.Size = MetadataLength;
 
334
                        if (ResourcesLength != 0)
 
335
                        {
 
336
                                cliHeader.Resources.VirtualAddress = ResourcesRVA;
 
337
                                cliHeader.Resources.Size = ResourcesLength;
 
338
                        }
 
339
                        if (StrongNameSignatureLength != 0)
 
340
                        {
 
341
                                cliHeader.StrongNameSignature.VirtualAddress = StrongNameSignatureRVA;
 
342
                                cliHeader.StrongNameSignature.Size = StrongNameSignatureLength;
 
343
                        }
 
344
                        if (VTableFixupsLength != 0)
 
345
                        {
 
346
                                cliHeader.VTableFixups.VirtualAddress = VTableFixupsRVA;
 
347
                                cliHeader.VTableFixups.Size = VTableFixupsLength;
 
348
                        }
 
349
                        cliHeader.Write(mw);
 
350
 
 
351
                        // alignment padding
 
352
                        for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--)
 
353
                        {
 
354
                                mw.Write((byte)0);
 
355
                        }
 
356
 
 
357
                        // Method Bodies
 
358
                        mw.Write(moduleBuilder.methodBodies);
 
359
 
 
360
                        // alignment padding
 
361
                        for (int i = (int)(ResourcesRVA - (MethodBodiesRVA + MethodBodiesLength)); i > 0; i--)
 
362
                        {
 
363
                                mw.Write((byte)0);
 
364
                        }
 
365
 
 
366
                        // Resources
 
367
                        mw.Write(moduleBuilder.manifestResources);
 
368
 
 
369
                        // The strong name signature live here (if it exists), but it will written later
 
370
                        // and the following alignment padding will take care of reserving the space.
 
371
 
 
372
                        // alignment padding
 
373
                        for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--)
 
374
                        {
 
375
                                mw.Write((byte)0);
 
376
                        }
 
377
 
 
378
                        // Metadata
 
379
                        AssertRVA(mw, MetadataRVA);
 
380
                        moduleBuilder.WriteMetadata(mw);
 
381
 
 
382
                        // alignment padding
 
383
                        for (int i = (int)(VTableFixupsRVA - (MetadataRVA + MetadataLength)); i > 0; i--)
 
384
                        {
 
385
                                mw.Write((byte)0);
 
386
                        }
 
387
 
 
388
                        // VTableFixups
 
389
                        AssertRVA(mw, VTableFixupsRVA);
 
390
                        WriteVTableFixups(mw, sdataRVA);
 
391
 
 
392
                        // Debug Directory
 
393
                        AssertRVA(mw, DebugDirectoryRVA);
 
394
                        WriteDebugDirectory(mw);
 
395
 
 
396
                        // alignment padding
 
397
                        for (int i = (int)(ExportDirectoryRVA - (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength)); i > 0; i--)
 
398
                        {
 
399
                                mw.Write((byte)0);
 
400
                        }
 
401
 
 
402
                        // Export Directory
 
403
                        AssertRVA(mw, ExportDirectoryRVA);
 
404
                        WriteExportDirectory(mw);
 
405
 
 
406
                        // Export Tables
 
407
                        AssertRVA(mw, ExportTablesRVA);
 
408
                        WriteExportTables(mw, sdataRVA);
 
409
        
 
410
                        // alignment padding
 
411
                        for (int i = (int)(ImportDirectoryRVA - (ExportTablesRVA + ExportTablesLength)); i > 0; i--)
 
412
                        {
 
413
                                mw.Write((byte)0);
 
414
                        }
 
415
 
 
416
                        // Import Directory
 
417
                        AssertRVA(mw, ImportDirectoryRVA);
 
418
                        if (ImportDirectoryLength != 0)
 
419
                        {
 
420
                                WriteImportDirectory(mw);
 
421
                        }
 
422
 
 
423
                        // alignment padding
 
424
                        for (int i = (int)(StartupStubRVA - (ImportDirectoryRVA + ImportDirectoryLength)); i > 0; i--)
 
425
                        {
 
426
                                mw.Write((byte)0);
 
427
                        }
 
428
 
 
429
                        // Startup Stub
 
430
                        AssertRVA(mw, StartupStubRVA);
 
431
                        if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64)
 
432
                        {
 
433
                                /*
 
434
                                 *   48 A1 00 20 40 00 00 00 00 00        mov         rax,qword ptr [0000000000402000h]
 
435
                                 *   FF E0                                jmp         rax
 
436
                                 */
 
437
                                mw.Write((ushort)0xA148);
 
438
                                mw.Write(peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
 
439
                                mw.Write((ushort)0xE0FF);
 
440
                        }
 
441
                        else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
 
442
                        {
 
443
                                mw.Write(new byte[] {
 
444
                                                0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40, 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
 
445
                                                0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50, 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00
 
446
                                        });
 
447
                                mw.Write(peWriter.Headers.OptionalHeader.ImageBase + StartupStubRVA);
 
448
                                mw.Write(peWriter.Headers.OptionalHeader.ImageBase + BaseRVA);
 
449
                        }
 
450
                        else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
 
451
                        {
 
452
                                mw.Write((ushort)0x25FF);
 
453
                                mw.Write((uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
 
454
                        }
 
455
                }
 
456
 
 
457
                [Conditional("DEBUG")]
 
458
                private void AssertRVA(MetadataWriter mw, uint rva)
 
459
                {
 
460
                        Debug.Assert(mw.Position - PointerToRawData + BaseRVA == rva);
 
461
                }
 
462
 
 
463
                private void WriteVTableFixups(MetadataWriter mw, uint sdataRVA)
 
464
                {
 
465
                        foreach (ModuleBuilder.VTableFixups fixups in moduleBuilder.vtablefixups)
 
466
                        {
 
467
                                mw.Write(fixups.initializedDataOffset + sdataRVA);
 
468
                                mw.Write(fixups.count);
 
469
                                mw.Write(fixups.type);
 
470
                        }
 
471
                }
 
472
 
 
473
                private void WriteDebugDirectory(MetadataWriter mw)
 
474
                {
 
475
                        if (DebugDirectoryLength != 0)
 
476
                        {
 
477
                                IMAGE_DEBUG_DIRECTORY idd = new IMAGE_DEBUG_DIRECTORY();
 
478
                                idd.Characteristics = 0;
 
479
                                idd.TimeDateStamp = peWriter.Headers.FileHeader.TimeDateStamp;
 
480
                                byte[] buf = SymbolSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd);
 
481
                                idd.PointerToRawData = (DebugDirectoryRVA - BaseRVA) + DebugDirectoryLength + PointerToRawData;
 
482
                                idd.AddressOfRawData = DebugDirectoryRVA + DebugDirectoryLength;
 
483
                                mw.Write(idd.Characteristics);
 
484
                                mw.Write(idd.TimeDateStamp);
 
485
                                mw.Write(idd.MajorVersion);
 
486
                                mw.Write(idd.MinorVersion);
 
487
                                mw.Write(idd.Type);
 
488
                                mw.Write(idd.SizeOfData);
 
489
                                mw.Write(idd.AddressOfRawData);
 
490
                                mw.Write(idd.PointerToRawData);
 
491
                                mw.Write(buf);
 
492
                        }
 
493
                }
 
494
 
 
495
                private sealed class ExportTables
 
496
                {
 
497
                        private readonly TextSection text;
 
498
                        internal readonly uint entries;
 
499
                        internal readonly uint ordinalBase;
 
500
                        internal readonly uint nameCount;
 
501
                        internal readonly uint namesLength;
 
502
                        internal readonly uint exportAddressTableRVA;
 
503
                        internal readonly uint exportNamePointerTableRVA;
 
504
                        internal readonly uint exportOrdinalTableRVA;
 
505
                        internal readonly uint namesRVA;
 
506
                        internal readonly uint stubsRVA;
 
507
                        private readonly uint stubLength;
 
508
 
 
509
                        internal ExportTables(TextSection text)
 
510
                        {
 
511
                                this.text = text;
 
512
                                ordinalBase = GetOrdinalBase(out entries);
 
513
                                namesLength = GetExportNamesLength(out nameCount);
 
514
                                exportAddressTableRVA = text.ExportTablesRVA;
 
515
                                exportNamePointerTableRVA = exportAddressTableRVA + 4 * entries;
 
516
                                exportOrdinalTableRVA = exportNamePointerTableRVA + 4 * nameCount;
 
517
                                namesRVA = exportOrdinalTableRVA + 2 * nameCount;
 
518
                                stubsRVA = (namesRVA + namesLength + 15) & ~15U;
 
519
                                // note that we align the stubs to avoid having to deal with the relocation crossing a page boundary
 
520
                                switch (text.peWriter.Headers.FileHeader.Machine)
 
521
                                {
 
522
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
523
                                                stubLength = 8;
 
524
                                                break;
 
525
                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
 
526
                                                stubLength = 16;
 
527
                                                break;
 
528
                                        default:
 
529
                                                throw new NotImplementedException();
 
530
                                }
 
531
                        }
 
532
 
 
533
                        internal uint Length
 
534
                        {
 
535
                                get { return (stubsRVA + stubLength * (uint)text.moduleBuilder.unmanagedExports.Count) - text.ExportTablesRVA; }
 
536
                        }
 
537
 
 
538
                        private uint GetOrdinalBase(out uint entries)
 
539
                        {
 
540
                                uint min = uint.MaxValue;
 
541
                                uint max = uint.MinValue;
 
542
                                foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
 
543
                                {
 
544
                                        uint ordinal = (uint)exp.ordinal;
 
545
                                        min = Math.Min(min, ordinal);
 
546
                                        max = Math.Max(max, ordinal);
 
547
                                }
 
548
                                entries = 1 + (max - min);
 
549
                                return min;
 
550
                        }
 
551
 
 
552
                        private uint GetExportNamesLength(out uint nameCount)
 
553
                        {
 
554
                                nameCount = 0;
 
555
                                // the first name in the names list is the module name (the Export Directory contains a name of the current module)
 
556
                                uint length = (uint)text.moduleBuilder.fileName.Length + 1;
 
557
                                foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
 
558
                                {
 
559
                                        if (exp.name != null)
 
560
                                        {
 
561
                                                nameCount++;
 
562
                                                length += (uint)exp.name.Length + 1;
 
563
                                        }
 
564
                                }
 
565
                                return length;
 
566
                        }
 
567
 
 
568
                        internal void Write(MetadataWriter mw, uint sdataRVA)
 
569
                        {
 
570
                                // sort the exports by ordinal
 
571
                                text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals);
 
572
 
 
573
                                // Now write the Export Address Table
 
574
                                text.AssertRVA(mw, exportAddressTableRVA);
 
575
                                for (int i = 0, pos = 0; i < entries; i++)
 
576
                                {
 
577
                                        if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase)
 
578
                                        {
 
579
                                                mw.Write(stubsRVA + (uint)pos * stubLength);
 
580
                                                pos++;
 
581
                                        }
 
582
                                        else
 
583
                                        {
 
584
                                                mw.Write(0);
 
585
                                        }
 
586
                                }
 
587
 
 
588
                                // sort the exports by name
 
589
                                text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportNames);
 
590
 
 
591
                                // Now write the Export Name Pointer Table
 
592
                                text.AssertRVA(mw, exportNamePointerTableRVA);
 
593
                                uint nameOffset = (uint)text.moduleBuilder.fileName.Length + 1;
 
594
                                foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
 
595
                                {
 
596
                                        if (exp.name != null)
 
597
                                        {
 
598
                                                mw.Write(namesRVA + nameOffset);
 
599
                                                nameOffset += (uint)exp.name.Length + 1;
 
600
                                        }
 
601
                                }
 
602
 
 
603
                                // Now write the Export Ordinal Table
 
604
                                text.AssertRVA(mw, exportOrdinalTableRVA);
 
605
                                foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
 
606
                                {
 
607
                                        if (exp.name != null)
 
608
                                        {
 
609
                                                mw.Write((ushort)(exp.ordinal - ordinalBase));
 
610
                                        }
 
611
                                }
 
612
 
 
613
                                // Now write the actual names
 
614
                                text.AssertRVA(mw, namesRVA);
 
615
                                mw.Write(Encoding.ASCII.GetBytes(text.moduleBuilder.fileName));
 
616
                                mw.Write((byte)0);
 
617
                                foreach (UnmanagedExport exp in text.moduleBuilder.unmanagedExports)
 
618
                                {
 
619
                                        if (exp.name != null)
 
620
                                        {
 
621
                                                mw.Write(Encoding.ASCII.GetBytes(exp.name));
 
622
                                                mw.Write((byte)0);
 
623
                                        }
 
624
                                }
 
625
                                text.AssertRVA(mw, namesRVA + namesLength);
 
626
 
 
627
                                // alignment padding
 
628
                                for (int i = (int)(stubsRVA - (namesRVA + namesLength)); i > 0; i--)
 
629
                                {
 
630
                                        mw.Write((byte)0);
 
631
                                }
 
632
 
 
633
                                // sort the exports by ordinal
 
634
                                text.moduleBuilder.unmanagedExports.Sort(CompareUnmanagedExportOrdinals);
 
635
 
 
636
                                // Now write the stubs
 
637
                                text.AssertRVA(mw, stubsRVA);
 
638
 
 
639
                                for (int i = 0, pos = 0; i < entries; i++)
 
640
                                {
 
641
                                        if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase)
 
642
                                        {
 
643
                                                switch (text.peWriter.Headers.FileHeader.Machine)
 
644
                                                {
 
645
                                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
646
                                                                mw.Write((byte)0xFF);
 
647
                                                                mw.Write((byte)0x25);
 
648
                                                                mw.Write((uint)text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA);
 
649
                                                                mw.Write((short)0);     // alignment
 
650
                                                                break;
 
651
                                                        case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
 
652
                                                                mw.Write((byte)0x48);
 
653
                                                                mw.Write((byte)0xA1);
 
654
                                                                mw.Write(text.peWriter.Headers.OptionalHeader.ImageBase + text.moduleBuilder.unmanagedExports[pos].rva.initializedDataOffset + sdataRVA);
 
655
                                                                mw.Write((byte)0xFF);
 
656
                                                                mw.Write((byte)0xE0);
 
657
                                                                mw.Write(0); // alignment
 
658
                                                                break;
 
659
                                                        default:
 
660
                                                                throw new NotImplementedException();
 
661
                                                }
 
662
                                                pos++;
 
663
                                        }
 
664
                                }
 
665
                        }
 
666
 
 
667
                        private static int CompareUnmanagedExportNames(UnmanagedExport x, UnmanagedExport y)
 
668
                        {
 
669
                                if (x.name == null)
 
670
                                {
 
671
                                        return y.name == null ? 0 : 1;
 
672
                                }
 
673
                                if (y.name == null)
 
674
                                {
 
675
                                        return -1;
 
676
                                }
 
677
                                return x.name.CompareTo(y.name);
 
678
                        }
 
679
 
 
680
                        private static int CompareUnmanagedExportOrdinals(UnmanagedExport x, UnmanagedExport y)
 
681
                        {
 
682
                                return x.ordinal.CompareTo(y.ordinal);
 
683
                        }
 
684
 
 
685
                        internal void WriteRelocations(MetadataWriter mw)
 
686
                        {
 
687
                                // we assume that unmanagedExports is still sorted by ordinal
 
688
                                for (int i = 0, pos = 0; i < entries; i++)
 
689
                                {
 
690
                                        if (text.moduleBuilder.unmanagedExports[pos].ordinal == i + ordinalBase)
 
691
                                        {
 
692
                                                // both I386 and AMD64 have the address at offset 2
 
693
                                                text.WriteRelocationBlock(mw, stubsRVA + 2 + (uint)pos * stubLength);
 
694
                                                pos++;
 
695
                                        }
 
696
                                }
 
697
                        }
 
698
                }
 
699
 
 
700
                private uint GetOrdinalBase(out uint entries)
 
701
                {
 
702
                        uint min = uint.MaxValue;
 
703
                        uint max = uint.MinValue;
 
704
                        foreach (UnmanagedExport exp in moduleBuilder.unmanagedExports)
 
705
                        {
 
706
                                uint ordinal = (uint)exp.ordinal;
 
707
                                min = Math.Min(min, ordinal);
 
708
                                max = Math.Max(max, ordinal);
 
709
                        }
 
710
                        entries = 1 + (max - min);
 
711
                        return min;
 
712
                }
 
713
 
 
714
                private uint GetExportNamesLength(out uint nameCount)
 
715
                {
 
716
                        nameCount = 0;
 
717
                        uint length = 0;
 
718
                        foreach (UnmanagedExport exp in moduleBuilder.unmanagedExports)
 
719
                        {
 
720
                                if (exp.name != null)
 
721
                                {
 
722
                                        nameCount++;
 
723
                                        length += (uint)exp.name.Length + 1;
 
724
                                }
 
725
                        }
 
726
                        return length;
 
727
                }
 
728
 
 
729
                private void WriteExportDirectory(MetadataWriter mw)
 
730
                {
 
731
                        if (ExportDirectoryLength != 0)
 
732
                        {
 
733
                                // Flags
 
734
                                mw.Write(0);
 
735
                                // Date/Time Stamp
 
736
                                mw.Write(peWriter.Headers.FileHeader.TimeDateStamp);
 
737
                                // Major Version
 
738
                                mw.Write((short)0);
 
739
                                // Minor Version
 
740
                                mw.Write((short)0);
 
741
                                // Name RVA
 
742
                                mw.Write(exportTables.namesRVA);
 
743
                                // Ordinal Base
 
744
                                mw.Write(exportTables.ordinalBase);
 
745
                                // Address Table Entries
 
746
                                mw.Write(exportTables.entries);
 
747
                                // Number of Name Pointers
 
748
                                mw.Write(exportTables.nameCount);
 
749
                                // Export Address Table RVA
 
750
                                mw.Write(exportTables.exportAddressTableRVA);
 
751
                                // Name Pointer RVA
 
752
                                mw.Write(exportTables.exportNamePointerTableRVA);
 
753
                                // Ordinal Table RVA
 
754
                                mw.Write(exportTables.exportOrdinalTableRVA);
 
755
                        }
 
756
                }
 
757
 
 
758
                private void WriteExportTables(MetadataWriter mw, uint sdataRVA)
 
759
                {
 
760
                        if (exportTables != null)
 
761
                        {
 
762
                                exportTables.Write(mw, sdataRVA);
 
763
                        }
 
764
                }
 
765
 
 
766
                private void WriteImportDirectory(MetadataWriter mw)
 
767
                {
 
768
                        mw.Write(ImportDirectoryRVA + 40);              // ImportLookupTable
 
769
                        mw.Write(0);                                                    // DateTimeStamp
 
770
                        mw.Write(0);                                                    // ForwarderChain
 
771
                        mw.Write(ImportHintNameTableRVA + 14);  // Name
 
772
                        mw.Write(ImportAddressTableRVA);
 
773
                        mw.Write(new byte[20]);
 
774
                        // Import Lookup Table
 
775
                        mw.Write(ImportHintNameTableRVA);               // Hint/Name Table RVA
 
776
                        int size = 48;
 
777
                        if (peWriter.Headers.FileHeader.Machine != IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
 
778
                        {
 
779
                                size += 4;
 
780
                                mw.Write(0);
 
781
                        }
 
782
                        mw.Write(0);
 
783
 
 
784
                        // alignment padding
 
785
                        for (int i = (int)(ImportHintNameTableRVA - (ImportDirectoryRVA + size)); i > 0; i--)
 
786
                        {
 
787
                                mw.Write((byte)0);
 
788
                        }
 
789
 
 
790
                        // Hint/Name Table
 
791
                        AssertRVA(mw, ImportHintNameTableRVA);
 
792
                        mw.Write((ushort)0);            // Hint
 
793
                        if ((peWriter.Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_DLL) != 0)
 
794
                        {
 
795
                                mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorDllMain"));
 
796
                        }
 
797
                        else
 
798
                        {
 
799
                                mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorExeMain"));
 
800
                        }
 
801
                        mw.Write((byte)0);
 
802
                        // Name
 
803
                        mw.Write(System.Text.Encoding.ASCII.GetBytes("mscoree.dll"));
 
804
                        mw.Write((ushort)0);
 
805
                }
 
806
 
 
807
                internal int Length
 
808
                {
 
809
                        get { return (int)(StartupStubRVA - BaseRVA + StartupStubLength); }
 
810
                }
 
811
 
 
812
                internal void WriteRelocations(MetadataWriter mw)
 
813
                {
 
814
                        uint relocAddress = this.StartupStubRVA;
 
815
                        switch (peWriter.Headers.FileHeader.Machine)
 
816
                        {
 
817
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
818
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
 
819
                                        relocAddress += 2;
 
820
                                        break;
 
821
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64:
 
822
                                        relocAddress += 0x20;
 
823
                                        break;
 
824
                        }
 
825
                        WriteRelocationBlock(mw, relocAddress);
 
826
                        if (exportTables != null)
 
827
                        {
 
828
                                exportTables.WriteRelocations(mw);
 
829
                        }
 
830
                }
 
831
 
 
832
                // note that we're lazy and write a new relocation block for every relocation
 
833
                // even if they are in the same page (since there is typically only one anyway)
 
834
                private void WriteRelocationBlock(MetadataWriter mw, uint relocAddress)
 
835
                {
 
836
                        uint pageRVA = relocAddress & ~0xFFFU;
 
837
                        mw.Write(pageRVA);      // PageRVA
 
838
                        mw.Write(0x000C);       // Block Size
 
839
                        switch (peWriter.Headers.FileHeader.Machine)
 
840
                        {
 
841
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386:
 
842
                                        mw.Write(0x3000 + relocAddress - pageRVA);                              // Type / Offset
 
843
                                        break;
 
844
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64:
 
845
                                        mw.Write(0xA000 + relocAddress - pageRVA);                              // Type / Offset
 
846
                                        break;
 
847
                                case IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64:
 
848
                                        // on IA64 the StartupStubRVA is 16 byte aligned, so these two addresses won't cross a page boundary
 
849
                                        mw.Write((short)(0xA000 + relocAddress - pageRVA));             // Type / Offset
 
850
                                        mw.Write((short)(0xA000 + relocAddress - pageRVA + 8)); // Type / Offset
 
851
                                        break;
 
852
                        }
 
853
                }
 
854
        }
 
855
}