| File: System\Reflection\PortableExecutable\ManagedPEBuilder.cs | Web Access |
| Project: src\runtime\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; namespace System.Reflection.PortableExecutable { public class ManagedPEBuilder : PEBuilder { public const int ManagedResourcesDataAlignment = ManagedTextSection.ManagedResourcesDataAlignment; public const int MappedFieldDataAlignment = ManagedTextSection.MappedFieldDataAlignment; private const int DefaultStrongNameSignatureSize = 128; private const string TextSectionName = ".text"; private const string ResourceSectionName = ".rsrc"; private const string RelocationSectionName = ".reloc"; private readonly PEDirectoriesBuilder _peDirectoriesBuilder; private readonly MetadataRootBuilder _metadataRootBuilder; private readonly BlobBuilder _ilStream; private readonly BlobBuilder? _mappedFieldDataOpt; private readonly BlobBuilder? _managedResourcesOpt; private readonly ResourceSectionBuilder? _nativeResourcesOpt; private readonly int _strongNameSignatureSize; private readonly MethodDefinitionHandle _entryPointOpt; private readonly DebugDirectoryBuilder? _debugDirectoryBuilderOpt; private readonly CorFlags _corFlags; private int _lazyEntryPointAddress; private Blob _lazyStrongNameSignature; public ManagedPEBuilder( PEHeaderBuilder header, MetadataRootBuilder metadataRootBuilder, BlobBuilder ilStream, BlobBuilder? mappedFieldData = null, BlobBuilder? managedResources = null, ResourceSectionBuilder? nativeResources = null, DebugDirectoryBuilder? debugDirectoryBuilder = null, int strongNameSignatureSize = DefaultStrongNameSignatureSize, MethodDefinitionHandle entryPoint = default(MethodDefinitionHandle), CorFlags flags = CorFlags.ILOnly, Func<IEnumerable<Blob>, BlobContentId>? deterministicIdProvider = null) : base(header, deterministicIdProvider) { if (header is null) { Throw.ArgumentNull(nameof(header)); } if (metadataRootBuilder is null) { Throw.ArgumentNull(nameof(metadataRootBuilder)); } if (ilStream is null) { Throw.ArgumentNull(nameof(ilStream)); } if (strongNameSignatureSize < 0) { Throw.ArgumentOutOfRange(nameof(strongNameSignatureSize)); } _metadataRootBuilder = metadataRootBuilder; _ilStream = ilStream; _mappedFieldDataOpt = mappedFieldData; _managedResourcesOpt = managedResources; _nativeResourcesOpt = nativeResources; _strongNameSignatureSize = strongNameSignatureSize; _entryPointOpt = entryPoint; _debugDirectoryBuilderOpt = debugDirectoryBuilder ?? CreateDefaultDebugDirectoryBuilder(); _corFlags = flags; _peDirectoriesBuilder = new PEDirectoriesBuilder(); } private DebugDirectoryBuilder? CreateDefaultDebugDirectoryBuilder() { if (IsDeterministic) { var builder = new DebugDirectoryBuilder(); builder.AddReproducibleEntry(); return builder; } return null; } protected override ImmutableArray<Section> CreateSections() { var builder = ImmutableArray.CreateBuilder<Section>(3); builder.Add(new Section(TextSectionName, SectionCharacteristics.MemRead | SectionCharacteristics.MemExecute | SectionCharacteristics.ContainsCode)); if (_nativeResourcesOpt != null) { builder.Add(new Section(ResourceSectionName, SectionCharacteristics.MemRead | SectionCharacteristics.ContainsInitializedData)); } if (Header.Machine == Machine.I386 || Header.Machine == 0) { builder.Add(new Section(RelocationSectionName, SectionCharacteristics.MemRead | SectionCharacteristics.MemDiscardable | SectionCharacteristics.ContainsInitializedData)); } return builder.ToImmutable(); } protected override BlobBuilder SerializeSection(string name, SectionLocation location) => name switch { TextSectionName => SerializeTextSection(location), ResourceSectionName => SerializeResourceSection(location), RelocationSectionName => SerializeRelocationSection(location), _ => throw new ArgumentException(SR.Format(SR.UnknownSectionName, name), nameof(name)), }; private BlobBuilder SerializeTextSection(SectionLocation location) { var sectionBuilder = new BlobBuilder(); var metadataBuilder = new BlobBuilder(); var metadataSizes = _metadataRootBuilder.Sizes; var textSection = new ManagedTextSection( imageCharacteristics: Header.ImageCharacteristics, machine: Header.Machine, ilStreamSize: _ilStream.Count, metadataSize: metadataSizes.MetadataSize, resourceDataSize: _managedResourcesOpt?.Count ?? 0, strongNameSignatureSize: _strongNameSignatureSize, debugDataSize: _debugDirectoryBuilderOpt?.Size ?? 0, mappedFieldDataSize: _mappedFieldDataOpt?.Count ?? 0); int methodBodyStreamRva = location.RelativeVirtualAddress + textSection.OffsetToILStream; int mappedFieldDataStreamRva = location.RelativeVirtualAddress + textSection.CalculateOffsetToMappedFieldDataStream(); _metadataRootBuilder.Serialize(metadataBuilder, methodBodyStreamRva, mappedFieldDataStreamRva); DirectoryEntry debugDirectoryEntry; BlobBuilder? debugTableBuilderOpt; if (_debugDirectoryBuilderOpt != null) { int debugDirectoryOffset = textSection.ComputeOffsetToDebugDirectory(); debugTableBuilderOpt = new BlobBuilder(_debugDirectoryBuilderOpt.TableSize); _debugDirectoryBuilderOpt.Serialize(debugTableBuilderOpt, location, debugDirectoryOffset); // Only the size of the fixed part of the debug table goes here. debugDirectoryEntry = new DirectoryEntry( location.RelativeVirtualAddress + debugDirectoryOffset, _debugDirectoryBuilderOpt.TableSize); } else { debugTableBuilderOpt = null; debugDirectoryEntry = default(DirectoryEntry); } _lazyEntryPointAddress = textSection.GetEntryPointAddress(location.RelativeVirtualAddress); textSection.Serialize( sectionBuilder, location.RelativeVirtualAddress, _entryPointOpt.IsNil ? 0 : MetadataTokens.GetToken(_entryPointOpt), _corFlags, Header.ImageBase, metadataBuilder, _ilStream, _mappedFieldDataOpt, _managedResourcesOpt, debugTableBuilderOpt, out _lazyStrongNameSignature); _peDirectoriesBuilder.AddressOfEntryPoint = _lazyEntryPointAddress; _peDirectoriesBuilder.DebugTable = debugDirectoryEntry; _peDirectoriesBuilder.ImportAddressTable = textSection.GetImportAddressTableDirectoryEntry(location.RelativeVirtualAddress); _peDirectoriesBuilder.ImportTable = textSection.GetImportTableDirectoryEntry(location.RelativeVirtualAddress); _peDirectoriesBuilder.CorHeaderTable = textSection.GetCorHeaderDirectoryEntry(location.RelativeVirtualAddress); return sectionBuilder; } private BlobBuilder SerializeResourceSection(SectionLocation location) { Debug.Assert(_nativeResourcesOpt != null); var sectionBuilder = new BlobBuilder(); _nativeResourcesOpt.Serialize(sectionBuilder, location); _peDirectoriesBuilder.ResourceTable = new DirectoryEntry(location.RelativeVirtualAddress, sectionBuilder.Count); return sectionBuilder; } private BlobBuilder SerializeRelocationSection(SectionLocation location) { var sectionBuilder = new BlobBuilder(); WriteRelocationSection(sectionBuilder, Header.Machine, _lazyEntryPointAddress); _peDirectoriesBuilder.BaseRelocationTable = new DirectoryEntry(location.RelativeVirtualAddress, sectionBuilder.Count); return sectionBuilder; } private static void WriteRelocationSection(BlobBuilder builder, Machine machine, int entryPointAddress) { Debug.Assert(builder.Count == 0); builder.WriteUInt32((((uint)entryPointAddress + 2) / 0x1000) * 0x1000); builder.WriteUInt32((machine == Machine.IA64) ? 14u : 12u); uint offsetWithinPage = ((uint)entryPointAddress + 2) % 0x1000; uint relocType = (machine == Machine.Amd64 || machine == Machine.IA64 || machine == Machine.Arm64) ? 10u : 3u; ushort s = (ushort)((relocType << 12) | offsetWithinPage); builder.WriteUInt16(s); if (machine == Machine.IA64) { builder.WriteUInt32(relocType << 12); } builder.WriteUInt16(0); // next chunk's RVA } protected internal override PEDirectoriesBuilder GetDirectories() { return _peDirectoriesBuilder; } public void Sign(BlobBuilder peImage, Func<IEnumerable<Blob>, byte[]> signatureProvider) { if (peImage is null) { Throw.ArgumentNull(nameof(peImage)); } if (signatureProvider is null) { Throw.ArgumentNull(nameof(signatureProvider)); } Sign(peImage!, _lazyStrongNameSignature, signatureProvider!); } } }