Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PE: Add tests for TLS parser and characteristics constants #426

Merged
merged 20 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
413 changes: 413 additions & 0 deletions etc/projects/bingen/.gitignore

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions etc/projects/bingen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.12)
project(bingen LANGUAGES CXX)
option(ENABLE_TLS "Whether to generate TLS in resulting binary" ON)

if(ENABLE_TLS)
add_definitions(-DENABLE_TLS)
endif()

set(CMAKE_SYSTEM_NAME Windows)

add_executable(bin WIN32 "main.cc")
set_target_properties(bin PROPERTIES LANGUAGE CXX)
target_compile_options(bin PRIVATE
/GS- # Disable generation of stack check handlers
/GL # Enable whole program optimization
)
target_link_options(bin PRIVATE
/ENTRY:main # Explicit entry symbol since there are no CRT/libs to be linked
/MANIFEST:NO # Disable manifest
/NODEFAULTLIB # No libs; we want a pure binary
/FIXED # No relocs
/DYNAMICBASE:NO # No ASLR
/SAFESEH # No unwinds
/MERGE:.data=.text /MERGE:.CRT=.text /MERGE:.tls=.text # Combine sections to avoid paddings
)
63 changes: 63 additions & 0 deletions etc/projects/bingen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Test binary generator for Portable Executable

## Preprocessor definitions

- `ENABLE_TLS`: if defined, compile the binary with Thread Local Storage (TLS) enabled.

## How to build

This project is designed to be compiled by Clang (`clang-cl`) _not_ MSVC toolchain, primarily because 1) MSVC linker supports more features and may unexpectedly generate larger binaries than LLD linker under Clang, 2) compiler and linker flags are designed for specifically Clang for best efforts in reducing size of the resulting binary, 3) sometimes LLD links much smarter e.g., metadatas such as unnecessary rich headers (can be disabled by `/EMITTOOLVERSIONINFO:NO`).

While MSVC toolchains are theoretically possible; but not recommended.

### CMake

**Prerequisites**
- 64-bit Windows host
- CMake 3.12 or later
- [Ninja build system](https://ninja-build.org) (any version)
- Clang (ideally 17 or later)

Firstly run the following commands on terminal:

```bash
mkdir build
```

```bash
cd build
```

```bash
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang-cl
```

Then build the binary:

```bash
cmake --build . --config release
```

### Visual Studio

**Prerequisites**
- 64-bit Windows host
- Visual Studio 2022 (editions do not matter)
- C++ Clang Compiler for Windows [or this method if you have manual installation](#optional-referencing-manually-installed-clang-toolchain)
- MSBuild support for LLVM (clang-cl) toolset

Open `bingen.sln` under [`etc/projects/bingen`](etc/projects/bingen/) and compile as Release (Debug configuration is redacted).

#### Optional: Referencing manually-installed Clang toolchain

If you do not have or not willing to install Clang under Visual Studio individual components, [customize the build by folder for MSBuild](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022) by deploying following `Directory.build.props` right next to the `.sln`:

```xml
<!-- Directory.build.props -->
<Project>
<PropertyGroup>
<LLVMInstallDir>C:/path/to/llvm/bin</LLVMInstallDir>
<LLVMToolsVersion>xx.xxxx.x</LLVMToolsVersion>
</PropertyGroup>
</Project>
```
22 changes: 22 additions & 0 deletions etc/projects/bingen/bingen.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35527.113
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bingen", "bingen.vcxproj", "{45EE6877-125F-49B9-9837-D91D38F6C2A3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x64.ActiveCfg = Release|x64
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x64.Build.0 = Release|x64
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x86.ActiveCfg = Release|Win32
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
91 changes: 91 additions & 0 deletions etc/projects/bingen/bingen.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{45EE6877-125F-49B9-9837-D91D38F6C2A3}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="main.cc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>ClangCL</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;ENABLE_TLS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<EntryPointSymbol>main</EntryPointSymbol>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<FixedBaseAddress>true</FixedBaseAddress>
<MergeSections>/MERGE:.data=.text /MERGE:.CRT=.text /MERGE:.tls=.text</MergeSections>
<ImageHasSafeExceptionHandlers>true</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
46 changes: 46 additions & 0 deletions etc/projects/bingen/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <Windows.h>

#if !(_WIN64)
#error "Only x64 is supported"
#endif

#ifdef ENABLE_TLS
EXTERN_C unsigned int _tls_index{};
static void NTAPI tls_callback(PVOID, DWORD, PVOID) {}

// Force include unreferenced symbols
// Marker symbol to tell the linker that TLS is being used
#pragma comment(linker, "/INCLUDE:_tls_used")
#pragma comment(linker, "/INCLUDE:_tls_callback")

#pragma data_seg(".tls")
int _tls_start = 0;
#pragma const_seg()

#pragma data_seg(".tls$ZZZ")
int _tls_end = 0;
#pragma const_seg()

#pragma data_seg(".CRT$XLA")
int __xl_a = 0;
#pragma const_seg()

#pragma data_seg(".CRT$XLZ")
int __xl_z = 0;
#pragma const_seg()

#pragma const_seg(".CRT$XLB")
EXTERN_C const PIMAGE_TLS_CALLBACK _tls_callback[] = { &tls_callback, 0 };
#pragma const_seg()

EXTERN_C IMAGE_TLS_DIRECTORY _tls_used = {
/*StartAddressOfRawData*/(ULONG64)&_tls_start,
/*EndAddressOfRawData*/(ULONG64)&_tls_end,
/*AddressOfIndex*/(ULONG64)&_tls_index,
/*AddressOfCallbacks*/(ULONG64)&_tls_callback,
/*SizeOfZeroFill*/0,
/*Characteristics*/{0},
};
#endif // #ifdef ENABLE_TLS

int main() { return 0; }
Loading
Loading