File: System\Reflection\PortableExecutable\PEHeader.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.Diagnostics;
using System.Reflection.Metadata;
 
namespace System.Reflection.PortableExecutable
{
    public sealed class PEHeader
    {
        #region Standard fields
 
        /// <summary>
        /// Identifies the format of the image file.
        /// </summary>
        public PEMagic Magic { get; }
 
        /// <summary>
        /// The linker major version number.
        /// </summary>
        public byte MajorLinkerVersion { get; }
 
        /// <summary>
        /// The linker minor version number.
        /// </summary>
        public byte MinorLinkerVersion { get; }
 
        /// <summary>
        /// The size of the code (text) section, or the sum of all code sections if there are multiple sections.
        /// </summary>
        public int SizeOfCode { get; }
 
        /// <summary>
        /// The size of the initialized data section, or the sum of all such sections if there are multiple data sections.
        /// </summary>
        public int SizeOfInitializedData { get; }
 
        /// <summary>
        /// The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections.
        /// </summary>
        public int SizeOfUninitializedData { get; }
 
        /// <summary>
        /// The address of the entry point relative to the image base when the PE file is loaded into memory.
        /// For program images, this is the starting address. For device drivers, this is the address of the initialization function.
        /// An entry point is optional for DLLs. When no entry point is present, this field must be zero.
        /// </summary>
        public int AddressOfEntryPoint { get; }
 
        /// <summary>
        /// The address that is relative to the image base of the beginning-of-code section when it is loaded into memory.
        /// </summary>
        public int BaseOfCode { get; }
 
        /// <summary>
        /// The address that is relative to the image base of the beginning-of-data section when it is loaded into memory.
        /// </summary>
        public int BaseOfData { get; }
 
        #endregion
 
        #region Windows Specific Fields
 
        /// <summary>
        /// The preferred address of the first byte of image when loaded into memory;
        /// must be a multiple of 64K.
        /// </summary>
        public ulong ImageBase { get; }
 
        /// <summary>
        /// The alignment (in bytes) of sections when they are loaded into memory. It must be greater than or equal to <see cref="FileAlignment"/>.
        /// The default is the page size for the architecture.
        /// </summary>
        public int SectionAlignment { get; }
 
        /// <summary>
        /// The alignment factor (in bytes) that is used to align the raw data of sections in the image file.
        /// The value should be a power of 2 between 512 and 64K, inclusive. The default is 512.
        /// If the <see cref="SectionAlignment"/> is less than the architecture's page size,
        /// then <see cref="FileAlignment"/> must match <see cref="SectionAlignment"/>.
        /// </summary>
        public int FileAlignment { get; }
 
        /// <summary>
        /// The major version number of the required operating system.
        /// </summary>
        public ushort MajorOperatingSystemVersion { get; }
 
        /// <summary>
        /// The minor version number of the required operating system.
        /// </summary>
        public ushort MinorOperatingSystemVersion { get; }
 
        /// <summary>
        /// The major version number of the image.
        /// </summary>
        public ushort MajorImageVersion { get; }
 
        /// <summary>
        /// The minor version number of the image.
        /// </summary>
        public ushort MinorImageVersion { get; }
 
        /// <summary>
        /// The major version number of the subsystem.
        /// </summary>
        public ushort MajorSubsystemVersion { get; }
 
        /// <summary>
        /// The minor version number of the subsystem.
        /// </summary>
        public ushort MinorSubsystemVersion { get; }
 
        /// <summary>
        /// The size (in bytes) of the image, including all headers, as the image is loaded in memory.
        /// It must be a multiple of <see cref="SectionAlignment"/>.
        /// </summary>
        public int SizeOfImage { get; }
 
        /// <summary>
        /// The combined size of an MS DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment.
        /// </summary>
        public int SizeOfHeaders { get; }
 
        /// <summary>
        /// The image file checksum.
        /// </summary>
        public uint CheckSum { get; }
 
        /// <summary>
        /// The subsystem that is required to run this image.
        /// </summary>
        public Subsystem Subsystem { get; }
 
        public DllCharacteristics DllCharacteristics { get; }
 
        /// <summary>
        /// The size of the stack to reserve. Only <see cref="SizeOfStackCommit"/> is committed;
        /// the rest is made available one page at a time until the reserve size is reached.
        /// </summary>
        public ulong SizeOfStackReserve { get; }
 
