Skip to content

Commit 7a0138d

Browse files
author
Stephen Gutekanst
committed
Replace proprietary dxil.dll code signing blob with FOSS alternative
Normal usage of dxcompiler requires that you use a proprietary `dxil.dll` distributed by Microsoft. If this is not found next to the dxcompiler binary when compiling shaders, then the final shader binary will not be signed and as a result will not run on others' machines. DXC is also written with the assumption that dxil.dll and dxcompiler.dll itself are loaded as dynamic libraries. This, combined with dxil.dll being a proprietary blob, is annoying for users of Mach engine and [many others](https://bevy-cheatbook.github.io/platforms/windows.html#dxc-compiler-support) as it just complicates application distribution further. This commit replaces dxcompiler.dll runtime loading behavior with an 'emulated' dynamic library, effectively completing our effort to make dxcompiler a static library. dxil.dll is closed-source, so we cannot simply patch it in the same way. To fix this, we outright disable runtime loading of dxil.dll and silence warnings related to it not being present / the final binary not being code signed. Instead, once the compiler would emit a compiled shader blob, we perform our own code signing algorithm (Mach Siegbert Vogt DXCSA) which results in a bitwise identical compiled shader, and thus dxil.dll is no longer needed to perform code signing of shaders. Ultimately, this means mach-dxcompiler can be a fully static library, code signing included. Signed-off-by: Stephen Gutekanst <[email protected]>
1 parent 093ec70 commit 7a0138d

File tree

11 files changed

+394
-79
lines changed

11 files changed

+394
-79
lines changed

