[clang] [llvm] Add support for Windows Secure Hot-Patching (redo) (PR #145565)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 24 11:24:31 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: None (sivadeilra)
<details>
<summary>Changes</summary>
(This is a re-do of #<!-- -->138972, which had a minor warning in `Clang.cpp`.)
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.
---
Patch is 56.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/145565.diff
31 Files Affected:
- (modified) clang/include/clang/Basic/CodeGenOptions.h (+7)
- (modified) clang/include/clang/Driver/Options.td (+18)
- (modified) clang/lib/CodeGen/CGCall.cpp (+7)
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+29)
- (modified) clang/lib/CodeGen/CodeGenModule.h (+5)
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+8)
- (added) clang/test/CodeGen/X86/ms-secure-hotpatch-bad-file.c (+18)
- (added) clang/test/CodeGen/X86/ms-secure-hotpatch-cpp.cpp (+24)
- (added) clang/test/CodeGen/X86/ms-secure-hotpatch-eh.cpp (+26)
- (added) clang/test/CodeGen/X86/ms-secure-hotpatch-globals.c (+135)
- (added) clang/test/CodeGen/X86/ms-secure-hotpatch-lto.c (+26)
- (added) clang/test/CodeGen/X86/ms-secure-hotpatch.c (+23)
- (modified) llvm/include/llvm/CodeGen/Passes.h (+3)
- (modified) llvm/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def (+2)
- (modified) llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h (+15)
- (modified) llvm/include/llvm/IR/Attributes.td (+10)
- (modified) llvm/include/llvm/InitializePasses.h (+1)
- (modified) llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (+24)
- (modified) llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h (+2)
- (modified) llvm/lib/CodeGen/CMakeLists.txt (+1)
- (modified) llvm/lib/CodeGen/TargetPassConfig.cpp (+3)
- (added) llvm/lib/CodeGen/WindowsSecureHotPatching.cpp (+617)
- (modified) llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp (+7)
- (modified) llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp (+7)
- (modified) llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp (+5)
- (added) llvm/test/CodeGen/X86/ms-secure-hotpatch-attr.ll (+38)
- (added) llvm/test/CodeGen/X86/ms-secure-hotpatch-bad-file.ll (+16)
- (added) llvm/test/CodeGen/X86/ms-secure-hotpatch-direct-global-access.ll (+39)
- (added) llvm/test/CodeGen/X86/ms-secure-hotpatch-functions-file.ll (+39)
- (added) llvm/test/CodeGen/X86/ms-secure-hotpatch-functions-list.ll (+38)
- (modified) llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp (+8)
``````````diff
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 7ba21fca6dd6b..77a0c559f7689 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -495,6 +495,13 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// A list of functions that are replacable by the loader.
std::vector<std::string> LoaderReplaceableFunctionNames;
+ /// The name of a file that contains functions which will be compiled for
+ /// hotpatching. See -fms-secure-hotpatch-functions-file.
+ std::string MSSecureHotPatchFunctionsFile;
+
+ /// A list of functions which will be compiled for hotpatching.
+ /// See -fms-secure-hotpatch-functions-list.
+ std::vector<std::string> MSSecureHotPatchFunctionsList;
public:
// Define accessors/mutators for code generation options of enumeration type.
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 4f91b82a3bfa6..26e953f7ac613 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3838,6 +3838,24 @@ def fms_hotpatch : Flag<["-"], "fms-hotpatch">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, CLOption]>,
HelpText<"Ensure that all functions can be hotpatched at runtime">,
MarshallingInfoFlag<CodeGenOpts<"HotPatch">>;
+
+// See llvm/lib/CodeGen/WindowsSecureHotPatching.cpp
+def fms_secure_hotpatch_functions_file
+ : Joined<["-"], "fms-secure-hotpatch-functions-file=">,
+ Group<f_Group>,
+ Visibility<[ClangOption, CC1Option, CLOption]>,
+ MarshallingInfoString<CodeGenOpts<"MSSecureHotPatchFunctionsFile">>,
+ HelpText<"Path to a file that contains a list of mangled names of "
+ "functions that should be hot-patched for Windows Secure "
+ "Hot-Patching">;
+def fms_secure_hotpatch_functions_list
+ : CommaJoined<["-"], "fms-secure-hotpatch-functions-list=">,
+ Group<f_Group>,
+ Visibility<[ClangOption, CC1Option, CLOption]>,
+ MarshallingInfoStringVector<CodeGenOpts<"MSSecureHotPatchFunctionsList">>,
+ HelpText<"List of mangled symbol names of functions that should be "
+ "hot-patched for Windows Secure Hot-Patching">;
+
def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Override the default ABI to return all structs on the stack">;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index fd75de42515da..c8c3d6b20c496 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -2660,6 +2660,13 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
// CPU/feature overrides. addDefaultFunctionDefinitionAttributes
// handles these separately to set them based on the global defaults.
GetCPUAndFeaturesAttributes(CalleeInfo.getCalleeDecl(), FuncAttrs);
+
+ // Windows hotpatching support
+ if (!MSHotPatchFunctions.empty()) {
+ bool IsHotPatched = llvm::binary_search(MSHotPatchFunctions, Name);
+ if (IsHotPatched)
+ FuncAttrs.addAttribute("marked_for_windows_hot_patching");
+ }
}
// Mark functions that are replaceable by the loader.
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 16688810d0685..96fdab212beb1 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -458,6 +458,35 @@ CodeGenModule::CodeGenModule(ASTContext &C,
if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters",
CodeGenOpts.NumRegisterParameters);
+
+ // If there are any functions that are marked for Windows secure hot-patching,
+ // then build the list of functions now.
+ if (!CGO.MSSecureHotPatchFunctionsFile.empty() ||
+ !CGO.MSSecureHotPatchFunctionsList.empty()) {
+ if (!CGO.MSSecureHotPatchFunctionsFile.empty()) {
+ auto BufOrErr =
+ llvm::MemoryBuffer::getFile(CGO.MSSecureHotPatchFunctionsFile);
+ if (BufOrErr) {
+ const llvm::MemoryBuffer &FileBuffer = **BufOrErr;
+ for (llvm::line_iterator I(FileBuffer.getMemBufferRef(), true), E;
+ I != E; ++I)
+ this->MSHotPatchFunctions.push_back(std::string{*I});
+ } else {
+ auto &DE = Context.getDiagnostics();
+ unsigned DiagID =
+ DE.getCustomDiagID(DiagnosticsEngine::Error,
+ "failed to open hotpatch functions file "
+ "(-fms-hotpatch-functions-file): %0 : %1");
+ DE.Report(DiagID) << CGO.MSSecureHotPatchFunctionsFile
+ << BufOrErr.getError().message();
+ }
+ }
+
+ for (const auto &FuncName : CGO.MSSecureHotPatchFunctionsList)
+ this->MSHotPatchFunctions.push_back(FuncName);
+
+ llvm::sort(this->MSHotPatchFunctions);
+ }
}
CodeGenModule::~CodeGenModule() {}
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 1b67d4354efc0..cb013feb769fc 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -678,6 +678,11 @@ class CodeGenModule : public CodeGenTypeCache {
AtomicOptions AtomicOpts;
+ // A set of functions which should be hot-patched; see
+ // -fms-hotpatch-functions-file (and -list). This will nearly always be empty.
+ // The list is sorted for binary-searching.
+ std::vector<std::string> MSHotPatchFunctions;
+
public:
CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &headersearchopts,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 87d04a42fcd70..25c65ab52fbaf 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6803,6 +6803,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch);
+ if (Args.hasArg(options::OPT_fms_secure_hotpatch_functions_file))
+ Args.AddLastArg(CmdArgs, options::OPT_fms_secure_hotpatch_functions_file);
+
+ for (const auto &A :
+ Args.getAllArgValues(options::OPT_fms_secure_hotpatch_functions_list))
+ CmdArgs.push_back(
+ Args.MakeArgString("-fms-secure-hotpatch-functions-list=" + Twine(A)));
+
if (TC.SupportsProfiling()) {
Args.AddLastArg(CmdArgs, options::OPT_pg);
diff --git a/clang/test/CodeGen/X86/ms-secure-hotpatch-bad-file.c b/clang/test/CodeGen/X86/ms-secure-hotpatch-bad-file.c
new file mode 100644
index 0000000000000..839dd44f7ff61
--- /dev/null
+++ b/clang/test/CodeGen/X86/ms-secure-hotpatch-bad-file.c
@@ -0,0 +1,18 @@
+// REQUIRES: x86-registered-target
+
+// This verifies that we correctly handle a -fms-secure-hotpatch-functions-file argument that points
+// to a missing file.
+//
+// RUN: not %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-secure-hotpatch-functions-file=%S/this-file-is-intentionally-missing-do-not-create-it.txt /Fo%t.obj %s 2>&1 | FileCheck %s
+// CHECK: failed to open hotpatch functions file
+
+void this_might_have_side_effects();
+
+int __declspec(noinline) this_gets_hotpatched() {
+ this_might_have_side_effects();
+ return 42;
+}
+
+int __declspec(noinline) this_does_not_get_hotpatched() {
+ return this_gets_hotpatched() + 100;
+}
diff --git a/clang/test/CodeGen/X86/ms-secure-hotpatch-cpp.cpp b/clang/test/CodeGen/X86/ms-secure-hotpatch-cpp.cpp
new file mode 100644
index 0000000000000..3dc75c95d76f7
--- /dev/null
+++ b/clang/test/CodeGen/X86/ms-secure-hotpatch-cpp.cpp
@@ -0,0 +1,24 @@
+// REQUIRES: x86-registered-target
+
+// This verifies that hotpatch function attributes are correctly propagated when compiling directly to OBJ,
+// and that name mangling works as expected.
+//
+// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-secure-hotpatch-functions-list=?this_gets_hotpatched@@YAHXZ /Fo%t.obj %s
+// RUN: llvm-readobj --codeview %t.obj | FileCheck %s
+
+void this_might_have_side_effects();
+
+int __declspec(noinline) this_gets_hotpatched() {
+ this_might_have_side_effects();
+ return 42;
+}
+
+// CHECK: Kind: S_HOTPATCHFUNC (0x1169)
+// CHECK-NEXT: Function: this_gets_hotpatched
+// CHECK-NEXT: Name: ?this_gets_hotpatched@@YAHXZ
+
+extern "C" int __declspec(noinline) this_does_not_get_hotpatched() {
+ return this_gets_hotpatched() + 100;
+}
+
+// CHECK-NOT: S_HOTPATCHFUNC
diff --git a/clang/test/CodeGen/X86/ms-secure-hotpatch-eh.cpp b/clang/test/CodeGen/X86/ms-secure-hotpatch-eh.cpp
new file mode 100644
index 0000000000000..69704626c8cb6
--- /dev/null
+++ b/clang/test/CodeGen/X86/ms-secure-hotpatch-eh.cpp
@@ -0,0 +1,26 @@
+// REQUIRES: x86-registered-target
+
+// Global constant data such as exception handler tables should not be redirected by Windows Secure Hot-Patching
+//
+// RUN: %clang_cl -c --target=x86_64-windows-msvc /EHsc -O2 -fms-secure-hotpatch-functions-list=this_gets_hotpatched /Fo%t.obj /clang:-S /clang:-o- %s 2>& 1 | FileCheck %s
+
+class Foo {
+public:
+ int x;
+};
+
+void this_might_throw();
+
+extern "C" int this_gets_hotpatched(int k) {
+ int ret;
+ try {
+ this_might_throw();
+ ret = 1;
+ } catch (Foo& f) {
+ ret = 2;
+ }
+ return ret;
+}
+
+// We expect that RTTI data is not redirected.
+// CHECK-NOT: "__ref_??_R0?AVFoo@@@8"
diff --git a/clang/test/CodeGen/X86/ms-secure-hotpatch-globals.c b/clang/test/CodeGen/X86/ms-secure-hotpatch-globals.c
new file mode 100644
index 0000000000000..d76d2aa6d8acc
--- /dev/null
+++ b/clang/test/CodeGen/X86/ms-secure-hotpatch-globals.c
@@ -0,0 +1,135 @@
+// REQUIRES: x86-registered-target
+
+// This verifies that global variable redirection works correctly when using hotpatching.
+//
+// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 \
+// RUN: -fms-secure-hotpatch-functions-list=hp1,hp2,hp3,hp4,hp5_phi_ptr_mixed,hp_phi_ptr_both,hp_const_ptr_sub \
+// RUN: /clang:-S /clang:-o- %s | FileCheck %s
+
+#ifdef __clang__
+#define NO_TAIL __attribute__((disable_tail_calls))
+#else
+#define NO_TAIL
+#endif
+
+extern int g_data[10];
+
+struct SomeData {
+ int x;
+ int y;
+};
+
+const struct SomeData g_this_is_const = { 100, 200 };
+
+struct HasPointers {
+ int* ptr;
+ int x;
+};
+
+extern struct HasPointers g_has_pointers;
+
+void take_data(const void* p);
+
+void do_side_effects();
+void do_other_side_effects();
+
+void hp1() NO_TAIL {
+ take_data(&g_data[5]);
+}
+
+// CHECK: hp1:
+// CHECK: mov rcx, qword ptr [rip + __ref_g_data]
+// CHECK: add rcx, 20
+// CHECK: call take_data
+// CHECK: .seh_endproc
+
+void hp2() NO_TAIL {
+ // We do not expect string literals to be redirected.
+ take_data("hello, world!");
+}
+
+// CHECK: hp2:
+// CHECK: lea rcx, [rip + "??_C at _0O@KJBLMJCB at hello?0?5world?$CB?$AA@"]
+// CHECK: call take_data
+// CHECK: .seh_endproc
+
+void hp3() NO_TAIL {
+ // We do not expect g_this_is_const to be redirected because it is const
+ // and contains no pointers.
+ take_data(&g_this_is_const);
+}
+
+// CHECK: hp3:
+// CHECK: lea rcx, [rip + g_this_is_const]
+// CHECK: call take_data
+// CHECK-NOT: __ref_g_this_is_const
+// CHECK: .seh_endproc
+
+void hp4() NO_TAIL {
+ take_data(&g_has_pointers);
+ // We expect &g_has_pointers to be redirected.
+}
+
+// CHECK: hp4:
+// CHECK: mov rcx, qword ptr [rip + __ref_g_has_pointers]
+// CHECK: call take_data
+// CHECK: .seh_endproc
+
+// This case checks that global variable redirection interacts correctly with PHI nodes.
+// The IR for this generates a "phi ptr g_has_pointers, g_this_is_const" node.
+// We expect g_has_pointers to be redirected, but not g_this_is_const.
+void hp5_phi_ptr_mixed(int x) NO_TAIL {
+ const void* y;
+ if (x) {
+ y = &g_has_pointers;
+ do_side_effects();
+ } else {
+ y = &g_this_is_const;
+ do_other_side_effects();
+ }
+ take_data(y);
+}
+
+// CHECK: hp5_phi_ptr_mixed
+// CHECK: .seh_endprologue
+// CHECK: test ecx, ecx
+// CHECK: mov rsi, qword ptr [rip + __ref_g_has_pointers]
+// CHECK: call do_side_effects
+// CHECK: jmp
+// CHECK: call do_other_side_effects
+// CHECK: lea rsi, [rip + g_this_is_const]
+// CHECK: mov rcx, rsi
+// CHECK: call take_data
+// CHECK: .seh_endproc
+
+// This case tests that global variable redirection interacts correctly with PHI nodes,
+// where two (all) operands of a given PHI node are globabl variables that redirect.
+void hp_phi_ptr_both(int x) NO_TAIL {
+ const void* y;
+ if (x) {
+ y = &g_has_pointers;
+ do_side_effects();
+ } else {
+ y = &g_data[5];
+ do_other_side_effects();
+ }
+ take_data(y);
+}
+
+// CHECK: hp_phi_ptr_both:
+// CHECK: .seh_endprologue
+// CHECK: test ecx, ecx
+// CHECK: mov rsi, qword ptr [rip + __ref_g_has_pointers]
+// CHECK: mov rsi, qword ptr [rip + __ref_g_data]
+// CHECK: take_data
+// CHECK: .seh_endproc
+
+// Test a constant expression which references global variable addresses.
+size_t hp_const_ptr_sub() NO_TAIL {
+ return (unsigned char*)&g_has_pointers - (unsigned char*)&g_data;
+}
+
+// CHECK: hp_const_ptr_sub:
+// CHECK: mov rax, qword ptr [rip + __ref_g_has_pointers]
+// CHECK: sub rax, qword ptr [rip + __ref_g_data]
+// CHECK: ret
diff --git a/clang/test/CodeGen/X86/ms-secure-hotpatch-lto.c b/clang/test/CodeGen/X86/ms-secure-hotpatch-lto.c
new file mode 100644
index 0000000000000..6adb0b1818e31
--- /dev/null
+++ b/clang/test/CodeGen/X86/ms-secure-hotpatch-lto.c
@@ -0,0 +1,26 @@
+// REQUIRES: x86-registered-target
+
+// This verifies that hotpatch function attributes are correctly propagated through LLVM IR when compiling with LTO.
+//
+// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-secure-hotpatch-functions-list=this_gets_hotpatched -flto /Fo%t.bc %s
+// RUN: llvm-dis %t.bc -o - | FileCheck %s
+//
+// CHECK-LABEL: define dso_local noundef i32 @this_gets_hotpatched()
+// CHECK-SAME: #0
+//
+// CHECK-LABEL: define dso_local noundef i32 @this_does_not_get_hotpatched()
+// CHECK-SAME: #1
+
+// CHECK: attributes #0
+// CHECK-SAME: "marked_for_windows_hot_patching"
+
+// CHECK: attributes #1
+// CHECK-NOT: "marked_for_windows_hot_patching"
+
+int __declspec(noinline) this_gets_hotpatched() {
+ return 42;
+}
+
+int __declspec(noinline) this_does_not_get_hotpatched() {
+ return this_gets_hotpatched() + 100;
+}
diff --git a/clang/test/CodeGen/X86/ms-secure-hotpatch.c b/clang/test/CodeGen/X86/ms-secure-hotpatch.c
new file mode 100644
index 0000000000000..b829e5acc5c83
--- /dev/null
+++ b/clang/test/CodeGen/X86/ms-secure-hotpatch.c
@@ -0,0 +1,23 @@
+// REQUIRES: x86-registered-target
+
+// This verifies that hotpatch function attributes are correctly propagated when compiling directly to OBJ.
+//
+// RUN: echo this_gets_hotpatched > %t.patch-functions.txt
+// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-secure-hotpatch-functions-file=%t.patch-functions.txt /Fo%t.obj %s
+// RUN: llvm-readobj --codeview %t.obj | FileCheck %s
+
+void this_might_have_side_effects();
+
+int __declspec(noinline) this_gets_hotpatched() {
+ this_might_have_side_effects();
+ return 42;
+}
+
+// CHECK: Kind: S_HOTPATCHFUNC (0x1169)
+// CHECK-NEXT: Function: this_gets_hotpatched
+
+int __declspec(noinline) this_does_not_get_hotpatched() {
+ return this_gets_hotpatched() + 100;
+}
+
+// CHECK-NOT: S_HOTPATCHFUNC
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index 990452fa11fec..18df5d657064a 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -618,6 +618,9 @@ LLVM_ABI FunctionPass *createSelectOptimizePass();
LLVM_ABI FunctionPass *createCallBrPass();
+/// Creates Windows Secure Hot Patch pass. \see WindowsSecureHotPatching.cpp
+ModulePass *createWindowsSecureHotPatchingPass();
+
/// Lowers KCFI operand bundles for indirect calls.
LLVM_ABI FunctionPass *createKCFIPass();
} // namespace llvm
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def
index 9d85acc49fa02..b38bdb482df43 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def
@@ -256,6 +256,8 @@ SYMBOL_RECORD_ALIAS(S_GTHREAD32 , 0x1113, GlobalTLS, ThreadLocalDataSym)
SYMBOL_RECORD(S_UNAMESPACE , 0x1124, UsingNamespaceSym)
SYMBOL_RECORD(S_ANNOTATION , 0x1019, AnnotationSym)
+SYMBOL_RECORD(S_HOTPATCHFUNC , 0x1169, HotPatchFuncSym)
+
#undef CV_SYMBOL
#undef SYMBOL_RECORD
#undef SYMBOL_RECORD_ALIAS
diff --git a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
index 5b4f0d31e6427..f5f6fe69430cc 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
@@ -177,6 +177,21 @@ class CallerSym : public SymbolRecord {
uint32_t RecordOffset = 0;
};
+class HotPatchFuncSym : public SymbolRecord {
+public:
+ explicit HotPatchFuncSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
+ HotPatchFuncSym(uint32_t RecordOffset)
+ : SymbolRecord(SymbolRecordKind::HotPatchFuncSym),
+ RecordOffset(RecordOffset) {}
+
+ // This is an ItemID in the IPI stream, which points to an LF_FUNC_ID or
+ // LF_MFUNC_ID record.
+ TypeIndex Function;
+ StringRef Name;
+
+ uint32_t RecordOffset = 0;
+};
+
struct DecodedAnnotation {
StringRef Name;
ArrayRef<uint8_t> Bytes;
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index d488c5f419b82..0bcd15eeed879 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -389,6 +389,16 @@ def CoroDestroyOnlyWhenComplete : EnumAttr<"coro_only_destroy_when_complete", In
/// pipeline to perform elide on the call or invoke instruction.
def CoroElideSafe : EnumAttr<"coro_elide_safe", IntersectPreserve, [FnAttr]>;
+/// Function is marked for Windows Hot Patching
+def MarkedForWindowsSecureHotPatching
+ : StrBoolAttr<"marked_for_windows_hot_patching">;
+
+/// Global variable should not be accessed through a "__ref_" global variable in
+/// a hot patching function This attribute is applied to the global variable
+/// decl, not the hotpatched function.
+def AllowDirectAccessInHotPatchFunction
+ : StrBoolAttr<"allow_direct_access_in_hot_patch_function">;
+
/// Target-independent string attributes.
def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">;
def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">;
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 1b5b1d5888824..1c4ed3843b390 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -336,6 +336,7 @@ LLVM_ABI void initializeVerifierLegacyPassPass(PassRegistry &);
LLVM_ABI void initializeVirtRegMapWrapperLegacyPass(PassRegistry &);
LLVM_ABI void initializeVirtRegRewriterLegacyPass(PassRegistry &);
LLVM_ABI void initializeWasmEHPreparePass(PassRegistry &);
+LLVM_ABI void initializeWindowsSecureHotPatchingPass(PassRegistry &);
LLVM_ABI void initializeWinEHPreparePass(PassRegistry &);
LLVM_ABI void initializeWriteBitcodePassPass(PassRegistry &);
LLVM_ABI void initializeXRayInstrumentationLegacyPass(PassRegistry &);
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index ea57a8fa1f793..5e1b313b4d2fa 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...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/145565
More information about the cfe-commits
mailing list