        /// <summary>
        /// The size of the stack to commit.
        /// </summary>
        public ulong SizeOfStackCommit { get; }
 
        /// <summary>
        /// The size of the local heap space to reserve. Only <see cref="SizeOfHeapCommit"/> is committed;
        /// the rest is made available one page at a time until the reserve size is reached.
        /// </summary>
        public ulong SizeOfHeapReserve { get; }
 
        /// <summary>
        /// The size of the local heap space to commit.
        /// </summary>
        public ulong SizeOfHeapCommit { get; }
 
        /// <summary>
        /// The number of data-directory entries in the remainder of the <see cref="PEHeader"/>. Each describes a location and size.
        /// </summary>
        public int NumberOfRvaAndSizes { get; }
 
        #endregion
 
        #region Directory Entries
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_EXPORT.
        /// </remarks>
        public DirectoryEntry ExportTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_IMPORT.
        /// </remarks>
        public DirectoryEntry ImportTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_RESOURCE.
        /// </remarks>
        public DirectoryEntry ResourceTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_EXCEPTION.
        /// </remarks>
        public DirectoryEntry ExceptionTableDirectory { get; }
 
        /// <summary>
        /// The Certificate Table entry points to a table of attribute certificates.
        /// </summary>
        /// <remarks>
        /// These certificates are not loaded into memory as part of the image.
        /// As such, the first field of this entry, which is normally an RVA, is a file pointer instead.
        ///
        /// Aka IMAGE_DIRECTORY_ENTRY_SECURITY.
        /// </remarks>
        public DirectoryEntry CertificateTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_BASERELOC.
        /// </remarks>
        public DirectoryEntry BaseRelocationTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_DEBUG.
        /// </remarks>
        public DirectoryEntry DebugTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_COPYRIGHT or IMAGE_DIRECTORY_ENTRY_ARCHITECTURE.
        /// </remarks>
        public DirectoryEntry CopyrightTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_GLOBALPTR.
        /// </remarks>
        public DirectoryEntry GlobalPointerTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_TLS.
        /// </remarks>
        public DirectoryEntry ThreadLocalStorageTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG.
        /// </remarks>
        public DirectoryEntry LoadConfigTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT.
        /// </remarks>
        public DirectoryEntry BoundImportTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_IAT.
        /// </remarks>
        public DirectoryEntry ImportAddressTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT.
        /// </remarks>
        public DirectoryEntry DelayImportTableDirectory { get; }
 
        /// <remarks>
        /// Aka IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR.
        /// </remarks>
        public DirectoryEntry CorHeaderTableDirectory { get; }
 
        #endregion
 
        internal const int OffsetOfChecksum =
            sizeof(short) +                              // Magic
            sizeof(byte) +                               // MajorLinkerVersion
            sizeof(byte) +                               // MinorLinkerVersion
            sizeof(int) +                                // SizeOfCode
            sizeof(int) +                                // SizeOfInitializedData
            sizeof(int) +                                // SizeOfUninitializedData
            sizeof(int) +                                // AddressOfEntryPoint
            sizeof(int) +                                // BaseOfCode
            sizeof(long) +                               // PE32:  BaseOfData (int), ImageBase (int)
                                                         // PE32+: ImageBase (long)
            sizeof(int) +                                // SectionAlignment
            sizeof(int) +                                // FileAlignment
            sizeof(short) +                              // MajorOperatingSystemVersion
            sizeof(short) +                              // MinorOperatingSystemVersion
            sizeof(short) +                              // MajorImageVersion
            sizeof(short) +                              // MinorImageVersion
            sizeof(short) +                              // MajorSubsystemVersion
            sizeof(short) +                              // MinorSubsystemVersion
            sizeof(int) +                                // Win32VersionValue
            sizeof(int) +                                // SizeOfImage
            sizeof(int);                                 // SizeOfHeaders
 
        internal static int Size(bool is32Bit) =>
            OffsetOfChecksum +
            sizeof(int) +                                // Checksum
            sizeof(short) +                              // Subsystem
            sizeof(short) +                              // DllCharacteristics
            4 * (is32Bit ? sizeof(int) : sizeof(long)) + // SizeOfStackReserve, SizeOfStackCommit, SizeOfHeapReserve, SizeOfHeapCommit
            sizeof(int) +                                // LoaderFlags
            sizeof(int) +                                // NumberOfRvaAndSizes
            16 * sizeof(long);                           // directory entries
 
