File: System\Reflection\PortableExecutable\PEHeaderBuilder.cs
Web Access
Project: src\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.Reflection.Internal;
 
namespace System.Reflection.PortableExecutable
{
    public sealed class PEHeaderBuilder
    {
        // COFF:
        public Machine Machine { get; }
        public Characteristics ImageCharacteristics { get; }
 
        // PE:
        public byte MajorLinkerVersion { get; }
        public byte MinorLinkerVersion { get; }
 
        public ulong ImageBase { get; }
        public int SectionAlignment { get; }
        public int FileAlignment { get; }
 
        public ushort MajorOperatingSystemVersion { get; }
        public ushort MinorOperatingSystemVersion { get; }
 
        public ushort MajorImageVersion { get; }
        public ushort MinorImageVersion { get; }
 
        public ushort MajorSubsystemVersion { get; }
        public ushort MinorSubsystemVersion { get; }
 
        public Subsystem Subsystem { get; }
        public DllCharacteristics DllCharacteristics { get; }
 
        public ulong SizeOfStackReserve { get; }
        public ulong SizeOfStackCommit { get; }
        public ulong SizeOfHeapReserve { get; }
        public ulong SizeOfHeapCommit { get; }
 
        /// <summary>
        /// Creates PE header builder.
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="fileAlignment"/> is not power of 2 between 512 and 64K, or
        /// <paramref name="sectionAlignment"/> not power of 2 or it's less than <paramref name="fileAlignment"/>.
        /// </exception>
        public PEHeaderBuilder(
            Machine machine = 0,
            int sectionAlignment = 0x2000,
            int fileAlignment = 0x200,
            ulong imageBase = 0x00400000,
            byte majorLinkerVersion = 0x30, // (what is ref.emit using?)
            byte minorLinkerVersion = 0,
            ushort majorOperatingSystemVersion = 4,
            ushort minorOperatingSystemVersion = 0,
            ushort majorImageVersion = 0,
            ushort minorImageVersion = 0,
            ushort majorSubsystemVersion = 4,
            ushort minorSubsystemVersion = 0,
            Subsystem subsystem = Subsystem.WindowsCui,
            DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible | DllCharacteristics.NoSeh | DllCharacteristics.TerminalServerAware,
            Characteristics imageCharacteristics = Characteristics.Dll,
            ulong sizeOfStackReserve = 0x00100000,
            ulong sizeOfStackCommit = 0x1000,
            ulong sizeOfHeapReserve = 0x00100000,
            ulong sizeOfHeapCommit = 0x1000)
        {
            if (fileAlignment < 512 || fileAlignment > 64 * 1024 || BitArithmetic.CountBits(fileAlignment) != 1)
            {
                Throw.ArgumentOutOfRange(nameof(fileAlignment));
            }
 
            if (sectionAlignment < fileAlignment || BitArithmetic.CountBits(sectionAlignment) != 1)
            {
                Throw.ArgumentOutOfRange(nameof(sectionAlignment));
            }
 
            Machine = machine;
            SectionAlignment = sectionAlignment;
            FileAlignment = fileAlignment;
            ImageBase = imageBase;
            MajorLinkerVersion = majorLinkerVersion;
            MinorLinkerVersion = minorLinkerVersion;
            MajorOperatingSystemVersion = majorOperatingSystemVersion;
            MinorOperatingSystemVersion = minorOperatingSystemVersion;
            MajorImageVersion = majorImageVersion;
            MinorImageVersion = minorImageVersion;
            MajorSubsystemVersion = majorSubsystemVersion;
            MinorSubsystemVersion = minorSubsystemVersion;
            Subsystem = subsystem;
            DllCharacteristics = dllCharacteristics;
            ImageCharacteristics = imageCharacteristics;
            SizeOfStackReserve = sizeOfStackReserve;
            SizeOfStackCommit = sizeOfStackCommit;
            SizeOfHeapReserve = sizeOfHeapReserve;
            SizeOfHeapCommit = sizeOfHeapCommit;
        }
 
        public static PEHeaderBuilder CreateExecutableHeader()
        {
            return new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage);
        }
 
        public static PEHeaderBuilder CreateLibraryHeader()
        {
            return new PEHeaderBuilder(imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll);
        }
 
        internal bool Is32Bit => Machine != Machine.Amd64 && Machine != Machine.IA64 && Machine != Machine.Arm64 && Machine != Machine.LoongArch64 && Machine != Machine.RiscV64;
 
        internal int ComputeSizeOfPEHeaders(int sectionCount) =>
            PEBuilder.DosHeaderSize +
            PEHeaders.PESignatureSize +
            CoffHeader.Size +
            PEHeader.Size(Is32Bit) +
            SectionHeader.Size * sectionCount;
    }
}