Skip to content

Commit 19d88ec

Browse files
authored
pe: Add tests for TLS parser and characteristics constants (#426)
* pe: add tests for TLS parser and characteristics constants * Fix panic on malformed callbacks may cause subtract with overflow * Add reproducible cxx project
1 parent 48da3d8 commit 19d88ec

12 files changed

+825
-1
lines changed

etc/projects/bingen/.gitignore

Lines changed: 413 additions & 0 deletions
Large diffs are not rendered by default.

etc/projects/bingen/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
cmake_minimum_required(VERSION 3.12)
2+
project(bingen LANGUAGES CXX)
3+
option(ENABLE_TLS "Whether to generate TLS in resulting binary" ON)
4+
5+
if(ENABLE_TLS)
6+
add_definitions(-DENABLE_TLS)
7+
endif()
8+
9+
set(CMAKE_SYSTEM_NAME Windows)
10+
11+
add_executable(bin WIN32 "main.cc")
12+
set_target_properties(bin PROPERTIES LANGUAGE CXX)
13+
target_compile_options(bin PRIVATE
14+
/GS- # Disable generation of stack check handlers
15+
/GL # Enable whole program optimization
16+
)
17+
target_link_options(bin PRIVATE
18+
/ENTRY:main # Explicit entry symbol since there are no CRT/libs to be linked
19+
/MANIFEST:NO # Disable manifest
20+
/NODEFAULTLIB # No libs; we want a pure binary
21+
/FIXED # No relocs
22+
/DYNAMICBASE:NO # No ASLR
23+
/SAFESEH # No unwinds
24+
/MERGE:.data=.text /MERGE:.CRT=.text /MERGE:.tls=.text # Combine sections to avoid paddings
25+
)

etc/projects/bingen/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Test binary generator for Portable Executable
2+
3+
## Preprocessor definitions
4+
5+
- `ENABLE_TLS`: if defined, compile the binary with Thread Local Storage (TLS) enabled.
6+
7+
## How to build
8+
9+
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`).
10+
11+
While MSVC toolchains are theoretically possible; but not recommended.
12+
13+
### CMake
14+
15+
**Prerequisites**
16+
- 64-bit Windows host
17+
- CMake 3.12 or later
18+
- [Ninja build system](https://ninja-build.org) (any version)
19+
- Clang (ideally 17 or later)
20+
21+
Firstly run the following commands on terminal:
22+
23+
```bash
24+
mkdir build
25+
```
26+
27+
```bash
28+
cd build
29+
```
30+
31+
```bash
32+
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang-cl
33+
```
34+
35+
Then build the binary:
36+
37+
```bash
38+
cmake --build . --config release
39+
```
40+
41+
### Visual Studio
42+
43+
**Prerequisites**
44+
- 64-bit Windows host
45+
- Visual Studio 2022 (editions do not matter)
46+
- C++ Clang Compiler for Windows [or this method if you have manual installation](#optional-referencing-manually-installed-clang-toolchain)
47+
- MSBuild support for LLVM (clang-cl) toolset
48+
49+
Open `bingen.sln` under [`etc/projects/bingen`](etc/projects/bingen/) and compile as Release (Debug configuration is redacted).
50+
51+
#### Optional: Referencing manually-installed Clang toolchain
52+
53+
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`:
54+
55+
```xml
56+
<!-- Directory.build.props -->
57+
<Project>
58+
<PropertyGroup>
59+
<LLVMInstallDir>C:/path/to/llvm/bin</LLVMInstallDir>
60+
<LLVMToolsVersion>xx.xxxx.x</LLVMToolsVersion>
61+
</PropertyGroup>
62+
</Project>
63+
```

etc/projects/bingen/bingen.sln

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.12.35527.113
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bingen", "bingen.vcxproj", "{45EE6877-125F-49B9-9837-D91D38F6C2A3}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Release|x64 = Release|x64
11+
Release|x86 = Release|x86
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x64.ActiveCfg = Release|x64
15+
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x64.Build.0 = Release|x64
16+
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x86.ActiveCfg = Release|Win32
17+
{45EE6877-125F-49B9-9837-D91D38F6C2A3}.Release|x86.Build.0 = Release|Win32
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
EndGlobal

etc/projects/bingen/bingen.vcxproj

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Label="ProjectConfigurations">
4+
<ProjectConfiguration Include="Release|Win32">
5+
<Configuration>Release</Configuration>
6+
<Platform>Win32</Platform>
7+
</ProjectConfiguration>
8+
<ProjectConfiguration Include="Release|x64">
9+
<Configuration>Release</Configuration>
10+
<Platform>x64</Platform>
11+
</ProjectConfiguration>
12+
</ItemGroup>
13+
<PropertyGroup Label="Globals">
14+
<ProjectGuid>{45EE6877-125F-49B9-9837-D91D38F6C2A3}</ProjectGuid>
15+
</PropertyGroup>
16+
<ItemGroup>
17+
<ClCompile Include="main.cc" />
18+
</ItemGroup>
19+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
20+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
21+
<ConfigurationType>Application</ConfigurationType>
22+
<UseDebugLibraries>false</UseDebugLibraries>
23+
<PlatformToolset>v143</PlatformToolset>
24+
<WholeProgramOptimization>true</WholeProgramOptimization>
25+
<CharacterSet>Unicode</CharacterSet>
26+
</PropertyGroup>
27+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
28+
<ConfigurationType>Application</ConfigurationType>
29+
<UseDebugLibraries>false</UseDebugLibraries>
30+
<PlatformToolset>ClangCL</PlatformToolset>
31+
<WholeProgramOptimization>true</WholeProgramOptimization>
32+
<CharacterSet>Unicode</CharacterSet>
33+
</PropertyGroup>
34+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
35+
<ImportGroup Label="ExtensionSettings">
36+
</ImportGroup>
37+
<ImportGroup Label="Shared">
38+
</ImportGroup>
39+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
40+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
41+
</ImportGroup>
42+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
43+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
44+
</ImportGroup>
45+
<PropertyGroup Label="UserMacros" />
46+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
47+
<GenerateManifest>false</GenerateManifest>
48+
</PropertyGroup>
49+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
50+
<ClCompile>
51+
<WarningLevel>Level3</WarningLevel>
52+
<FunctionLevelLinking>true</FunctionLevelLinking>
53+
<IntrinsicFunctions>true</IntrinsicFunctions>
54+
<SDLCheck>true</SDLCheck>
55+
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
56+
<ConformanceMode>true</ConformanceMode>
57+
</ClCompile>
58+
<Link>
59+
<SubSystem>Console</SubSystem>
60+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
61+
<OptimizeReferences>true</OptimizeReferences>
62+
<GenerateDebugInformation>true</GenerateDebugInformation>
63+
</Link>
64+
</ItemDefinitionGroup>
65+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
66+
<ClCompile>
67+
<WarningLevel>Level3</WarningLevel>
68+
<FunctionLevelLinking>true</FunctionLevelLinking>
69+
<IntrinsicFunctions>true</IntrinsicFunctions>
70+
<SDLCheck>true</SDLCheck>
71+
<PreprocessorDefinitions>NDEBUG;_CONSOLE;ENABLE_TLS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
72+
<ConformanceMode>true</ConformanceMode>
73+
<BufferSecurityCheck>false</BufferSecurityCheck>
74+
</ClCompile>
75+
<Link>
76+
<SubSystem>Console</SubSystem>
77+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
78+
<OptimizeReferences>true</OptimizeReferences>
79+
<GenerateDebugInformation>false</GenerateDebugInformation>
80+
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
81+
<EntryPointSymbol>main</EntryPointSymbol>
82+
<RandomizedBaseAddress>false</RandomizedBaseAddress>
83+
<FixedBaseAddress>true</FixedBaseAddress>
84+
<MergeSections>/MERGE:.data=.text /MERGE:.CRT=.text /MERGE:.tls=.text</MergeSections>
85+
<ImageHasSafeExceptionHandlers>true</ImageHasSafeExceptionHandlers>
86+
</Link>
87+
</ItemDefinitionGroup>
88+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
89+
<ImportGroup Label="ExtensionTargets">
90+
</ImportGroup>
91+
</Project>

etc/projects/bingen/main.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <Windows.h>
2+
3+
#if !(_WIN64)
4+
#error "Only x64 is supported"
5+
#endif
6+
7+
#ifdef ENABLE_TLS
8+
EXTERN_C unsigned int _tls_index{};
9+
static void NTAPI tls_callback(PVOID, DWORD, PVOID) {}
10+
11+
// Force include unreferenced symbols
12+
// Marker symbol to tell the linker that TLS is being used
13+
#pragma comment(linker, "/INCLUDE:_tls_used")
14+
#pragma comment(linker, "/INCLUDE:_tls_callback")
15+
16+
#pragma data_seg(".tls")
17+
int _tls_start = 0;
18+
#pragma const_seg()
19+
20+
#pragma data_seg(".tls$ZZZ")
21+
int _tls_end = 0;
22+
#pragma const_seg()
23+
24+
#pragma data_seg(".CRT$XLA")
25+
int __xl_a = 0;
26+
#pragma const_seg()
27+
28+
#pragma data_seg(".CRT$XLZ")
29+
int __xl_z = 0;
30+
#pragma const_seg()
31+
32+
#pragma const_seg(".CRT$XLB")
33+
EXTERN_C const PIMAGE_TLS_CALLBACK _tls_callback[] = { &tls_callback, 0 };
34+
#pragma const_seg()
35+
36+
EXTERN_C IMAGE_TLS_DIRECTORY _tls_used = {
37+
/*StartAddressOfRawData*/(ULONG64)&_tls_start,
38+
/*EndAddressOfRawData*/(ULONG64)&_tls_end,
39+
/*AddressOfIndex*/(ULONG64)&_tls_index,
40+
/*AddressOfCallbacks*/(ULONG64)&_tls_callback,
41+
/*SizeOfZeroFill*/0,
42+
/*Characteristics*/{0},
43+
};
44+
#endif // #ifdef ENABLE_TLS
45+
46+
int main() { return 0; }

0 commit comments

Comments
 (0)