        internal PEHeader(ref PEBinaryReader reader)
        {
            PEMagic magic = (PEMagic)reader.ReadUInt16();
            if (magic != PEMagic.PE32 && magic != PEMagic.PE32Plus)
            {
                throw new BadImageFormatException(SR.UnknownPEMagicValue);
            }
 
            Magic = magic;
            MajorLinkerVersion = reader.ReadByte();
            MinorLinkerVersion = reader.ReadByte();
            SizeOfCode = reader.ReadInt32();
            SizeOfInitializedData = reader.ReadInt32();
            SizeOfUninitializedData = reader.ReadInt32();
            AddressOfEntryPoint = reader.ReadInt32();
            BaseOfCode = reader.ReadInt32();
 
            if (magic == PEMagic.PE32Plus)
            {
                BaseOfData = 0; // not present
            }
            else
            {
                Debug.Assert(magic == PEMagic.PE32);
                BaseOfData = reader.ReadInt32();
            }
 
            if (magic == PEMagic.PE32Plus)
            {
                ImageBase = reader.ReadUInt64();
            }
            else
            {
                ImageBase = reader.ReadUInt32();
            }
 
            // NT additional fields:
            SectionAlignment = reader.ReadInt32();
            FileAlignment = reader.ReadInt32();
            MajorOperatingSystemVersion = reader.ReadUInt16();
            MinorOperatingSystemVersion = reader.ReadUInt16();
            MajorImageVersion = reader.ReadUInt16();
            MinorImageVersion = reader.ReadUInt16();
            MajorSubsystemVersion = reader.ReadUInt16();
            MinorSubsystemVersion = reader.ReadUInt16();
 
            // Win32VersionValue (reserved, should be 0)
            reader.ReadUInt32();
 
            SizeOfImage = reader.ReadInt32();
            SizeOfHeaders = reader.ReadInt32();
            CheckSum = reader.ReadUInt32();
            Subsystem = (Subsystem)reader.ReadUInt16();
            DllCharacteristics = (DllCharacteristics)reader.ReadUInt16();
 
            if (magic == PEMagic.PE32Plus)
            {
                SizeOfStackReserve = reader.ReadUInt64();
                SizeOfStackCommit = reader.ReadUInt64();
                SizeOfHeapReserve = reader.ReadUInt64();
                SizeOfHeapCommit = reader.ReadUInt64();
            }
            else
            {
                SizeOfStackReserve = reader.ReadUInt32();
                SizeOfStackCommit = reader.ReadUInt32();
                SizeOfHeapReserve = reader.ReadUInt32();
                SizeOfHeapCommit = reader.ReadUInt32();
            }
 
            // loader flags
            reader.ReadUInt32();
 
            NumberOfRvaAndSizes = reader.ReadInt32();
 
            // directory entries:
            ExportTableDirectory = new DirectoryEntry(ref reader);
            ImportTableDirectory = new DirectoryEntry(ref reader);
            ResourceTableDirectory = new DirectoryEntry(ref reader);
            ExceptionTableDirectory = new DirectoryEntry(ref reader);
            CertificateTableDirectory = new DirectoryEntry(ref reader);
            BaseRelocationTableDirectory = new DirectoryEntry(ref reader);
            DebugTableDirectory = new DirectoryEntry(ref reader);
            CopyrightTableDirectory = new DirectoryEntry(ref reader);
            GlobalPointerTableDirectory = new DirectoryEntry(ref reader);
            ThreadLocalStorageTableDirectory = new DirectoryEntry(ref reader);
            LoadConfigTableDirectory = new DirectoryEntry(ref reader);
            BoundImportTableDirectory = new DirectoryEntry(ref reader);
            ImportAddressTableDirectory = new DirectoryEntry(ref reader);
            DelayImportTableDirectory = new DirectoryEntry(ref reader);
            CorHeaderTableDirectory = new DirectoryEntry(ref reader);
 
            // ReservedDirectory (should be 0, 0)
            new DirectoryEntry(ref reader);
        }
    }
}