From 26d318e4a9437f95b6a2e7abace5f2b867c88a3e Mon Sep 17 00:00:00 2001 From: sivadeilra Date: Tue, 24 Jun 2025 09:22:38 -0700 Subject: Add support for Windows Secure Hot-Patching (#138972) This PR adds some of the support needed for Windows hot-patching. Windows implements a form of hot-patching. This allows patches to be applied to Windows apps, drivers, and the kernel, without rebooting or restarting any of these components. Hot-patching is a complex technology and requires coordination between the OS, compilers, linkers, and additional tools. This PR adds support to Clang and LLVM for part of the hot-patching process. It enables LLVM to generate the required code changes and to generate CodeView symbols which identify hot-patched functions. The PR provides new command-line arguments to Clang which allow developers to identify the list of functions that need to be hot-patched. This PR also allows LLVM to directly receive the list of functions to be modified, so that language front-ends which have not yet been modified (such as Rust) can still make use of hot-patching. This PR: * Adds a `MarkedForWindowsHotPatching` LLVM function attribute. This attribute indicates that a function should be _hot-patched_. This generates a new CodeView symbol, `S_HOTPATCHFUNC`, which identifies any function that has been hot-patched. This attribute also causes accesses to global variables to be indirected through a `_ref_*` global variable. This allows hot-patched functions to access the correct version of a global variable; the hot-patched code needs to access the variable in the _original_ image, not the patch image. * Adds a `AllowDirectAccessInHotPatchFunction` LLVM attribute. This attribute may be placed on global variable declarations. It indicates that the variable may be safely accessed without the `_ref_*` indirection. * Adds two Clang command-line parameters: `-fms-hotpatch-functions-file` and `-fms-hotpatch-functions-list`. The `-file` flag may point to a text file, which contains a list of functions to be hot-patched (one function name per line). The `-list` flag simply directly identifies functions to be patched, using a comma-separated list. These two command-line parameters may also be combined; the final set of functions to be hot-patched is the union of the two sets. * Adds similar LLVM command-line parameters: `--ms-hotpatch-functions-file` and `--ms-hotpatch-functions-list`. * Adds integration tests for both LLVM and Clang. * Adds support for dumping the new `S_HOTPATCHFUNC` CodeView symbol. Although the flags are redundant between Clang and LLVM, this allows additional languages (such as Rust) to take advantage of hot-patching support before they have been modified to generate the required attributes. Credit to @dpaoliello, who wrote the original form of this patch. --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp') diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index ea57a8f..5e1b313 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -669,6 +669,8 @@ void CodeViewDebug::endModule() { if (!Asm) return; + emitSecureHotPatchInformation(); + emitInlineeLinesSubsection(); // Emit per-function debug information. @@ -823,6 +825,28 @@ void CodeViewDebug::emitObjName() { endSymbolRecord(CompilerEnd); } +void CodeViewDebug::emitSecureHotPatchInformation() { + MCSymbol *hotPatchInfo = nullptr; + + for (const auto &F : MMI->getModule()->functions()) { + if (!F.isDeclarationForLinker() && + F.hasFnAttribute("marked_for_windows_hot_patching")) { + if (hotPatchInfo == nullptr) + hotPatchInfo = beginCVSubsection(DebugSubsectionKind::Symbols); + MCSymbol *HotPatchEnd = beginSymbolRecord(SymbolKind::S_HOTPATCHFUNC); + auto *SP = F.getSubprogram(); + OS.AddComment("Function"); + OS.emitInt32(getFuncIdForSubprogram(SP).getIndex()); + OS.AddComment("Name"); + emitNullTerminatedSymbolName(OS, F.getName()); + endSymbolRecord(HotPatchEnd); + } + } + + if (hotPatchInfo != nullptr) + endCVSubsection(hotPatchInfo); +} + namespace { struct Version { int Part[4]; -- cgit v1.1