/// <summary> /// Copy PE headers into a PEHeaderBuilder used by PEBuilder. /// </summary> /// <param name="peHeaders">Headers to copy</param> /// <param name="target">Target architecture to set in the header</param> public static PEHeaderBuilder Copy(PEHeaders peHeaders, TargetDetails target) { bool is64BitTarget = target.PointerSize == sizeof(long); Characteristics imageCharacteristics = peHeaders.CoffHeader.Characteristics; if (is64BitTarget) { imageCharacteristics &= ~Characteristics.Bit32Machine; imageCharacteristics |= Characteristics.LargeAddressAware; } return(new PEHeaderBuilder( machine: target.MachineFromTarget(), // On Linux, we must match the bottom 12 bits of section RVA's to their file offsets. For this reason // we need the same alignment for both. sectionAlignment: (target.IsWindows ? peHeaders.PEHeader.SectionAlignment : peHeaders.PEHeader.FileAlignment), fileAlignment: peHeaders.PEHeader.FileAlignment, imageBase: peHeaders.PEHeader.ImageBase, majorLinkerVersion: peHeaders.PEHeader.MajorLinkerVersion, minorLinkerVersion: peHeaders.PEHeader.MinorLinkerVersion, majorOperatingSystemVersion: peHeaders.PEHeader.MajorOperatingSystemVersion, minorOperatingSystemVersion: peHeaders.PEHeader.MinorOperatingSystemVersion, majorImageVersion: peHeaders.PEHeader.MajorImageVersion, minorImageVersion: peHeaders.PEHeader.MinorImageVersion, majorSubsystemVersion: peHeaders.PEHeader.MajorSubsystemVersion, minorSubsystemVersion: peHeaders.PEHeader.MinorSubsystemVersion, subsystem: peHeaders.PEHeader.Subsystem, dllCharacteristics: peHeaders.PEHeader.DllCharacteristics, imageCharacteristics: imageCharacteristics, sizeOfStackReserve: peHeaders.PEHeader.SizeOfStackReserve, sizeOfStackCommit: peHeaders.PEHeader.SizeOfStackCommit, sizeOfHeapReserve: peHeaders.PEHeader.SizeOfHeapReserve, sizeOfHeapCommit: peHeaders.PEHeader.SizeOfHeapCommit)); }
/// <summary> /// Fill in PE header information into a PEHeaderBuilder used by PEBuilder. /// </summary> /// <param name="relocsStripped">Relocs are not present in the PE executable</param> /// <param name="dllCharacteristics">Extra DLL characteristics to apply</param> /// <param name="subsystem">Targeting subsystem</param> /// <param name="target">Target architecture to set in the header</param> public static PEHeaderBuilder Create(Characteristics imageCharacteristics, DllCharacteristics dllCharacteristics, Subsystem subsystem, TargetDetails target) { bool is64BitTarget = target.PointerSize == sizeof(long); imageCharacteristics &= ~(Characteristics.Bit32Machine | Characteristics.LargeAddressAware); imageCharacteristics |= (is64BitTarget ? Characteristics.LargeAddressAware : Characteristics.Bit32Machine); ulong imageBase = PE32HeaderConstants.ImageBase; if (target.IsWindows && is64BitTarget && (imageBase <= uint.MaxValue)) { // Base addresses below 4 GiB are reserved for WoW on x64 and disallowed on ARM64. // If the input assembly was compiled for anycpu, its base address is 32-bit and we need to fix it. imageBase = (imageCharacteristics & Characteristics.Dll) != 0 ? PE64HeaderConstants.DllImageBase : PE64HeaderConstants.ExeImageBase; } int fileAlignment = 0x200; if (!target.IsWindows && !is64BitTarget) { // To minimize wasted VA space on 32 bit systems align file to page bounaries (presumed to be 4K). fileAlignment = 0x1000; } int sectionAlignment = 0x1000; if (!target.IsWindows && is64BitTarget) { // On Linux, we must match the bottom 12 bits of section RVA's to their file offsets. For this reason // we need the same alignment for both. sectionAlignment = fileAlignment; } dllCharacteristics &= DllCharacteristics.AppContainer; // In Crossgen1, this is under a debug-specific condition 'if (0 == CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NoASLRForNgen))' dllCharacteristics |= DllCharacteristics.DynamicBase; // Without NxCompatible the PE executable cannot execute on Windows ARM64 dllCharacteristics |= DllCharacteristics.NxCompatible | DllCharacteristics.TerminalServerAware; if (is64BitTarget) { dllCharacteristics |= DllCharacteristics.HighEntropyVirtualAddressSpace; } else { dllCharacteristics |= DllCharacteristics.NoSeh; } return(new PEHeaderBuilder( machine: target.MachineFromTarget(), sectionAlignment: sectionAlignment, fileAlignment: fileAlignment, imageBase: imageBase, majorLinkerVersion: PEHeaderConstants.MajorLinkerVersion, minorLinkerVersion: PEHeaderConstants.MinorLinkerVersion, majorOperatingSystemVersion: PEHeaderConstants.MajorOperatingSystemVersion, minorOperatingSystemVersion: PEHeaderConstants.MinorOperatingSystemVersion, majorImageVersion: PEHeaderConstants.MajorImageVersion, minorImageVersion: PEHeaderConstants.MinorImageVersion, majorSubsystemVersion: PEHeaderConstants.MajorSubsystemVersion, minorSubsystemVersion: PEHeaderConstants.MinorSubsystemVersion, subsystem: subsystem, dllCharacteristics: dllCharacteristics, imageCharacteristics: imageCharacteristics, sizeOfStackReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfStackReserve : PE32HeaderConstants.SizeOfStackReserve), sizeOfStackCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfStackCommit : PE32HeaderConstants.SizeOfStackCommit), sizeOfHeapReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapReserve : PE32HeaderConstants.SizeOfHeapReserve), sizeOfHeapCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapCommit : PE32HeaderConstants.SizeOfHeapCommit))); }
/// <summary> /// Copy PE headers into a PEHeaderBuilder used by PEBuilder. /// </summary> /// <param name="peHeaders">Headers to copy</param> /// <param name="target">Target architecture to set in the header</param> public static PEHeaderBuilder Copy(PEHeaders peHeaders, TargetDetails target) { bool is64BitTarget = target.PointerSize == sizeof(long); Characteristics imageCharacteristics = peHeaders.CoffHeader.Characteristics; if (is64BitTarget) { imageCharacteristics &= ~Characteristics.Bit32Machine; imageCharacteristics |= Characteristics.LargeAddressAware; } int fileAlignment = 0x200; if (!target.IsWindows && !is64BitTarget) { // To minimize wasted VA space on 32 bit systems align file to page bounaries (presumed to be 4K). fileAlignment = 0x1000; } int sectionAlignment = 0x1000; if (!target.IsWindows && is64BitTarget) { // On Linux, we must match the bottom 12 bits of section RVA's to their file offsets. For this reason // we need the same alignment for both. sectionAlignment = fileAlignment; } DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible; if (!is64BitTarget) { dllCharacteristics |= DllCharacteristics.NoSeh; } // Copy over selected DLL characteristics bits from IL image dllCharacteristics |= peHeaders.PEHeader.DllCharacteristics & (DllCharacteristics.TerminalServerAware | DllCharacteristics.AppContainer); if (is64BitTarget) { dllCharacteristics |= DllCharacteristics.HighEntropyVirtualAddressSpace; } return(new PEHeaderBuilder( machine: target.MachineFromTarget(), sectionAlignment: sectionAlignment, fileAlignment: fileAlignment, imageBase: peHeaders.PEHeader.ImageBase, majorLinkerVersion: 11, minorLinkerVersion: 0, majorOperatingSystemVersion: 5, // Win2k = 5.0 for 32-bit images, Win2003 = 5.2 for 64-bit images minorOperatingSystemVersion: is64BitTarget ? (ushort)2 : (ushort)0, majorImageVersion: peHeaders.PEHeader.MajorImageVersion, minorImageVersion: peHeaders.PEHeader.MinorImageVersion, majorSubsystemVersion: peHeaders.PEHeader.MajorSubsystemVersion, minorSubsystemVersion: peHeaders.PEHeader.MinorSubsystemVersion, subsystem: peHeaders.PEHeader.Subsystem, dllCharacteristics: dllCharacteristics, imageCharacteristics: imageCharacteristics, sizeOfStackReserve: peHeaders.PEHeader.SizeOfStackReserve, sizeOfStackCommit: peHeaders.PEHeader.SizeOfStackCommit, sizeOfHeapReserve: 0, sizeOfHeapCommit: 0)); }
/// <summary> /// Fill in PE header information into a PEHeaderBuilder used by PEBuilder. /// </summary> /// <param name="subsystem">Targeting subsystem</param> /// <param name="target">Target architecture to set in the header</param> public static PEHeaderBuilder Create(Subsystem subsystem, TargetDetails target, ulong imageBase) { bool is64BitTarget = target.PointerSize == sizeof(long); Characteristics imageCharacteristics = Characteristics.ExecutableImage | Characteristics.Dll; imageCharacteristics |= is64BitTarget ? Characteristics.LargeAddressAware : Characteristics.Bit32Machine; int fileAlignment = 0x200; bool isWindowsOr32bit = target.IsWindows || !is64BitTarget; if (isWindowsOr32bit) { // To minimize wasted VA space on 32-bit systems (regardless of OS), // align file to page boundaries (presumed to be 4K) // // On Windows we use 4K file alignment (regardless of ptr size), // per requirements of memory mapping API (MapViewOfFile3, et al). // The alternative could be using the same approach as on Unix, but that would result in PEs // incompatible with OS loader. While that is not a problem on Unix, we do not want that on Windows. fileAlignment = 0x1000; } int sectionAlignment = 0x1000; if (!isWindowsOr32bit) { // On 64bit Linux, we must match the bottom 12 bits of section RVA's to their file offsets. For this reason // we need the same alignment for both. // // In addition to that we specify section RVAs to be at least 64K apart, which is > page on most systems. // It ensures that the sections will not overlap when mapped from a singlefile bundle, which introduces a sub-page skew. // // Such format would not be accepted by OS loader on Windows, but it is not a problem on Unix. sectionAlignment = fileAlignment; } // Without NxCompatible the PE executable cannot execute on Windows ARM64 DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible | DllCharacteristics.TerminalServerAware; if (is64BitTarget) { dllCharacteristics |= DllCharacteristics.HighEntropyVirtualAddressSpace; } else { dllCharacteristics |= DllCharacteristics.NoSeh; } return(new PEHeaderBuilder( machine: target.MachineFromTarget(), sectionAlignment: sectionAlignment, fileAlignment: fileAlignment, imageBase: imageBase, majorLinkerVersion: PEHeaderConstants.MajorLinkerVersion, minorLinkerVersion: PEHeaderConstants.MinorLinkerVersion, majorOperatingSystemVersion: PEHeaderConstants.MajorOperatingSystemVersion, minorOperatingSystemVersion: PEHeaderConstants.MinorOperatingSystemVersion, majorImageVersion: PEHeaderConstants.MajorImageVersion, minorImageVersion: PEHeaderConstants.MinorImageVersion, majorSubsystemVersion: PEHeaderConstants.MajorSubsystemVersion, minorSubsystemVersion: PEHeaderConstants.MinorSubsystemVersion, subsystem: subsystem, dllCharacteristics: dllCharacteristics, imageCharacteristics: imageCharacteristics, sizeOfStackReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfStackReserve : PE32HeaderConstants.SizeOfStackReserve), sizeOfStackCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfStackCommit : PE32HeaderConstants.SizeOfStackCommit), sizeOfHeapReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapReserve : PE32HeaderConstants.SizeOfHeapReserve), sizeOfHeapCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapCommit : PE32HeaderConstants.SizeOfHeapCommit))); }
/// <summary> /// Fill in PE header information into a PEHeaderBuilder used by PEBuilder. /// </summary> /// <param name="subsystem">Targeting subsystem</param> /// <param name="target">Target architecture to set in the header</param> public static PEHeaderBuilder Create(Subsystem subsystem, TargetDetails target) { bool is64BitTarget = target.PointerSize == sizeof(long); Characteristics imageCharacteristics = Characteristics.ExecutableImage | Characteristics.Dll; imageCharacteristics |= is64BitTarget ? Characteristics.LargeAddressAware : Characteristics.Bit32Machine; ulong imageBase = is64BitTarget ? PE64HeaderConstants.DllImageBase : PE32HeaderConstants.ImageBase; int fileAlignment = 0x200; if (!target.IsWindows && !is64BitTarget) { // To minimize wasted VA space on 32-bit systems, align file to page boundaries (presumed to be 4K) fileAlignment = 0x1000; } int sectionAlignment = 0x1000; if (!target.IsWindows && is64BitTarget) { // On Linux, we must match the bottom 12 bits of section RVA's to their file offsets. For this reason // we need the same alignment for both. sectionAlignment = fileAlignment; } // Without NxCompatible the PE executable cannot execute on Windows ARM64 DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible | DllCharacteristics.TerminalServerAware; if (is64BitTarget) { dllCharacteristics |= DllCharacteristics.HighEntropyVirtualAddressSpace; } else { dllCharacteristics |= DllCharacteristics.NoSeh; } return(new PEHeaderBuilder( machine: target.MachineFromTarget(), sectionAlignment: sectionAlignment, fileAlignment: fileAlignment, imageBase: imageBase, majorLinkerVersion: PEHeaderConstants.MajorLinkerVersion, minorLinkerVersion: PEHeaderConstants.MinorLinkerVersion, majorOperatingSystemVersion: PEHeaderConstants.MajorOperatingSystemVersion, minorOperatingSystemVersion: PEHeaderConstants.MinorOperatingSystemVersion, majorImageVersion: PEHeaderConstants.MajorImageVersion, minorImageVersion: PEHeaderConstants.MinorImageVersion, majorSubsystemVersion: PEHeaderConstants.MajorSubsystemVersion, minorSubsystemVersion: PEHeaderConstants.MinorSubsystemVersion, subsystem: subsystem, dllCharacteristics: dllCharacteristics, imageCharacteristics: imageCharacteristics, sizeOfStackReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfStackReserve : PE32HeaderConstants.SizeOfStackReserve), sizeOfStackCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfStackCommit : PE32HeaderConstants.SizeOfStackCommit), sizeOfHeapReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapReserve : PE32HeaderConstants.SizeOfHeapReserve), sizeOfHeapCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapCommit : PE32HeaderConstants.SizeOfHeapCommit))); }
/// <summary> /// Copy PE headers into a PEHeaderBuilder used by PEBuilder. /// </summary> /// <param name="peHeaders">Headers to copy</param> /// <param name="target">Target architecture to set in the header</param> public static PEHeaderBuilder Copy(PEHeaders peHeaders, TargetDetails target) { // Default base addresses used by Roslyn const ulong DefaultExeBaseAddress64Bit = 0x1_4000_0000; const ulong DefaultDllBaseAddress64Bit = 0x1_8000_0000; bool is64BitTarget = target.PointerSize == sizeof(long); Characteristics imageCharacteristics = peHeaders.CoffHeader.Characteristics; if (is64BitTarget) { imageCharacteristics &= ~Characteristics.Bit32Machine; imageCharacteristics |= Characteristics.LargeAddressAware; } ulong imageBase = peHeaders.PEHeader.ImageBase; if (target.IsWindows && is64BitTarget && (imageBase <= uint.MaxValue)) { // Base addresses below 4 GiB are reserved for WoW on x64 and disallowed on ARM64. // If the input assembly was compiled for anycpu, its base address is 32-bit and we need to fix it. imageBase = (imageCharacteristics & Characteristics.Dll) != 0 ? DefaultDllBaseAddress64Bit : DefaultExeBaseAddress64Bit; } int fileAlignment = 0x200; if (!target.IsWindows && !is64BitTarget) { // To minimize wasted VA space on 32 bit systems align file to page bounaries (presumed to be 4K). fileAlignment = 0x1000; } int sectionAlignment = 0x1000; if (!target.IsWindows && is64BitTarget) { // On Linux, we must match the bottom 12 bits of section RVA's to their file offsets. For this reason // we need the same alignment for both. sectionAlignment = fileAlignment; } DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible; // Copy over selected DLL characteristics bits from IL image dllCharacteristics |= peHeaders.PEHeader.DllCharacteristics & (DllCharacteristics.TerminalServerAware | DllCharacteristics.AppContainer); if (is64BitTarget) { dllCharacteristics |= DllCharacteristics.HighEntropyVirtualAddressSpace; } else { dllCharacteristics |= DllCharacteristics.NoSeh; } return(new PEHeaderBuilder( machine: target.MachineFromTarget(), sectionAlignment: sectionAlignment, fileAlignment: fileAlignment, imageBase: imageBase, majorLinkerVersion: 11, minorLinkerVersion: 0, majorOperatingSystemVersion: 5, // Win2k = 5.0 for 32-bit images, Win2003 = 5.2 for 64-bit images minorOperatingSystemVersion: is64BitTarget ? (ushort)2 : (ushort)0, majorImageVersion: peHeaders.PEHeader.MajorImageVersion, minorImageVersion: peHeaders.PEHeader.MinorImageVersion, majorSubsystemVersion: peHeaders.PEHeader.MajorSubsystemVersion, minorSubsystemVersion: peHeaders.PEHeader.MinorSubsystemVersion, subsystem: peHeaders.PEHeader.Subsystem, dllCharacteristics: dllCharacteristics, imageCharacteristics: imageCharacteristics, sizeOfStackReserve: peHeaders.PEHeader.SizeOfStackReserve, sizeOfStackCommit: peHeaders.PEHeader.SizeOfStackCommit, sizeOfHeapReserve: 0, sizeOfHeapCommit: 0)); }