File: PEWriter\ExtendedPEBuilder.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis;
 
namespace Microsoft.Cci
{
    /// <summary>
    /// This PEBuilder adds an .mvid section.
    /// </summary>
    internal sealed class ExtendedPEBuilder
        : ManagedPEBuilder
    {
        private const string MvidSectionName = ".mvid";
        public const int SizeOfGuid = 16;
 
        // When the section is built with a placeholder, the placeholder blob is saved for later fixing up.
        private Blob _mvidSectionFixup = default(Blob);
 
        // Only include the .mvid section in ref assemblies
        private readonly bool _withMvidSection;
 
        public ExtendedPEBuilder(
            PEHeaderBuilder header,
            MetadataRootBuilder metadataRootBuilder,
            BlobBuilder ilStream,
            BlobBuilder? mappedFieldData,
            BlobBuilder? managedResources,
            ResourceSectionBuilder? nativeResources,
            DebugDirectoryBuilder? debugDirectoryBuilder,
            int strongNameSignatureSize,
            MethodDefinitionHandle entryPoint,
            CorFlags flags,
            Func<IEnumerable<Blob>, BlobContentId>? deterministicIdProvider,
            bool withMvidSection)
            : base(header, metadataRootBuilder, ilStream, mappedFieldData, managedResources, nativeResources,
                  debugDirectoryBuilder, strongNameSignatureSize, entryPoint, flags, deterministicIdProvider)
        {
            _withMvidSection = withMvidSection;
        }
 
        protected override ImmutableArray<Section> CreateSections()
        {
            var baseSections = base.CreateSections();
 
            if (_withMvidSection)
            {
                var builder = ArrayBuilder<Section>.GetInstance(baseSections.Length + 1);
 
                builder.Add(new Section(MvidSectionName, SectionCharacteristics.MemRead |
                    SectionCharacteristics.ContainsInitializedData |
                    SectionCharacteristics.MemDiscardable));
 
                builder.AddRange(baseSections);
                return builder.ToImmutableAndFree();
            }
            else
            {
                return baseSections;
            }
        }
 
        protected override BlobBuilder SerializeSection(string name, SectionLocation location)
        {
            if (name.Equals(MvidSectionName, StringComparison.Ordinal))
            {
                Debug.Assert(_withMvidSection);
                return SerializeMvidSection();
            }
 
            return base.SerializeSection(name, location);
        }
 
        internal BlobContentId Serialize(BlobBuilder peBlob, out Blob mvidSectionFixup)
        {
            var result = base.Serialize(peBlob);
            mvidSectionFixup = _mvidSectionFixup;
            return result;
        }
 
        private BlobBuilder SerializeMvidSection()
        {
            var sectionBuilder = new BlobBuilder();
 
            // The guid will be filled in later:
            _mvidSectionFixup = sectionBuilder.ReserveBytes(SizeOfGuid);
            var mvidWriter = new BlobWriter(_mvidSectionFixup);
            mvidWriter.WriteBytes(0, _mvidSectionFixup.Length);
            Debug.Assert(mvidWriter.RemainingBytes == 0);
 
            return sectionBuilder;
        }
    }
}