include/dxc/Support/dxcapi.use.h

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,26 @@
1717
namespace dxc {
1818

1919
extern const char *kDxCompilerLib;
20-
// Mach change start: static dxil
21-
// extern const char *kDxilLib;
20+
extern const char *kDxilLib;
21+
22+
// Mach change start: static dxcompiler/dxil
23+
extern "C" BOOL MachDxcompilerInvokeDllMain();
24+
extern "C" void MachDxcompilerInvokeDllShutdown();
25+
static bool dxcompiler_dll_loaded = false;
2226
// Mach change end
2327

2428
// Helper class to dynamically load the dxcompiler or a compatible libraries.
2529
class DxcDllSupport {
2630
protected:
27-
// Mach change start: static dxcompiler
31+
// Mach change start: static dxcompiler/dxil
2832
BOOL m_initialized;
33+
std::string m_dllName;
2934
// Mach change end
3035
HMODULE m_dll;
3136
DxcCreateInstanceProc m_createFn;
3237
DxcCreateInstance2Proc m_createFn2;
3338

34-
// Mach change start: static dxcompiler
39+
// Mach change start: static dxcompiler/dxil
3540
// HRESULT InitializeInternal(LPCSTR dllName, LPCSTR fnName) {
3641
// if (m_dll != nullptr)
3742
// return S_OK;
@@ -79,10 +84,44 @@ class DxcDllSupport {
7984
// return S_OK;
8085
// }
8186
HRESULT InitializeInternal(LPCSTR dllName, LPCSTR fnName) {
87+
// The compilation process occurs as follows:
88+
//
89+
// 1. Compilation begins
90+
// 2. InitializeInternal(kDxCompilerLib, "DxcCreateInstance") is called
91+
// 3. MachDxcompilerInvokeDllMain() is invoked..
92+
// 3a. which calls dxcompiler.dll's DllMain entrypoint
93+
// 3b. which triggers loading of dxil.dll
94+
// 4. InitializeInternal(kDxilLib, "DxcCreateInstance") is called
95+
// 4a. E_FAIL is returned, indicating dxil.dll is not present
96+
// 4b. We silence the warning related to dxil.dll not being present and
97+
// code signing not occuring (commented out)
98+
// 5. We perform Mach Siegbert Vogt DXCSA on the final container/blob before the
99+
// compiler writes it to disk.
100+
//
101+
// Look for "DXCSA" in the codebase to see where signing happens.
102+
103+
// Store which DLL this is for later, so we can MachDxcompilerInvokeDllShutdown later.
104+
m_dllName = dllName;
105+
106+
// If this is dxil.dll, emulate that we do not have it.
107+
if (strcmp(dllName, kDxilLib) == 0) {
108+
return E_FAIL;
109+
}
110+
111+
// If this is dxcompiler.dll, emulate as if we loaded it in-process.
82112
if (strcmp(fnName, "DxcCreateInstance") == 0) {
83113
m_initialized = true;
84114
m_createFn = &DxcCreateInstance;
85115
m_createFn2 = &DxcCreateInstance2;
116+
117+
// If this is the first time this is called, invoke DllMain()
118+
if (!dxcompiler_dll_loaded) {
119+
if (!MachDxcompilerInvokeDllMain()) {
120+
fprintf(stderr, "mach-dxcompiler: MachDxcompilerInvokeDllMain failed\n");
121+
return E_FAIL;
122+
}
123+
dxcompiler_dll_loaded = true;
124+
}
86125
return S_OK;
87126
}
88127
fprintf(stderr, "mach-dxcompiler: InitializeInternal: unknown GetProcAddress name: %s\n", fnName);
@@ -91,15 +130,17 @@ class DxcDllSupport {
91130
// Mach change end
92131

93132
public:
94-
// Mach change start: static dxcompiler
133+
// Mach change start: static dxcompiler/dxil
95134
// DxcDllSupport() : m_dll(nullptr), m_createFn(nullptr), m_createFn2(nullptr) {}
96135
DxcDllSupport() : m_initialized(false), m_dll(nullptr), m_createFn(nullptr), m_createFn2(nullptr) {}
97136
// Mach change end
98137

99138
DxcDllSupport(DxcDllSupport &&other) {
100-
// Mach change start: static dxcompiler
139+
// Mach change start: static dxcompiler/dxil
101140
m_initialized = other.m_initialized;
102141
other.m_initialized = false;
142+
m_dllName = other.m_dllName;
143+
other.m_dllName = nullptr;
103144
// Mach change end
104145
m_dll = other.m_dll;
105146
other.m_dll = nullptr;
@@ -127,7 +168,7 @@ class DxcDllSupport {
127168
HRESULT CreateInstance(REFCLSID clsid, REFIID riid, IUnknown **pResult) {
128169
if (pResult == nullptr)
129170
return E_POINTER;
130-
// Mach change start: static dxcompiler
171+
// Mach change start: static dxcompiler/dxil
131172
// if (m_dll == nullptr)
132173
if (!m_initialized)
133174
// Mach change end
@@ -147,7 +188,7 @@ class DxcDllSupport {
147188
IUnknown **pResult) {
148189
if (pResult == nullptr)
149190
return E_POINTER;
150-
// Mach change start: static dxcompiler
191+
// Mach change start: static dxcompiler/dxil
151192
// if (m_dll == nullptr)
152193
if (!m_initialized)
153194
// Mach change end
@@ -160,12 +201,18 @@ class DxcDllSupport {
160201

161202
bool HasCreateWithMalloc() const { return m_createFn2 != nullptr; }
162203

163-
// Mach change start: static dxcompiler
204+
// Mach change start: static dxcompiler/dxil
164205
// bool IsEnabled() const { return m_dll != nullptr; }
165206
bool IsEnabled() const { return m_initialized; }
166207
// Mach change start
167208

168209
void Cleanup() {
210+
// Mach change start: static dxcompiler/dxil
211+
if (m_dllName == kDxCompilerLib && dxcompiler_dll_loaded) {
212+
dxcompiler_dll_loaded = false;
213+
MachDxcompilerInvokeDllShutdown();
214+
}
215+
// Mach change end
169216
if (m_dll != nullptr) {
170217
m_createFn = nullptr;
171218
m_createFn2 = nullptr;
@@ -178,12 +225,13 @@ class DxcDllSupport {
178225
}
179226
}
180227

181-
// Mach change start: static dxcompiler
228+
// Mach change start: static dxcompiler/dxil
182229
// HMODULE Detach() {
183230
// HMODULE hModule = m_dll;
184231
// m_dll = nullptr;
185232
// return hModule;
186233
// }
234+
void Detach() { m_initialized = false; }
187235
// Mach change end
188236
};
189237

lib/DxcSupport/dxcapi.use.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@ namespace dxc {
2929
#define CMAKE_SHARED_LIBRARY_PREFIX
3030
#define CMAKE_SHARED_LIBRARY_SUFFIX
3131
// Mach change end
32+
3233
const char *kDxCompilerLib =
3334
CMAKE_SHARED_LIBRARY_PREFIX "dxcompiler" CMAKE_SHARED_LIBRARY_SUFFIX;
34-
// Mach change start: static dxil
35-
// const char *kDxilLib =
36-
// CMAKE_SHARED_LIBRARY_PREFIX "dxil" CMAKE_SHARED_LIBRARY_SUFFIX;
37-
//
38-
// Mach change end
35+
const char *kDxilLib =
36+
CMAKE_SHARED_LIBRARY_PREFIX "dxil" CMAKE_SHARED_LIBRARY_SUFFIX;
3937

4038
#ifdef _WIN32
4139
static void TrimEOL(char *pMsg) {

tools/clang/tools/dxclib/dxc.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,12 +1339,10 @@ void DxcContext::GetCompilerVersionInfo(llvm::raw_string_ostream &OS) {
13391339
m_Opts.ExternalFn.empty() ? nullptr : m_Opts.ExternalFn.data(),
13401340
m_dxcSupport);
13411341

1342-
// Mach change start: static dxil
1343-
// // Print validator if exists
1344-
// DxcDllSupport DxilSupport;
1345-
// DxilSupport.InitializeForDll(kDxilLib, "DxcCreateInstance");
1346-
// WriteDXILVersionInfo(OS, DxilSupport);
1347-
// Mach change end
1342+
// Print validator if exists
1343+
DxcDllSupport DxilSupport;
1344+
DxilSupport.InitializeForDll(kDxilLib, "DxcCreateInstance");
1345+
WriteDXILVersionInfo(OS, DxilSupport);
13481346
}
13491347

13501348
#ifndef VERSION_STRING_SUFFIX

tools/clang/tools/dxcompiler/DXCompiler.cpp

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ static HRESULT InitMaybeFail() throw() {
6565
fsSetup = true;
6666
IFC(hlsl::SetupRegistryPassForHLSL());
6767
IFC(hlsl::SetupRegistryPassForPIX());
68-
// Mach change start: static dxil
69-
// IFC(DxilLibInitialize());
70-
// Mach change end
68+
IFC(DxilLibInitialize());
7169
if (hlsl::options::initHlslOptTable()) {
7270
hr = E_FAIL;
7371
goto Cleanup;
@@ -87,18 +85,34 @@ static HRESULT InitMaybeFail() throw() {
8785
return hr;
8886
}
8987
#if defined(LLVM_ON_UNIX)
90-
HRESULT __attribute__((constructor)) DllMain() { return InitMaybeFail(); }
88+
// Mach change start: static dxcompiler/dxil
89+
// HRESULT __attribute__((constructor)) DllMain() { return InitMaybeFail(); }
90+
HRESULT MachDxcompiler_DllMain() { return InitMaybeFail(); }
91+
// Mach change end
9192

92-
void __attribute__((destructor)) DllShutdown() {
93+
// Mach change start: static dxcompiler/dxil
94+
// void __attribute__((destructor)) DllShutdown() {
95+
void MachDxcompiler_DllShutdown() {
96+
// Mach change end
9397
DxcSetThreadMallocToDefault();
9498
::hlsl::options::cleanupHlslOptTable();
9599
::llvm::sys::fs::CleanupPerThreadFileSystem();
96100
::llvm::llvm_shutdown();
97101
DxcClearThreadMalloc();
98102
DxcCleanupThreadMalloc();
99103
}
104+
// Mach change start: static dxcompiler/dxil
105+
extern "C" {
106+
BOOL MachDxcompilerInvokeDllMain() {
107+
return SUCCEEDED(MachDxcompiler_DllMain());
108+
}
109+
void MachDxcompilerInvokeDllShutdown() {
110+
MachDxcompiler_DllShutdown();
111+
}
112+
}
113+
// Mach change end
100114
#else // LLVM_ON_UNIX
101-
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved) {
115+
BOOL WINAPI MachDxcompiler_DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved) {
102116
BOOL result = TRUE;
103117
if (Reason == DLL_PROCESS_ATTACH) {
104118
EventRegisterMicrosoft_Windows_DXCompiler_API();
@@ -112,14 +126,12 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved) {
112126
::hlsl::options::cleanupHlslOptTable();
113127
::llvm::sys::fs::CleanupPerThreadFileSystem();
114128
::llvm::llvm_shutdown();
115-
// Mach change start: static dxil
116-
// if (reserved ==
117-
// NULL) { // FreeLibrary has been called or the DLL load failed
118-
// DxilLibCleanup(DxilLibCleanUpType::UnloadLibrary);
119-
// } else { // Process termination. We should not call FreeLibrary()
120-
// DxilLibCleanup(DxilLibCleanUpType::ProcessTermination);
121-
// }
122-
// Mach change end
129+
if (reserved ==
130+
NULL) { // FreeLibrary has been called or the DLL load failed
131+
DxilLibCleanup(DxilLibCleanUpType::UnloadLibrary);
132+
} else { // Process termination. We should not call FreeLibrary()
133+
DxilLibCleanup(DxilLibCleanUpType::ProcessTermination);
134+
}
123135
DxcClearThreadMalloc();
124136
DxcCleanupThreadMalloc();
125137
DxcEtw_DXCompilerShutdown_Stop(S_OK);
@@ -128,4 +140,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved) {
128140

129141
return result;
130142
}
143+
// Mach change start: static dxcompiler/dxil
144+
extern "C" {
145+
BOOL MachDxcompilerInvokeDllMain() {
146+
return MachDxcompiler_DllMain(nullptr, DLL_PROCESS_ATTACH, nullptr);
147+
}
148+
void MachDxcompilerInvokeDllShutdown() {
149+
MachDxcompiler_DllMain(nullptr, DLL_PROCESS_DETACH, nullptr);
150+
}
151+
}
152+
// Mach change end
131153
#endif // LLVM_ON_UNIX

0 commit comments

Comments
 (0)