< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 233
Coverable lines: 233
Total lines: 462
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 62
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Reflection.Internal;
 6using System.Reflection.Metadata;
 7
 8namespace System.Reflection.PortableExecutable
 9{
 10    /// <summary>
 11    /// Managed .text PE section.
 12    /// </summary>
 13    /// <remarks>
 14    /// Contains in the following order:
 15    /// - Import Address Table
 16    /// - COR Header
 17    /// - IL
 18    /// - Metadata
 19    /// - Managed Resource Data
 20    /// - Strong Name Signature
 21    /// - Debug Data (directory and extra info)
 22    /// - Import Table
 23    /// - Name Table
 24    /// - Runtime Startup Stub
 25    /// - Mapped Field Data
 26    /// </remarks>
 27    internal sealed class ManagedTextSection
 28    {
 029        public Characteristics ImageCharacteristics { get; }
 030        public Machine Machine { get; }
 31
 32        /// <summary>
 33        /// The size of IL stream (unaligned).
 34        /// </summary>
 035        public int ILStreamSize { get; }
 36
 37        /// <summary>
 38        /// Total size of metadata (header and all streams).
 39        /// </summary>
 040        public int MetadataSize { get; }
 41
 42        /// <summary>
 43        /// The size of managed resource data stream.
 44        /// </summary>
 045        public int ResourceDataSize { get; }
 46
 47        /// <summary>
 48        /// Size of strong name hash.
 49        /// </summary>
 050        public int StrongNameSignatureSize { get; }
 51
 52        /// <summary>
 53        /// Size of Debug data.
 54        /// </summary>
 055        public int DebugDataSize { get; }
 56
 57        /// <summary>
 58        /// The size of mapped field data stream.
 59        /// Aligned to <see cref="MappedFieldDataAlignment"/>.
 60        /// </summary>
 061        public int MappedFieldDataSize { get; }
 62
 063        public ManagedTextSection(
 064            Characteristics imageCharacteristics,
 065            Machine machine,
 066            int ilStreamSize,
 067            int metadataSize,
 068            int resourceDataSize,
 069            int strongNameSignatureSize,
 070            int debugDataSize,
 071            int mappedFieldDataSize)
 072        {
 073            MetadataSize = metadataSize;
 074            ResourceDataSize = resourceDataSize;
 075            ILStreamSize = ilStreamSize;
 076            MappedFieldDataSize = mappedFieldDataSize;
 077            StrongNameSignatureSize = strongNameSignatureSize;
 078            ImageCharacteristics = imageCharacteristics;
 079            Machine = machine;
 080            DebugDataSize = debugDataSize;
 081        }
 82
 83        /// <summary>
 84        /// If set, the module must include a machine code stub that transfers control to the virtual execution system.
 85        /// </summary>
 086        internal bool RequiresStartupStub => Machine == Machine.I386 || Machine == 0;
 87
 88        /// <summary>
 89        /// If set, the module contains instructions that assume a 64 bit instruction set. For example it may depend on 
 90        /// This may be true even if the module contains only IL instructions because of PlatformInvoke and COM interop.
 91        /// </summary>
 092        internal bool Requires64bits => Machine == Machine.Amd64 || Machine == Machine.IA64 || Machine == Machine.Arm64;
 93
 094        public bool Is32Bit => !Requires64bits;
 95
 96        public const int ManagedResourcesDataAlignment = 8;
 97
 098        private static ReadOnlySpan<byte> CorEntryPointDll => "mscoree.dll"u8;
 099        private ReadOnlySpan<byte> CorEntryPointName => (ImageCharacteristics & Characteristics.Dll) != 0 ? "_CorDllMain
 100
 0101        private int SizeOfImportAddressTable => RequiresStartupStub ? (Is32Bit ? 2 * sizeof(uint) : 2 * sizeof(ulong)) :
 102
 103        // (_is32bit ? 66 : 70);
 104        private int SizeOfImportTable =>
 0105            sizeof(uint) + // RVA
 0106            sizeof(uint) + // 0
 0107            sizeof(uint) + // 0
 0108            sizeof(uint) + // name RVA
 0109            sizeof(uint) + // import address table RVA
 0110            20 +           // ?
 0111            (Is32Bit ? 3 * sizeof(uint) : 2 * sizeof(ulong)) + // import lookup table
 0112            sizeof(ushort) + // hint
 0113            CorEntryPointName.Length +
 0114            1;    // NUL
 115
 116        private static int SizeOfNameTable =>
 0117            CorEntryPointDll.Length + 1 + sizeof(ushort);
 118
 0119        private int SizeOfRuntimeStartupStub => Is32Bit ? 8 : 16;
 120
 121        public const int MappedFieldDataAlignment = 8;
 122
 123        internal int CalculateOffsetToMappedFieldDataStreamUnaligned()
 0124        {
 0125            int result = ComputeOffsetToImportTable();
 126
 0127            if (RequiresStartupStub)
 0128            {
 0129                result += SizeOfImportTable + SizeOfNameTable;
 0130                result = BitArithmetic.Align(result, Is32Bit ? 4 : 8); //optional padding to make startup stub's target 
 0131                result += SizeOfRuntimeStartupStub;
 0132            }
 133
 0134            return result;
 0135        }
 136
 137        public int CalculateOffsetToMappedFieldDataStream()
 0138        {
 0139            int result = CalculateOffsetToMappedFieldDataStreamUnaligned();
 0140            if (MappedFieldDataSize != 0)
 0141            {
 0142                result = BitArithmetic.Align(result, MappedFieldDataAlignment);
 0143            }
 0144            return result;
 0145        }
 146
 147        internal int ComputeOffsetToDebugDirectory()
 0148        {
 0149            return
 0150                ComputeOffsetToMetadata() +
 0151                MetadataSize +
 0152                ResourceDataSize +
 0153                StrongNameSignatureSize;
 0154        }
 155
 156        private int ComputeOffsetToImportTable()
 0157        {
 0158            return
 0159                ComputeOffsetToDebugDirectory() +
 0160                DebugDataSize;
 0161        }
 162
 163        private const int CorHeaderSize =
 164            sizeof(int) +    // header size
 165            sizeof(short) +  // major runtime version
 166            sizeof(short) +  // minor runtime version
 167            sizeof(long) +   // metadata directory
 168            sizeof(int) +    // COR flags
 169            sizeof(int) +    // entry point
 170            sizeof(long) +   // resources directory
 171            sizeof(long) +   // strong name signature directory
 172            sizeof(long) +   // code manager table directory
 173            sizeof(long) +   // vtable fixups directory
 174            sizeof(long) +   // export address table jumps directory
 175            sizeof(long);   // managed-native header directory
 176
 0177        public int OffsetToILStream => SizeOfImportAddressTable + CorHeaderSize;
 178
 179        private int ComputeOffsetToMetadata()
 0180        {
 0181            return OffsetToILStream + BitArithmetic.Align(ILStreamSize, 4);
 0182        }
 183
 184        public int ComputeSizeOfTextSection()
 0185        {
 0186            return CalculateOffsetToMappedFieldDataStream() + MappedFieldDataSize;
 0187        }
 188
 189        public int GetEntryPointAddress(int rva)
 0190        {
 191            // TODO: constants
 0192            return RequiresStartupStub ?
 0193                rva + CalculateOffsetToMappedFieldDataStreamUnaligned() - (Is32Bit ? 6 : 10) :
 0194                0;
 0195        }
 196
 197        public DirectoryEntry GetImportAddressTableDirectoryEntry(int rva)
 0198        {
 0199            return RequiresStartupStub ?
 0200                new DirectoryEntry(rva, SizeOfImportAddressTable) :
 0201                default(DirectoryEntry);
 0202        }
 203
 204        public DirectoryEntry GetImportTableDirectoryEntry(int rva)
 0205        {
 206            // TODO: constants
 0207            return RequiresStartupStub ?
 0208                new DirectoryEntry(rva + ComputeOffsetToImportTable(), (Is32Bit ? 66 : 70) + 13) :
 0209                default(DirectoryEntry);
 0210        }
 211
 212        public DirectoryEntry GetCorHeaderDirectoryEntry(int rva)
 0213        {
 0214            return new DirectoryEntry(rva + SizeOfImportAddressTable, CorHeaderSize);
 0215        }
 216
 217        #region Serialization
 218
 219        /// <summary>
 220        /// Serializes .text section data into a specified <paramref name="builder"/>.
 221        /// </summary>
 222        /// <param name="builder">An empty builder to serialize section data to.</param>
 223        /// <param name="relativeVirtualAddess">Relative virtual address of the section within the containing PE file.</
 224        /// <param name="entryPointTokenOrRelativeVirtualAddress">Entry point token or RVA (<see cref="CorHeader.EntryPo
 225        /// <param name="corFlags">COR Flags (<see cref="CorHeader.Flags"/>).</param>
 226        /// <param name="baseAddress">Base address of the PE image.</param>
 227        /// <param name="metadataBuilder"><see cref="BlobBuilder"/> containing metadata. Must be populated with data. Li
 228        /// <param name="ilBuilder"><see cref="BlobBuilder"/> containing IL stream. Must be populated with data. Linked 
 229        /// <param name="mappedFieldDataBuilderOpt"><see cref="BlobBuilder"/> containing mapped field data. Must be popu
 230        /// <param name="resourceBuilderOpt"><see cref="BlobBuilder"/> containing managed resource data. Must be populat
 231        /// <param name="debugDataBuilderOpt"><see cref="BlobBuilder"/> containing PE debug table and data. Must be popu
 232        /// <param name="strongNameSignature">Blob reserved in the <paramref name="builder"/> for strong name signature.
 233        public void Serialize(
 234            BlobBuilder builder,
 235            int relativeVirtualAddess,
 236            int entryPointTokenOrRelativeVirtualAddress,
 237            CorFlags corFlags,
 238            ulong baseAddress,
 239            BlobBuilder metadataBuilder,
 240            BlobBuilder ilBuilder,
 241            BlobBuilder? mappedFieldDataBuilderOpt,
 242            BlobBuilder? resourceBuilderOpt,
 243            BlobBuilder? debugDataBuilderOpt,
 244            out Blob strongNameSignature)
 0245        {
 0246            Debug.Assert(builder.Count == 0);
 0247            Debug.Assert(metadataBuilder.Count == MetadataSize);
 0248            Debug.Assert(metadataBuilder.Count % 4 == 0);
 0249            Debug.Assert(ilBuilder.Count == ILStreamSize);
 0250            Debug.Assert((mappedFieldDataBuilderOpt?.Count ?? 0) == MappedFieldDataSize);
 0251            Debug.Assert((resourceBuilderOpt?.Count ?? 0) == ResourceDataSize);
 252
 253            // TODO: avoid recalculation
 0254            int importTableRva = GetImportTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress;
 0255            int importAddressTableRva = GetImportAddressTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddres
 256
 0257            if (RequiresStartupStub)
 0258            {
 0259                WriteImportAddressTable(builder, importTableRva);
 0260            }
 261
 0262            WriteCorHeader(builder, relativeVirtualAddess, entryPointTokenOrRelativeVirtualAddress, corFlags);
 263
 264            // IL:
 0265            ilBuilder.Align(4);
 0266            builder.LinkSuffix(ilBuilder);
 267
 268            // metadata:
 0269            builder.LinkSuffix(metadataBuilder);
 270
 271            // managed resources:
 0272            if (resourceBuilderOpt != null)
 0273            {
 0274                builder.LinkSuffix(resourceBuilderOpt);
 0275            }
 276
 277            // strong name signature:
 278            // The bytes are required to be 0 for the purpose of calculating hash of the PE content
 279            // when strong name signing. This is already handled by ReserveBytes.
 0280            strongNameSignature = builder.ReserveBytes(StrongNameSignatureSize);
 281
 282            // debug directory and data:
 0283            if (debugDataBuilderOpt != null)
 0284            {
 0285                builder.LinkSuffix(debugDataBuilderOpt);
 0286            }
 287
 0288            if (RequiresStartupStub)
 0289            {
 0290                WriteImportTable(builder, importTableRva, importAddressTableRva);
 0291                WriteNameTable(builder);
 0292                WriteRuntimeStartupStub(builder, importAddressTableRva, baseAddress);
 0293            }
 294
 295            // mapped field data:
 0296            if (mappedFieldDataBuilderOpt != null)
 0297            {
 0298                if (mappedFieldDataBuilderOpt.Count != 0)
 0299                    builder.Align(MappedFieldDataAlignment);
 0300                builder.LinkSuffix(mappedFieldDataBuilderOpt);
 0301            }
 302
 0303            Debug.Assert(builder.Count == ComputeSizeOfTextSection());
 0304        }
 305
 306        private void WriteImportAddressTable(BlobBuilder builder, int importTableRva)
 0307        {
 0308            int start = builder.Count;
 309
 0310            int ilRva = importTableRva + 40;
 0311            int hintRva = ilRva + (Is32Bit ? 12 : 16);
 312
 313            // Import Address Table
 0314            if (Is32Bit)
 0315            {
 0316                builder.WriteUInt32((uint)hintRva); // 4
 0317                builder.WriteUInt32(0); // 8
 0318            }
 319            else
 0320            {
 0321                builder.WriteUInt64((uint)hintRva); // 8
 0322                builder.WriteUInt64(0); // 16
 0323            }
 324
 0325            Debug.Assert(builder.Count - start == SizeOfImportAddressTable);
 0326        }
 327
 328        private void WriteImportTable(BlobBuilder builder, int importTableRva, int importAddressTableRva)
 0329        {
 0330            int start = builder.Count;
 331
 0332            int ilRVA = importTableRva + 40;
 0333            int hintRva = ilRVA + (Is32Bit ? 12 : 16);
 0334            int nameRva = hintRva + 12 + 2;
 335
 336            // Import table
 0337            builder.WriteUInt32((uint)ilRVA); // 4
 0338            builder.WriteUInt32(0); // 8
 0339            builder.WriteUInt32(0); // 12
 0340            builder.WriteUInt32((uint)nameRva); // 16
 0341            builder.WriteUInt32((uint)importAddressTableRva); // 20
 0342            builder.WriteBytes(0, 20); // 40
 343
 344            // Import Lookup table
 0345            if (Is32Bit)
 0346            {
 0347                builder.WriteUInt32((uint)hintRva); // 44
 0348                builder.WriteUInt32(0); // 48
 0349                builder.WriteUInt32(0); // 52
 0350            }
 351            else
 0352            {
 0353                builder.WriteUInt64((uint)hintRva); // 48
 0354                builder.WriteUInt64(0); // 56
 0355            }
 356
 357            // Hint table
 0358            builder.WriteUInt16(0); // Hint 54|58
 359
 0360            builder.WriteBytes(CorEntryPointName); // 65|69
 0361            builder.WriteByte(0); // 66|70
 0362            Debug.Assert(builder.Count - start == SizeOfImportTable);
 0363        }
 364
 365        private static void WriteNameTable(BlobBuilder builder)
 0366        {
 0367            int start = builder.Count;
 368
 0369            builder.WriteBytes(CorEntryPointDll);
 0370            builder.WriteByte(0);
 0371            builder.WriteUInt16(0);
 0372            Debug.Assert(builder.Count - start == SizeOfNameTable);
 0373        }
 374
 375        private void WriteCorHeader(BlobBuilder builder, int textSectionRva, int entryPointTokenOrRva, CorFlags corFlags
 0376        {
 377            const ushort majorRuntimeVersion = 2;
 378            const ushort minorRuntimeVersion = 5;
 379
 0380            int metadataRva = textSectionRva + ComputeOffsetToMetadata();
 0381            int resourcesRva = metadataRva + MetadataSize;
 0382            int signatureRva = resourcesRva + ResourceDataSize;
 383
 0384            int start = builder.Count;
 385
 386            // Size:
 0387            builder.WriteUInt32(CorHeaderSize);
 388
 389            // Version:
 0390            builder.WriteUInt16(majorRuntimeVersion);
 0391            builder.WriteUInt16(minorRuntimeVersion);
 392
 393            // MetadataDirectory:
 0394            builder.WriteUInt32((uint)metadataRva);
 0395            builder.WriteUInt32((uint)MetadataSize);
 396
 397            // COR Flags:
 0398            builder.WriteUInt32((uint)corFlags);
 399
 400            // EntryPoint:
 0401            builder.WriteUInt32((uint)entryPointTokenOrRva);
 402
 403            // ResourcesDirectory:
 0404            builder.WriteUInt32((uint)(ResourceDataSize == 0 ? 0 : resourcesRva)); // 28
 0405            builder.WriteUInt32((uint)ResourceDataSize);
 406
 407            // StrongNameSignatureDirectory:
 0408            builder.WriteUInt32((uint)(StrongNameSignatureSize == 0 ? 0 : signatureRva)); // 36
 0409            builder.WriteUInt32((uint)StrongNameSignatureSize);
 410
 411            // CodeManagerTableDirectory (not supported):
 0412            builder.WriteUInt32(0);
 0413            builder.WriteUInt32(0);
 414
 415            // VtableFixupsDirectory (not supported):
 0416            builder.WriteUInt32(0);
 0417            builder.WriteUInt32(0);
 418
 419            // ExportAddressTableJumpsDirectory (not supported):
 0420            builder.WriteUInt32(0);
 0421            builder.WriteUInt32(0);
 422
 423            // ManagedNativeHeaderDirectory (not supported):
 0424            builder.WriteUInt32(0);
 0425            builder.WriteUInt32(0);
 426
 0427            Debug.Assert(builder.Count - start == CorHeaderSize);
 0428            Debug.Assert(builder.Count % 4 == 0);
 0429        }
 430
 431        private void WriteRuntimeStartupStub(BlobBuilder sectionBuilder, int importAddressTableRva, ulong baseAddress)
 0432        {
 433            // entry point code, consisting of a jump indirect to _CorXXXMain
 0434            if (Is32Bit)
 0435            {
 436                // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 4 byte boun
 437                // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively 
 0438                sectionBuilder.Align(4);
 439
 0440                sectionBuilder.WriteUInt16(0);
 0441                sectionBuilder.WriteByte(0xff);
 0442                sectionBuilder.WriteByte(0x25); //4
 0443                sectionBuilder.WriteUInt32((uint)importAddressTableRva + (uint)baseAddress); //8
 0444            }
 445            else
 0446            {
 447                // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 8 byte boun
 448                // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively 
 0449                sectionBuilder.Align(8);
 450
 0451                sectionBuilder.WriteUInt32(0);
 0452                sectionBuilder.WriteUInt16(0);
 0453                sectionBuilder.WriteByte(0xff);
 0454                sectionBuilder.WriteByte(0x25); //8
 0455                sectionBuilder.WriteUInt64((ulong)importAddressTableRva + baseAddress); //16
 0456            }
 0457        }
 458
 459        #endregion
 460    }
 461}
 462

Methods/Properties

ImageCharacteristics()
Machine()
ILStreamSize()
MetadataSize()
ResourceDataSize()
StrongNameSignatureSize()
DebugDataSize()
MappedFieldDataSize()
.ctor(System.Reflection.PortableExecutable.Characteristics,System.Reflection.PortableExecutable.Machine,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32)
RequiresStartupStub()
Requires64bits()
Is32Bit()
CorEntryPointDll()
CorEntryPointName()
SizeOfImportAddressTable()
SizeOfImportTable()
SizeOfNameTable()
SizeOfRuntimeStartupStub()
CalculateOffsetToMappedFieldDataStreamUnaligned()
CalculateOffsetToMappedFieldDataStream()
ComputeOffsetToDebugDirectory()
ComputeOffsetToImportTable()
OffsetToILStream()
ComputeOffsetToMetadata()
ComputeSizeOfTextSection()
GetEntryPointAddress(System.Int32)
GetImportAddressTableDirectoryEntry(System.Int32)
GetImportTableDirectoryEntry(System.Int32)
GetCorHeaderDirectoryEntry(System.Int32)
Serialize(System.Reflection.Metadata.BlobBuilder,System.Int32,System.Int32,System.Reflection.PortableExecutable.CorFlags,System.UInt64,System.Reflection.Metadata.BlobBuilder,System.Reflection.Metadata.BlobBuilder,System.Reflection.Metadata.BlobBuilder,System.Reflection.Metadata.BlobBuilder,System.Reflection.Metadata.BlobBuilder,System.Reflection.Metadata.Blob&)
WriteImportAddressTable(System.Reflection.Metadata.BlobBuilder,System.Int32)
WriteImportTable(System.Reflection.Metadata.BlobBuilder,System.Int32,System.Int32)
WriteNameTable(System.Reflection.Metadata.BlobBuilder)
WriteCorHeader(System.Reflection.Metadata.BlobBuilder,System.Int32,System.Int32,System.Reflection.PortableExecutable.CorFlags)
WriteRuntimeStartupStub(System.Reflection.Metadata.BlobBuilder,System.Int32,System.UInt64)