================
@@ -0,0 +1,283 @@
+//===------ WindowsHotPatch.cpp - Support for Windows hotpatching 
---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides support for the Windows "Secure Hot-Patching" feature.
+//
+// Windows contains technology, called "Secure Hot-Patching" (SHP), for 
securely
+// applying hot-patches to a running system. Hot-patches may be applied to the
+// kernel, kernel-mode components, device drivers, user-mode system services,
+// etc.
+//
+// SHP relies on integration between many tools, including compiler, linker,
+// hot-patch generation tools, and the Windows kernel. This file implements 
that
+// part of the workflow needed in compilers / code generators.
+//
+// SHP is not intended for productivity scenarios such as Edit-and-Continue or
+// interactive development. SHP is intended to minimize downtime during
+// installation of Windows OS patches.
+//
+// In order to work with SHP, LLVM must do all of the following:
+//
+// * On some architectures (X86, AMD64), the function prolog must begin with
+//   hot-patchable instructions. This is handled by the MSVC `/hotpatch` option
+//   and the equivalent `-fms-hotpatch` function. This is necessary because we
+//   generally cannot anticipate which functions will need to be patched in the
+//   future. This option ensures that a function can be hot-patched in the
+//   future, but does not actually generate any hot-patch for it.
+//
+// * For a selected set of functions that are being hot-patched (which are
+//   identified using command-line options), LLVM must generate the
+//   `S_HOTPATCHFUNC` CodeView record (symbol). This record indicates that a
+//   function was compiled with hot-patching enabled.
+//
+//   This implementation uses the `MarkedForWindowsHotPatching` attribute to
+//   annotate those functions that were marked for hot-patching by command-line
+//   parameters. The attribute may be specified by a language front-end by
+//   setting an attribute when a function is created in LLVM IR, or it may be
+//   set by passing LLVM arguments.
+//
+// * For those functions that are hot-patched, LLVM must rewrite references to
+//   global variables so that they are indirected through a `__ref_*` pointer
+//   variable.  For each global variable, that is accessed by a hot-patched
+//   function, e.g. `FOO`, a `__ref_FOO` global pointer variable is created and
+//   all references to the original `FOO` are rewritten as dereferences of the
+//   `__ref_FOO` pointer.
+//
+//   Some globals do not need `__ref_*` indirection. The pointer indirection
+//   behavior can be disabled for these globals by marking them with the
+//   `AllowDirectAccessInHotPatchFunction`.
+//
+// References
+//
+// * "Hotpatching on Windows":
+//   
https://techcommunity.microsoft.com/blog/windowsosplatform/hotpatching-on-windows/2959541
+//
+// * "Hotpatch for Windows client now available":
+//   
https://techcommunity.microsoft.com/blog/windows-itpro-blog/hotpatch-for-windows-client-now-available/4399808
+//
+// * "Get hotpatching for Windows Server":
+//   
https://www.microsoft.com/en-us/windows-server/blog/2025/04/24/tired-of-all-the-restarts-get-hotpatching-for-windows-server/
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "windows-secure-hot-patch"
+
+// A file containing list of mangled function names to mark for hot patching.
+static cl::opt<std::string> LLVMMSSecureHotPatchFunctionsFile(
+    "ms-secure-hotpatch-functions-file", cl::value_desc("filename"),
+    cl::desc("A file containing list of mangled function names to mark for "
+             "Windows Secure Hot-Patching"));
+
+// A list of mangled function names to mark for hot patching.
+static cl::list<std::string> LLVMMSSecureHotPatchFunctionsList(
+    "ms-secure-hotpatch-functions-list", cl::value_desc("list"),
+    cl::desc("A list of mangled function names to mark for Windows Secure "
+             "Hot-Patching"),
+    cl::CommaSeparated);
+
+namespace {
+
+class WindowsSecureHotPatching : public ModulePass {
+  struct GlobalVariableUse {
+    GlobalVariable *GV;
+    Instruction *User;
+    unsigned Op;
+  };
+
+public:
+  static char ID;
+
+  WindowsSecureHotPatching() : ModulePass(ID) {
+    initializeWindowsSecureHotPatchingPass(*PassRegistry::getPassRegistry());
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+  }
+
+  bool runOnModule(Module &M) override;
+
+private:
+  bool
+  runOnFunction(Function &F,
+                SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping);
+};
+
+} // end anonymous namespace
+
+char WindowsSecureHotPatching::ID = 0;
+
+INITIALIZE_PASS(WindowsSecureHotPatching, "windows-secure-hot-patch",
+                "Mark functions for Windows hot patch support", false, false)
+ModulePass *llvm::createWindowsSecureHotPatchingPass() {
+  return new WindowsSecureHotPatching();
+}
+
+// Find functions marked with Attribute::MarkedForWindowsHotPatching and modify
+// their code (if necessary) to account for accesses to global variables.
+bool WindowsSecureHotPatching::runOnModule(Module &M) {
+  // The front end may have already marked functions for hot-patching. However,
+  // we also allow marking functions by passing -ms-hotpatch-functions-file or
+  // -ms-hotpatch-functions-list directly to LLVM. This allows hot-patching to
+  // work with languages that have not yet updated their front-ends.
+  if (!LLVMMSSecureHotPatchFunctionsFile.empty() ||
+      !LLVMMSSecureHotPatchFunctionsList.empty()) {
+    std::vector<std::string> HotPatchFunctionsList;
+
+    if (!LLVMMSSecureHotPatchFunctionsFile.empty()) {
+      auto BufOrErr =
+          llvm::MemoryBuffer::getFile(LLVMMSSecureHotPatchFunctionsFile);
+      if (BufOrErr) {
+        const llvm::MemoryBuffer &FileBuffer = **BufOrErr;
+        for (llvm::line_iterator I(FileBuffer.getMemBufferRef(), true), E;
+             I != E; ++I)
+          HotPatchFunctionsList.push_back(std::string{*I});
+      } else {
+        M.getContext().diagnose(llvm::DiagnosticInfoGeneric{
+            llvm::Twine("failed to open hotpatch functions file "
+                        "(--ms-hotpatch-functions-file): ") +
+            LLVMMSSecureHotPatchFunctionsFile + llvm::Twine(" : ") +
+            BufOrErr.getError().message()});
+      }
+    }
+
+    if (!LLVMMSSecureHotPatchFunctionsList.empty())
+      for (const auto &FuncName : LLVMMSSecureHotPatchFunctionsList)
+        HotPatchFunctionsList.push_back(FuncName);
+
+    // Build a set for quick lookups. This points into HotPatchFunctionsList, 
so
+    // HotPatchFunctionsList must live longer than HotPatchFunctionsSet.
+    llvm::SmallSet<llvm::StringRef, 16> HotPatchFunctionsSet;
+    for (const auto &FuncName : HotPatchFunctionsList)
+      HotPatchFunctionsSet.insert(llvm::StringRef{FuncName});
+
+    // Iterate through all of the functions and check whether they need to be
+    // marked for hotpatching using the list provided directly to LLVM.
+    for (auto &F : M.functions()) {
+      // Ignore declarations that are not definitions.
+      if (F.isDeclarationForLinker())
+        continue;
+
+      if (HotPatchFunctionsSet.contains(F.getName()))
+        F.addFnAttr(Attribute::MarkedForWindowsHotPatching);
----------------
aganea wrote:

> > What is the plan there for handling the function prologue [...] Shouldn't 
> > we enable `-fms-hotpatch` de facto for the TU when using the 
> > `-fms-secure-hotpatch` ... flags?
> 
> It's true that `-fms-secure-*` requires `-fms-hotpatch`. We could: 1) do 
> nothing in the compiler (and detect it downstream during patch generation); 
> 2) report a warning when `-fms-secure-*` is used but `-fms-hotpatch` is not; 
> 3) implicitly turn on `-fms-hotpatch` when `-fms-secure-*` is used.
> 
> I don't have a strong preference, here. In Windows, we compile everything 
> with `/hotpatch`, because the codegen costs are minor and because this 
> maximizes the set of code that we can hot-patch down the road. I'm willing to 
> go with any of the above options -- just let me know which one the LLVM 
> project would prefer.

Ok, fair enough, since you already have that enabled in your build scripts that 
use the `-fms-secure-hotpatch` flags, and since these flags are for a very 
limited audience, we could leave this as it is for now.

> the main requirement is to support the `/functionpadmin` argument.

This is [already supported](https://reviews.llvm.org/D49366) in LLD.



https://github.com/llvm/llvm-project/pull/138972
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to