https://github.com/sivadeilra updated https://github.com/llvm/llvm-project/pull/138972
>From 18bcf7a9da1b0698b6e7b9808edf4f12d0db16aa Mon Sep 17 00:00:00 2001 From: Arlie Davis <arda...@microsoft.com> Date: Thu, 3 Apr 2025 16:10:50 -0700 Subject: [PATCH 1/4] Windows hotpatching support Address PR feedback * Simply use F.getName() for function name. * Fix llvm/test/CodeGen/Generic/ms-hotpatch-direct-global-access.ll * Add negative testing for functions that are not supposed to be hotpatched --- clang/include/clang/Basic/CodeGenOptions.h | 7 + clang/include/clang/Driver/Options.td | 14 + clang/lib/CodeGen/CGCall.cpp | 9 + clang/lib/CodeGen/CodeGenModule.cpp | 31 +++ clang/lib/CodeGen/CodeGenModule.h | 5 + clang/lib/Driver/ToolChains/Clang.cpp | 10 + clang/test/CodeGen/ms-hotpatch-bad-file.c | 16 ++ clang/test/CodeGen/ms-hotpatch-cpp.cpp | 22 ++ clang/test/CodeGen/ms-hotpatch-functions.txt | 1 + clang/test/CodeGen/ms-hotpatch-lto.c | 18 ++ clang/test/CodeGen/ms-hotpatch.c | 20 ++ llvm/include/llvm/Bitcode/LLVMBitCodes.h | 2 + llvm/include/llvm/CodeGen/Passes.h | 3 + .../DebugInfo/CodeView/CodeViewSymbols.def | 2 + .../llvm/DebugInfo/CodeView/SymbolRecord.h | 15 ++ llvm/include/llvm/IR/Attributes.td | 11 + llvm/include/llvm/InitializePasses.h | 1 + llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 4 + llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 4 + llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 32 ++- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h | 2 + llvm/lib/CodeGen/CMakeLists.txt | 1 + llvm/lib/CodeGen/TargetPassConfig.cpp | 3 + llvm/lib/CodeGen/WindowsHotPatch.cpp | 242 ++++++++++++++++++ llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp | 7 + .../CodeView/SymbolRecordMapping.cpp | 7 + llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp | 5 + llvm/lib/Transforms/Utils/CodeExtractor.cpp | 2 + llvm/test/CodeGen/Generic/ms-hotpatch-attr.ll | 38 +++ .../CodeGen/Generic/ms-hotpatch-bad-file.ll | 16 ++ .../ms-hotpatch-direct-global-access.ll | 39 +++ .../Generic/ms-hotpatch-functions-file.ll | 38 +++ .../Generic/ms-hotpatch-functions-file.txt | 1 + .../Generic/ms-hotpatch-functions-list.ll | 38 +++ .../llvm-pdbutil/MinimalSymbolDumper.cpp | 8 + 35 files changed, 672 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGen/ms-hotpatch-bad-file.c create mode 100644 clang/test/CodeGen/ms-hotpatch-cpp.cpp create mode 100644 clang/test/CodeGen/ms-hotpatch-functions.txt create mode 100644 clang/test/CodeGen/ms-hotpatch-lto.c create mode 100644 clang/test/CodeGen/ms-hotpatch.c create mode 100644 llvm/lib/CodeGen/WindowsHotPatch.cpp create mode 100644 llvm/test/CodeGen/Generic/ms-hotpatch-attr.ll create mode 100644 llvm/test/CodeGen/Generic/ms-hotpatch-bad-file.ll create mode 100644 llvm/test/CodeGen/Generic/ms-hotpatch-direct-global-access.ll create mode 100644 llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.ll create mode 100644 llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt create mode 100644 llvm/test/CodeGen/Generic/ms-hotpatch-functions-list.ll diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 278803f7bb960..b0efc445b8450 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -501,6 +501,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-hot-patch-functions-file. + std::string MSHotPatchFunctionsFile; + + /// A list of functions which will be compiled for hotpatching. + /// See -fms-hot-patch-functions-list. + std::vector<std::string> MSHotPatchFunctionsList; 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 bd8df8f6a749a..9d1931381dee7 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3830,6 +3830,20 @@ 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">>; +def fms_hotpatch_functions_file + : Joined<["-"], "fms-hotpatch-functions-file=">, + Group<f_Group>, + Visibility<[ClangOption, CC1Option, CLOption]>, + MarshallingInfoString<CodeGenOpts<"MSHotPatchFunctionsFile">>, + HelpText<"Path to a file that contains a list of mangled symbol names of " + "functions that should be hot-patched">; +def fms_hotpatch_functions_list + : CommaJoined<["-"], "fms-hotpatch-functions-list=">, + Group<f_Group>, + Visibility<[ClangOption, CC1Option, CLOption]>, + MarshallingInfoStringVector<CodeGenOpts<"MSHotPatchFunctionsList">>, + HelpText<"List of mangled symbol names of functions that should be " + "hot-patched">; 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 aa1909443e8cd..666b00809c37e 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2639,6 +2639,15 @@ 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 = std::binary_search(MSHotPatchFunctions.begin(), + MSHotPatchFunctions.end(), Name); + if (IsHotPatched) { + FuncAttrs.addAttribute(llvm::Attribute::MarkedForWindowsHotPatching); + } + } } // Mark functions that are replaceable by the loader. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 428a4b8335524..aa11487c4dce1 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -453,6 +453,37 @@ 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 hot-patching, + // then build the list of functions now. + if (!CGO.MSHotPatchFunctionsFile.empty() || + !CGO.MSHotPatchFunctionsList.empty()) { + if (!CGO.MSHotPatchFunctionsFile.empty()) { + auto BufOrErr = llvm::MemoryBuffer::getFile(CGO.MSHotPatchFunctionsFile); + 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.MSHotPatchFunctionsFile + << BufOrErr.getError().message(); + } + } + + for (const auto &FuncName : CGO.MSHotPatchFunctionsList) { + this->MSHotPatchFunctions.push_back(FuncName); + } + + std::sort(this->MSHotPatchFunctions.begin(), + this->MSHotPatchFunctions.end()); + } } CodeGenModule::~CodeGenModule() {} diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 1db5c3bc4e4ef..45411cb95b7d2 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 a08bdba99bfe0..6a38a9ada42ec 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6946,6 +6946,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch); + if (Arg *A = Args.getLastArg(options::OPT_fms_hotpatch_functions_file)) { + Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch_functions_file); + } + + for (const auto &A : + Args.getAllArgValues(options::OPT_fms_hotpatch_functions_list)) { + CmdArgs.push_back( + Args.MakeArgString("-fms-hotpatch-functions-list=" + Twine(A))); + } + if (TC.SupportsProfiling()) { Args.AddLastArg(CmdArgs, options::OPT_pg); diff --git a/clang/test/CodeGen/ms-hotpatch-bad-file.c b/clang/test/CodeGen/ms-hotpatch-bad-file.c new file mode 100644 index 0000000000000..55304488175df --- /dev/null +++ b/clang/test/CodeGen/ms-hotpatch-bad-file.c @@ -0,0 +1,16 @@ +// This verifies that we correctly handle a -fms-hotpatch-functions-file argument that points +// to a missing file. +// +// RUN: not %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-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/ms-hotpatch-cpp.cpp b/clang/test/CodeGen/ms-hotpatch-cpp.cpp new file mode 100644 index 0000000000000..26e11f429c962 --- /dev/null +++ b/clang/test/CodeGen/ms-hotpatch-cpp.cpp @@ -0,0 +1,22 @@ +// 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-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/ms-hotpatch-functions.txt b/clang/test/CodeGen/ms-hotpatch-functions.txt new file mode 100644 index 0000000000000..2512ba3881c66 --- /dev/null +++ b/clang/test/CodeGen/ms-hotpatch-functions.txt @@ -0,0 +1 @@ +this_gets_hotpatched diff --git a/clang/test/CodeGen/ms-hotpatch-lto.c b/clang/test/CodeGen/ms-hotpatch-lto.c new file mode 100644 index 0000000000000..290f7695b02f6 --- /dev/null +++ b/clang/test/CodeGen/ms-hotpatch-lto.c @@ -0,0 +1,18 @@ +// 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-hotpatch-functions-file=%S/ms-hotpatch-functions.txt -flto /Fo%t.bc %s +// RUN: llvm-dis %t.bc -o - | FileCheck %s +// +// CHECK: ; Function Attrs: marked_for_windows_hot_patching mustprogress nofree noinline norecurse nosync nounwind sspstrong willreturn memory(none) uwtable +// CHECK-NEXT: define dso_local noundef i32 @this_gets_hotpatched() local_unnamed_addr #0 !dbg !13 { +// +// CHECK: ; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind sspstrong willreturn memory(none) uwtable +// CHECK-NEXT: define dso_local noundef i32 @this_does_not_get_hotpatched() local_unnamed_addr #1 !dbg !19 { + +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/ms-hotpatch.c b/clang/test/CodeGen/ms-hotpatch.c new file mode 100644 index 0000000000000..79da105f4cec3 --- /dev/null +++ b/clang/test/CodeGen/ms-hotpatch.c @@ -0,0 +1,20 @@ +// This verifies that hotpatch function attributes are correctly propagated when compiling directly to OBJ. +// +// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-hotpatch-functions-file=%S/ms-hotpatch-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/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index b362a88963f6c..707e51031f7dd 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -798,6 +798,8 @@ enum AttributeKindCodes { ATTR_KIND_NO_DIVERGENCE_SOURCE = 100, ATTR_KIND_SANITIZE_TYPE = 101, ATTR_KIND_CAPTURES = 102, + ATTR_KIND_ALLOW_DIRECT_ACCESS_IN_HOT_PATCH_FUNCTION = 103, + ATTR_KIND_MARKED_FOR_WINDOWS_HOT_PATCHING = 104, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index d214ab9306c2f..c4163617da5ae 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -617,6 +617,9 @@ namespace llvm { /// Lowers KCFI operand bundles for indirect calls. FunctionPass *createKCFIPass(); + + /// Creates Windows Hot Patch pass. \see WindowsHotPatch.cpp + ModulePass *createWindowsHotPatch(); } // End llvm namespace #endif 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 3cce40dcf735a..de80d37999890 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ b/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -176,6 +176,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..9baf9a53d2f4d 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -389,6 +389,17 @@ 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 MarkedForWindowsHotPatching + : EnumAttr<"marked_for_windows_hot_patching", IntersectPreserve, [FnAttr]>; + +/// 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 + : EnumAttr<"allow_direct_access_in_hot_patch_function", + IntersectPreserve, [FnAttr]>; + /// 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 5a282d17b72c8..53722dd10fac7 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -323,6 +323,7 @@ void initializeVirtRegMapWrapperLegacyPass(PassRegistry &); void initializeVirtRegRewriterLegacyPass(PassRegistry &); void initializeWasmEHPreparePass(PassRegistry &); void initializeWinEHPreparePass(PassRegistry &); +void initializeWindowsHotPatchPass(PassRegistry &); void initializeWriteBitcodePassPass(PassRegistry &); void initializeXRayInstrumentationLegacyPass(PassRegistry &); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 1e07f060d72cb..eb72655a75560 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2247,6 +2247,10 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::NoExt; case bitc::ATTR_KIND_CAPTURES: return Attribute::Captures; + case bitc::ATTR_KIND_ALLOW_DIRECT_ACCESS_IN_HOT_PATCH_FUNCTION: + return Attribute::AllowDirectAccessInHotPatchFunction; + case bitc::ATTR_KIND_MARKED_FOR_WINDOWS_HOT_PATCHING: + return Attribute::MarkedForWindowsHotPatching; } } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 1a15c5120d3fd..b3c2d974c3db1 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -937,6 +937,10 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_NO_EXT; case Attribute::Captures: return bitc::ATTR_KIND_CAPTURES; + case Attribute::AllowDirectAccessInHotPatchFunction: + return bitc::ATTR_KIND_ALLOW_DIRECT_ACCESS_IN_HOT_PATCH_FUNCTION; + case Attribute::MarkedForWindowsHotPatching: + return bitc::ATTR_KIND_MARKED_FOR_WINDOWS_HOT_PATCHING; case Attribute::EndAttrKinds: llvm_unreachable("Can not encode end-attribute kinds marker."); case Attribute::None: diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index df4e48571692c..c643bd269f3b1 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -627,8 +627,6 @@ void CodeViewDebug::beginModule(Module *M) { CurrentSourceLanguage = MapDWLangToCVLang(CU->getSourceLanguage()); - collectGlobalVariableInfo(); - // Check if we should emit type record hashes. ConstantInt *GH = mdconst::extract_or_null<ConstantInt>(M->getModuleFlag("CodeViewGHash")); @@ -639,6 +637,8 @@ void CodeViewDebug::endModule() { if (!Asm || !Asm->hasDebugInfo()) return; + collectGlobalVariableInfo(); + // The COFF .debug$S section consists of several subsections, each starting // with a 4-byte control code (e.g. 0xF1, 0xF2, etc) and then a 4-byte length // of the payload followed by the payload itself. The subsections are 4-byte @@ -653,6 +653,8 @@ void CodeViewDebug::endModule() { emitCompilerInformation(); endCVSubsection(CompilerInfo); + emitHotPatchInformation(); + emitInlineeLinesSubsection(); // Emit per-function debug information. @@ -807,6 +809,32 @@ void CodeViewDebug::emitObjName() { endSymbolRecord(CompilerEnd); } +void CodeViewDebug::emitHotPatchInformation() { + MCSymbol *hotPatchInfo = nullptr; + for (const auto &F : MMI->getModule()->functions()) { + if (!F.isDeclarationForLinker() && + F.hasFnAttribute(Attribute::MarkedForWindowsHotPatching)) { + 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"); + llvm::StringRef Name = SP->getLinkageName(); + if (Name.empty()) { + Name = F.getName(); + } + emitNullTerminatedSymbolName(OS, Name); + endSymbolRecord(HotPatchEnd); + } + } + if (hotPatchInfo != nullptr) { + endCVSubsection(hotPatchInfo); + } +} + namespace { struct Version { int Part[4]; diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 7a138a0332b6d..3cc47b79b5b32 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -333,6 +333,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void emitCompilerInformation(); + void emitHotPatchInformation(); + void emitBuildInfo(); void emitInlineeLinesSubsection(); diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 5dd6413431255..f18f085b0450b 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -250,6 +250,7 @@ add_llvm_component_library(LLVMCodeGen VirtRegMap.cpp WasmEHPrepare.cpp WindowScheduler.cpp + WindowsHotPatch.cpp WinEHPrepare.cpp XRayInstrumentation.cpp ${GeneratedMLSources} diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 0095ce3d96277..1d93efc21fbab 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -893,6 +893,9 @@ void TargetPassConfig::addIRPasses() { if (EnableGlobalMergeFunc) addPass(createGlobalMergeFuncPass()); + + if (TM->getTargetTriple().isOSBinFormatCOFF()) + addPass(createWindowsHotPatch()); } /// Turn exception handling constructs into something the code generators can diff --git a/llvm/lib/CodeGen/WindowsHotPatch.cpp b/llvm/lib/CodeGen/WindowsHotPatch.cpp new file mode 100644 index 0000000000000..08995439e51e9 --- /dev/null +++ b/llvm/lib/CodeGen/WindowsHotPatch.cpp @@ -0,0 +1,242 @@ +//===------ 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 +// +//===----------------------------------------------------------------------===// +// +// Marks functions with the `marked_for_windows_hot_patching` attribute. +// +//===----------------------------------------------------------------------===// + +#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-hot-patch" + +// A file containing list of mangled function names to mark for hot patching. +static cl::opt<std::string> LLVMMSHotPatchFunctionsFile( + "ms-hotpatch-functions-file", cl::value_desc("filename"), + cl::desc("A file containing list of mangled function names to mark for hot " + "patching")); + +// A list of mangled function names to mark for hot patching. +static cl::list<std::string> LLVMMSHotPatchFunctionsList( + "ms-hotpatch-functions-list", cl::value_desc("list"), + cl::desc("A list of mangled function names to mark for hot patching"), + cl::CommaSeparated); + +namespace { + +class WindowsHotPatch : public ModulePass { + struct GlobalVariableUse { + GlobalVariable *GV; + Instruction *User; + unsigned Op; + }; + +public: + static char ID; + + WindowsHotPatch() : ModulePass(ID) { + initializeWindowsHotPatchPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + } + + bool runOnModule(Module &M) override; + +private: + bool + runOnFunction(Function &F, + SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping); + void replaceGlobalVariableUses( + Function &F, SmallVectorImpl<GlobalVariableUse> &GVUses, + SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping, + DIBuilder &DebugInfo); +}; + +} // end anonymous namespace + +char WindowsHotPatch::ID = 0; + +INITIALIZE_PASS(WindowsHotPatch, "windows-hot-patch", + "Mark functions for Windows hot patch support", false, false) +ModulePass *llvm::createWindowsHotPatch() { return new WindowsHotPatch(); } + +// Find functions marked with Attribute::MarkedForWindowsHotPatching and modify +// their code (if necessary) to account for accesses to global variables. +bool WindowsHotPatch::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 (!LLVMMSHotPatchFunctionsFile.empty() || + !LLVMMSHotPatchFunctionsList.empty()) { + std::vector<std::string> HotPatchFunctionsList; + + if (!LLVMMSHotPatchFunctionsFile.empty()) { + auto BufOrErr = llvm::MemoryBuffer::getFile(LLVMMSHotPatchFunctionsFile); + 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): ") + + LLVMMSHotPatchFunctionsFile + llvm::Twine(" : ") + + BufOrErr.getError().message()}); + } + } + + if (!LLVMMSHotPatchFunctionsList.empty()) { + for (const auto &FuncName : LLVMMSHotPatchFunctionsList) { + 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); + } + } + } + + SmallDenseMap<GlobalVariable *, GlobalVariable *> RefMapping; + bool MadeChanges = false; + for (auto &F : M.functions()) { + if (F.hasFnAttribute(Attribute::MarkedForWindowsHotPatching)) { + if (runOnFunction(F, RefMapping)) { + MadeChanges = true; + } + } + } + return MadeChanges; +} + +// Processes a function that is marked for hot-patching. +// +// If a function is marked for hot-patching, we generate an S_HOTPATCHFUNC +// CodeView debug symbol. Tools that generate hot-patches look for +// S_HOTPATCHFUNC in final PDBs so that they can find functions that have been +// hot-patched and so that they can distinguish hot-patched functions from +// non-hot-patched functions. +// +// Also, in functions that are hot-patched, we must indirect all access to +// (mutable) global variables through a pointer. This pointer may point into the +// unpatched ("base") binary or may point into the patched image, depending on +// whether a hot-patch was loaded as a patch or as a base image. These +// indirections go through a new global variable, `named __ref_<Foo>` where +// `<Foo>` is the original symbol name of the global variable. +// +// This function handles rewriting accesses to global variables, but the +// generation of S_HOTPATCHFUNC occurs in +// CodeViewDebug::emitHotPatchInformation(). +// +// Returns true if any changes were made to the function. +bool WindowsHotPatch::runOnFunction( + Function &F, + SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping) { + SmallVector<GlobalVariableUse, 32> GVUses; + for (auto &I : instructions(F)) { + for (auto &U : I.operands()) { + // Discover all uses of GlobalVariable, these will need to be replaced. + GlobalVariable *GV = dyn_cast<GlobalVariable>(&U); + if ((GV != nullptr) && + !GV->hasAttribute(Attribute::AllowDirectAccessInHotPatchFunction)) { + unsigned OpNo = &U - I.op_begin(); + GVUses.push_back({GV, &I, OpNo}); + } + } + } + + if (!GVUses.empty()) { + const llvm::DISubprogram *Subprogram = F.getSubprogram(); + DIBuilder DebugInfo{*F.getParent(), true, + Subprogram != nullptr ? Subprogram->getUnit() + : nullptr}; + replaceGlobalVariableUses(F, GVUses, RefMapping, DebugInfo); + if (Subprogram != nullptr) { + DebugInfo.finalize(); + } + return true; + } else { + return false; + } +} + +void WindowsHotPatch::replaceGlobalVariableUses( + Function &F, SmallVectorImpl<GlobalVariableUse> &GVUses, + SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping, + DIBuilder &DebugInfo) { + for (auto &GVUse : GVUses) { + IRBuilder<> Builder(GVUse.User); + + // Get or create a new global variable that points to the old one and who's + // name begins with `__ref_`. + GlobalVariable *&ReplaceWithRefGV = + RefMapping.try_emplace(GVUse.GV).first->second; + if (ReplaceWithRefGV == nullptr) { + Constant *AddrOfOldGV = ConstantExpr::getGetElementPtr( + Builder.getPtrTy(), GVUse.GV, ArrayRef<Value *>{}); + ReplaceWithRefGV = + new GlobalVariable(*F.getParent(), Builder.getPtrTy(), true, + GlobalValue::InternalLinkage, AddrOfOldGV, + Twine("__ref_").concat(GVUse.GV->getName()), + nullptr, GlobalVariable::NotThreadLocal); + + // Create debug info for the replacement global variable. + DISubprogram *SP = F.getSubprogram(); + DataLayout Layout = F.getParent()->getDataLayout(); + DIType *DebugType = DebugInfo.createPointerType( + nullptr, Layout.getTypeSizeInBits(GVUse.GV->getValueType())); + DIGlobalVariableExpression *GVE = + DebugInfo.createGlobalVariableExpression( + SP != nullptr ? SP->getUnit() : nullptr, + ReplaceWithRefGV->getName(), StringRef{}, + SP != nullptr ? SP->getFile() : nullptr, /*LineNo*/ 0, DebugType, + /*IsLocalToUnit*/ false); + ReplaceWithRefGV->addDebugInfo(GVE); + } + + // Now replace the use of that global variable with the new one (via a load + // since it is a pointer to the old global variable). + LoadInst *LoadedRefGV = + Builder.CreateLoad(ReplaceWithRefGV->getValueType(), ReplaceWithRefGV); + GVUse.User->setOperand(GVUse.Op, LoadedRefGV); + } +} diff --git a/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp index f56739db7c75f..9cb3bca8d6e5e 100644 --- a/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -672,6 +672,13 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, return Error::success(); } +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + HotPatchFuncSym &HotPatchFunc) { + printTypeIndex("Function", HotPatchFunc.Function); + W.printString("Name", HotPatchFunc.Name); + return Error::success(); +} + Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) { W.printNumber("Length", CVR.length()); return Error::success(); diff --git a/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp index b5e366b965a95..525343b90a3ae 100644 --- a/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp +++ b/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp @@ -496,6 +496,13 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, return Error::success(); } +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + HotPatchFuncSym &HotPatchFunc) { + error(IO.mapInteger(HotPatchFunc.Function)); + error(IO.mapStringZ(HotPatchFunc.Name)); + return Error::success(); +} + RegisterId codeview::decodeFramePtrReg(EncodedFramePtrReg EncodedReg, CPUType CPU) { assert(unsigned(EncodedReg) < 4); diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp index b15919f68725f..3056251809308 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp @@ -605,6 +605,11 @@ template <> void SymbolRecordImpl<JumpTableSym>::map(IO &IO) { IO.mapRequired("EntriesCount", Symbol.EntriesCount); } +template <> void SymbolRecordImpl<HotPatchFuncSym>::map(IO &IO) { + IO.mapRequired("Function", Symbol.Function); + IO.mapRequired("Name", Symbol.Name); +} + } // end namespace detail } // end namespace CodeViewYAML } // end namespace llvm diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index c4894c90c127f..37888210377f2 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -938,6 +938,8 @@ Function *CodeExtractor::constructFunctionDeclaration( case Attribute::CoroDestroyOnlyWhenComplete: case Attribute::CoroElideSafe: case Attribute::NoDivergenceSource: + case Attribute::MarkedForWindowsHotPatching: + case Attribute::AllowDirectAccessInHotPatchFunction: continue; // Those attributes should be safe to propagate to the extracted function. case Attribute::AlwaysInline: diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-attr.ll b/llvm/test/CodeGen/Generic/ms-hotpatch-attr.ll new file mode 100644 index 0000000000000..08fbc073e0716 --- /dev/null +++ b/llvm/test/CodeGen/Generic/ms-hotpatch-attr.ll @@ -0,0 +1,38 @@ +; This tests directly annotating a function with marked_for_windows_hot_patching. +; +; RUN: llc -mtriple=x86_64-windows < %s | FileCheck %s + +source_filename = ".\\ms-hotpatch-attr.ll" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.36.32537" + +@some_global_var = external global i32 + +define noundef i32 @this_gets_hotpatched() #0 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #0 = { marked_for_windows_hot_patching mustprogress noinline nounwind optnone uwtable } + +; CHECK: this_gets_hotpatched: # @this_gets_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movq __ref_some_global_var(%rip), %rax +; CHECK-NEXT: movl (%rax), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq + +define noundef i32 @this_does_not_get_hotpatched() #1 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #1 = { mustprogress noinline nounwind optnone uwtable } + +; CHECK: this_does_not_get_hotpatched: # @this_does_not_get_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movl some_global_var(%rip), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-bad-file.ll b/llvm/test/CodeGen/Generic/ms-hotpatch-bad-file.ll new file mode 100644 index 0000000000000..59a83c9040a41 --- /dev/null +++ b/llvm/test/CodeGen/Generic/ms-hotpatch-bad-file.ll @@ -0,0 +1,16 @@ +; RUN: not llc -mtriple=x86_64-windows --ms-hotpatch-functions-file=%S/this-file-is-intentionally-missing-do-not-create-it.txt < %s 2>&1 | FileCheck %s +; CHECK: failed to open hotpatch functions file + +source_filename = ".\\ms-hotpatch.ll" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.36.32537" + +@some_global_var = external global i32 + +define noundef i32 @this_gets_hotpatched() #0 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #0 = { marked_for_windows_hot_patching mustprogress noinline nounwind optnone uwtable } diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-direct-global-access.ll b/llvm/test/CodeGen/Generic/ms-hotpatch-direct-global-access.ll new file mode 100644 index 0000000000000..eb8754ee6c3f7 --- /dev/null +++ b/llvm/test/CodeGen/Generic/ms-hotpatch-direct-global-access.ll @@ -0,0 +1,39 @@ +; This tests hotpatching functions that bypass double-indirection for global variables. +; +; RUN: llc -mtriple=x86_64-windows < %s | FileCheck %s + +source_filename = ".\\ms-hotpatch-direct-global-access.ll" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.36.32537" + +@some_global_var = external global i32 #2 + +define noundef i32 @this_gets_hotpatched() #0 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #0 = { marked_for_windows_hot_patching mustprogress noinline nounwind optnone uwtable } + +; CHECK: this_gets_hotpatched: # @this_gets_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movl some_global_var(%rip), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq + +define noundef i32 @this_does_not_get_hotpatched() #1 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #1 = { mustprogress noinline nounwind optnone uwtable } + +attributes #2 = { allow_direct_access_in_hot_patch_function } + +; CHECK: this_does_not_get_hotpatched: # @this_does_not_get_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movl some_global_var(%rip), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.ll b/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.ll new file mode 100644 index 0000000000000..d02d1ae1bfed5 --- /dev/null +++ b/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.ll @@ -0,0 +1,38 @@ +; This tests annotating a function with marked_for_windows_hot_patching by using --ms-hotpatch-functions-file. +; +; RUN: llc -mtriple=x86_64-windows --ms-hotpatch-functions-file=%S/ms-hotpatch-functions-file.txt < %s | FileCheck %s + +source_filename = ".\\ms-hotpatch-functions-file.ll" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.36.32537" + +@some_global_var = external global i32 + +define noundef i32 @this_gets_hotpatched() #0 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #0 = { mustprogress noinline nounwind optnone uwtable } + +; CHECK: this_gets_hotpatched: # @this_gets_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movq __ref_some_global_var(%rip), %rax +; CHECK-NEXT: movl (%rax), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq + +define noundef i32 @this_does_not_get_hotpatched() #1 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #1 = { mustprogress noinline nounwind optnone uwtable } + +; CHECK: this_does_not_get_hotpatched: # @this_does_not_get_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movl some_global_var(%rip), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt b/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt new file mode 100644 index 0000000000000..2512ba3881c66 --- /dev/null +++ b/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt @@ -0,0 +1 @@ +this_gets_hotpatched diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-list.ll b/llvm/test/CodeGen/Generic/ms-hotpatch-functions-list.ll new file mode 100644 index 0000000000000..c5565824cbe6c --- /dev/null +++ b/llvm/test/CodeGen/Generic/ms-hotpatch-functions-list.ll @@ -0,0 +1,38 @@ +; This tests annotating a function with marked_for_windows_hot_patching by using --ms-hotpatch-functions-list. +; +; RUN: llc -mtriple=x86_64-windows --ms-hotpatch-functions-list=this_gets_hotpatched < %s | FileCheck %s + +source_filename = ".\\ms-hotpatch-functions-list.ll" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.36.32537" + +@some_global_var = external global i32 + +define noundef i32 @this_gets_hotpatched() #0 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #0 = { mustprogress noinline nounwind optnone uwtable } + +; CHECK: this_gets_hotpatched: # @this_gets_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movq __ref_some_global_var(%rip), %rax +; CHECK-NEXT: movl (%rax), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq + +define noundef i32 @this_does_not_get_hotpatched() #1 { + %1 = load i32, ptr @some_global_var + %2 = add i32 %1, 1 + ret i32 %2 +} + +attributes #1 = { mustprogress noinline nounwind optnone uwtable } + +; CHECK: this_does_not_get_hotpatched: # @this_does_not_get_hotpatched +; CHECK-NEXT: bb.0: +; CHECK-NEXT: movl some_global_var(%rip), %eax +; CHECK-NEXT: addl $1, %eax +; CHECK-NEXT: retq diff --git a/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp index 479d025835188..66a091f50d6b2 100644 --- a/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp +++ b/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -955,3 +955,11 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, JumpTable.EntriesCount); return Error::success(); } + +Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, + HotPatchFuncSym &JumpTable) { + AutoIndent Indent(P, 7); + P.formatLine("function = {0}, name = {1}", typeIndex(JumpTable.Function), + JumpTable.Name); + return Error::success(); +} >From 6e727ebfe44b9dfa4221a7fafa4749283c42953e Mon Sep 17 00:00:00 2001 From: sivadeilra <arlie.da...@microsoft.com> Date: Tue, 13 May 2025 10:37:14 -0700 Subject: [PATCH 2/4] Rename to Secure, in LLVM --- llvm/include/llvm/CodeGen/Passes.h | 2 +- llvm/include/llvm/InitializePasses.h | 2 +- llvm/lib/CodeGen/CMakeLists.txt | 2 +- llvm/lib/CodeGen/TargetPassConfig.cpp | 2 +- ...Patch.cpp => WindowsSecureHotPatching.cpp} | 110 ++++++++++++------ .../Generic/ms-hotpatch-functions-file.txt | 1 - ...tch-attr.ll => ms-secure-hotpatch-attr.ll} | 0 ...file.ll => ms-secure-hotpatch-bad-file.ll} | 2 +- ...s-secure-hotpatch-direct-global-access.ll} | 0 ...l => ms-secure-hotpatch-functions-file.ll} | 3 +- ...l => ms-secure-hotpatch-functions-list.ll} | 2 +- 11 files changed, 80 insertions(+), 46 deletions(-) rename llvm/lib/CodeGen/{WindowsHotPatch.cpp => WindowsSecureHotPatching.cpp} (62%) delete mode 100644 llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt rename llvm/test/CodeGen/Generic/{ms-hotpatch-attr.ll => ms-secure-hotpatch-attr.ll} (100%) rename llvm/test/CodeGen/Generic/{ms-hotpatch-bad-file.ll => ms-secure-hotpatch-bad-file.ll} (75%) rename llvm/test/CodeGen/Generic/{ms-hotpatch-direct-global-access.ll => ms-secure-hotpatch-direct-global-access.ll} (100%) rename llvm/test/CodeGen/Generic/{ms-hotpatch-functions-file.ll => ms-secure-hotpatch-functions-file.ll} (86%) rename llvm/test/CodeGen/Generic/{ms-hotpatch-functions-list.ll => ms-secure-hotpatch-functions-list.ll} (91%) diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index c4163617da5ae..d0cee3ddf268d 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -619,7 +619,7 @@ namespace llvm { FunctionPass *createKCFIPass(); /// Creates Windows Hot Patch pass. \see WindowsHotPatch.cpp - ModulePass *createWindowsHotPatch(); + ModulePass *createWindowsSecureHotPatching(); } // End llvm namespace #endif diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index 53722dd10fac7..3b204d79a21d6 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -323,7 +323,7 @@ void initializeVirtRegMapWrapperLegacyPass(PassRegistry &); void initializeVirtRegRewriterLegacyPass(PassRegistry &); void initializeWasmEHPreparePass(PassRegistry &); void initializeWinEHPreparePass(PassRegistry &); -void initializeWindowsHotPatchPass(PassRegistry &); +void initializeWindowsSecureHotPatchingPass(PassRegistry &); void initializeWriteBitcodePassPass(PassRegistry &); void initializeXRayInstrumentationLegacyPass(PassRegistry &); diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index f18f085b0450b..f8f9bbba53e43 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -250,7 +250,7 @@ add_llvm_component_library(LLVMCodeGen VirtRegMap.cpp WasmEHPrepare.cpp WindowScheduler.cpp - WindowsHotPatch.cpp + WindowsSecureHotPatching.cpp WinEHPrepare.cpp XRayInstrumentation.cpp ${GeneratedMLSources} diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 1d93efc21fbab..0f6ac3ee12316 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -895,7 +895,7 @@ void TargetPassConfig::addIRPasses() { addPass(createGlobalMergeFuncPass()); if (TM->getTargetTriple().isOSBinFormatCOFF()) - addPass(createWindowsHotPatch()); + addPass(createWindowsSecureHotPatching()); } /// Turn exception handling constructs into something the code generators can diff --git a/llvm/lib/CodeGen/WindowsHotPatch.cpp b/llvm/lib/CodeGen/WindowsSecureHotPatching.cpp similarity index 62% rename from llvm/lib/CodeGen/WindowsHotPatch.cpp rename to llvm/lib/CodeGen/WindowsSecureHotPatching.cpp index 08995439e51e9..977f950ee6ea6 100644 --- a/llvm/lib/CodeGen/WindowsHotPatch.cpp +++ b/llvm/lib/CodeGen/WindowsSecureHotPatching.cpp @@ -6,7 +6,50 @@ // //===----------------------------------------------------------------------===// // -// Marks functions with the `marked_for_windows_hot_patching` attribute. +// 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/?msockid=19a6f8f09bd160ac0b18ed449afc614b // //===----------------------------------------------------------------------===// @@ -30,20 +73,19 @@ using namespace llvm; #define DEBUG_TYPE "windows-hot-patch" // A file containing list of mangled function names to mark for hot patching. -static cl::opt<std::string> LLVMMSHotPatchFunctionsFile( - "ms-hotpatch-functions-file", cl::value_desc("filename"), - cl::desc("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> LLVMMSHotPatchFunctionsList( - "ms-hotpatch-functions-list", cl::value_desc("list"), - cl::desc("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 WindowsHotPatch : public ModulePass { +class WindowsSecureHotPatching : public ModulePass { struct GlobalVariableUse { GlobalVariable *GV; Instruction *User; @@ -53,8 +95,8 @@ class WindowsHotPatch : public ModulePass { public: static char ID; - WindowsHotPatch() : ModulePass(ID) { - initializeWindowsHotPatchPass(*PassRegistry::getPassRegistry()); + WindowsSecureHotPatching() : ModulePass(ID) { + initializeWindowsSecureHotPatchingPass(*PassRegistry::getPassRegistry()); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -75,64 +117,58 @@ class WindowsHotPatch : public ModulePass { } // end anonymous namespace -char WindowsHotPatch::ID = 0; +char WindowsSecureHotPatching::ID = 0; -INITIALIZE_PASS(WindowsHotPatch, "windows-hot-patch", +INITIALIZE_PASS(WindowsSecureHotPatching, "windows-secure-hot-patch", "Mark functions for Windows hot patch support", false, false) -ModulePass *llvm::createWindowsHotPatch() { return new WindowsHotPatch(); } +ModulePass *llvm::createWindowsSecureHotPatching() { return new WindowsSecureHotPatching(); } // Find functions marked with Attribute::MarkedForWindowsHotPatching and modify // their code (if necessary) to account for accesses to global variables. -bool WindowsHotPatch::runOnModule(Module &M) { +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 (!LLVMMSHotPatchFunctionsFile.empty() || - !LLVMMSHotPatchFunctionsList.empty()) { + if (!LLVMMSSecureHotPatchFunctionsFile.empty() || + !LLVMMSSecureHotPatchFunctionsList.empty()) { std::vector<std::string> HotPatchFunctionsList; - if (!LLVMMSHotPatchFunctionsFile.empty()) { - auto BufOrErr = llvm::MemoryBuffer::getFile(LLVMMSHotPatchFunctionsFile); + 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) { + 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): ") + - LLVMMSHotPatchFunctionsFile + llvm::Twine(" : ") + + LLVMMSSecureHotPatchFunctionsFile + llvm::Twine(" : ") + BufOrErr.getError().message()}); } } - if (!LLVMMSHotPatchFunctionsList.empty()) { - for (const auto &FuncName : LLVMMSHotPatchFunctionsList) { + 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) { + 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()) { + if (F.isDeclarationForLinker()) continue; - } - if (HotPatchFunctionsSet.contains(F.getName())) { + if (HotPatchFunctionsSet.contains(F.getName())) F.addFnAttr(Attribute::MarkedForWindowsHotPatching); - } } } @@ -140,9 +176,8 @@ bool WindowsHotPatch::runOnModule(Module &M) { bool MadeChanges = false; for (auto &F : M.functions()) { if (F.hasFnAttribute(Attribute::MarkedForWindowsHotPatching)) { - if (runOnFunction(F, RefMapping)) { + if (runOnFunction(F, RefMapping)) MadeChanges = true; - } } } return MadeChanges; @@ -168,7 +203,7 @@ bool WindowsHotPatch::runOnModule(Module &M) { // CodeViewDebug::emitHotPatchInformation(). // // Returns true if any changes were made to the function. -bool WindowsHotPatch::runOnFunction( +bool WindowsSecureHotPatching::runOnFunction( Function &F, SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping) { SmallVector<GlobalVariableUse, 32> GVUses; @@ -190,16 +225,15 @@ bool WindowsHotPatch::runOnFunction( Subprogram != nullptr ? Subprogram->getUnit() : nullptr}; replaceGlobalVariableUses(F, GVUses, RefMapping, DebugInfo); - if (Subprogram != nullptr) { + if (Subprogram != nullptr) DebugInfo.finalize(); - } return true; } else { return false; } } -void WindowsHotPatch::replaceGlobalVariableUses( +void WindowsSecureHotPatching::replaceGlobalVariableUses( Function &F, SmallVectorImpl<GlobalVariableUse> &GVUses, SmallDenseMap<GlobalVariable *, GlobalVariable *> &RefMapping, DIBuilder &DebugInfo) { diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt b/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt deleted file mode 100644 index 2512ba3881c66..0000000000000 --- a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.txt +++ /dev/null @@ -1 +0,0 @@ -this_gets_hotpatched diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-attr.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-attr.ll similarity index 100% rename from llvm/test/CodeGen/Generic/ms-hotpatch-attr.ll rename to llvm/test/CodeGen/Generic/ms-secure-hotpatch-attr.ll diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-bad-file.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll similarity index 75% rename from llvm/test/CodeGen/Generic/ms-hotpatch-bad-file.ll rename to llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll index 59a83c9040a41..4501863dd0bd2 100644 --- a/llvm/test/CodeGen/Generic/ms-hotpatch-bad-file.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll @@ -1,4 +1,4 @@ -; RUN: not llc -mtriple=x86_64-windows --ms-hotpatch-functions-file=%S/this-file-is-intentionally-missing-do-not-create-it.txt < %s 2>&1 | FileCheck %s +; RUN: not llc -mtriple=x86_64-windows --ms-secure-hotpatch-functions-file=%S/this-file-is-intentionally-missing-do-not-create-it.txt < %s 2>&1 | FileCheck %s ; CHECK: failed to open hotpatch functions file source_filename = ".\\ms-hotpatch.ll" diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-direct-global-access.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-direct-global-access.ll similarity index 100% rename from llvm/test/CodeGen/Generic/ms-hotpatch-direct-global-access.ll rename to llvm/test/CodeGen/Generic/ms-secure-hotpatch-direct-global-access.ll diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll similarity index 86% rename from llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.ll rename to llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll index d02d1ae1bfed5..eef572832c726 100644 --- a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-file.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll @@ -1,6 +1,7 @@ ; This tests annotating a function with marked_for_windows_hot_patching by using --ms-hotpatch-functions-file. ; -; RUN: llc -mtriple=x86_64-windows --ms-hotpatch-functions-file=%S/ms-hotpatch-functions-file.txt < %s | FileCheck %s +; RUN: echo this_gets_hotpatched > %t.patch-functions.txt +; RUN: llc -mtriple=x86_64-windows --ms-secure-hotpatch-functions-file=%t.patch-functions.txt < %s | FileCheck %s source_filename = ".\\ms-hotpatch-functions-file.ll" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" diff --git a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-list.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll similarity index 91% rename from llvm/test/CodeGen/Generic/ms-hotpatch-functions-list.ll rename to llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll index c5565824cbe6c..f841db41d3821 100644 --- a/llvm/test/CodeGen/Generic/ms-hotpatch-functions-list.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll @@ -1,6 +1,6 @@ ; This tests annotating a function with marked_for_windows_hot_patching by using --ms-hotpatch-functions-list. ; -; RUN: llc -mtriple=x86_64-windows --ms-hotpatch-functions-list=this_gets_hotpatched < %s | FileCheck %s +; RUN: llc -mtriple=x86_64-windows --ms-secure-hotpatch-functions-list=this_gets_hotpatched < %s | FileCheck %s source_filename = ".\\ms-hotpatch-functions-list.ll" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" >From 25dcedc3c1dcb7548b309d6a5bd898b8cd0c0d62 Mon Sep 17 00:00:00 2001 From: sivadeilra <arlie.da...@microsoft.com> Date: Tue, 13 May 2025 10:43:57 -0700 Subject: [PATCH 3/4] rename more integration tests --- clang/test/CodeGen/ms-hotpatch-functions.txt | 1 - .../{ms-hotpatch-bad-file.c => ms-secure-hotpatch-bad-file.c} | 0 .../{ms-hotpatch-cpp.cpp => ms-secure-hotpatch-cpp.cpp} | 0 .../CodeGen/{ms-hotpatch-lto.c => ms-secure-hotpatch-lto.c} | 2 +- clang/test/CodeGen/{ms-hotpatch.c => ms-secure-hotpatch.c} | 3 ++- llvm/test/CodeGen/Generic/ms-secure-hotpatch-attr.ll | 2 +- llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll | 2 +- .../CodeGen/Generic/ms-secure-hotpatch-direct-global-access.ll | 2 +- llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll | 2 +- llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll | 2 +- 10 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 clang/test/CodeGen/ms-hotpatch-functions.txt rename clang/test/CodeGen/{ms-hotpatch-bad-file.c => ms-secure-hotpatch-bad-file.c} (100%) rename clang/test/CodeGen/{ms-hotpatch-cpp.cpp => ms-secure-hotpatch-cpp.cpp} (100%) rename clang/test/CodeGen/{ms-hotpatch-lto.c => ms-secure-hotpatch-lto.c} (92%) rename clang/test/CodeGen/{ms-hotpatch.c => ms-secure-hotpatch.c} (83%) diff --git a/clang/test/CodeGen/ms-hotpatch-functions.txt b/clang/test/CodeGen/ms-hotpatch-functions.txt deleted file mode 100644 index 2512ba3881c66..0000000000000 --- a/clang/test/CodeGen/ms-hotpatch-functions.txt +++ /dev/null @@ -1 +0,0 @@ -this_gets_hotpatched diff --git a/clang/test/CodeGen/ms-hotpatch-bad-file.c b/clang/test/CodeGen/ms-secure-hotpatch-bad-file.c similarity index 100% rename from clang/test/CodeGen/ms-hotpatch-bad-file.c rename to clang/test/CodeGen/ms-secure-hotpatch-bad-file.c diff --git a/clang/test/CodeGen/ms-hotpatch-cpp.cpp b/clang/test/CodeGen/ms-secure-hotpatch-cpp.cpp similarity index 100% rename from clang/test/CodeGen/ms-hotpatch-cpp.cpp rename to clang/test/CodeGen/ms-secure-hotpatch-cpp.cpp diff --git a/clang/test/CodeGen/ms-hotpatch-lto.c b/clang/test/CodeGen/ms-secure-hotpatch-lto.c similarity index 92% rename from clang/test/CodeGen/ms-hotpatch-lto.c rename to clang/test/CodeGen/ms-secure-hotpatch-lto.c index 290f7695b02f6..e8791f1f0935e 100644 --- a/clang/test/CodeGen/ms-hotpatch-lto.c +++ b/clang/test/CodeGen/ms-secure-hotpatch-lto.c @@ -1,6 +1,6 @@ // 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-hotpatch-functions-file=%S/ms-hotpatch-functions.txt -flto /Fo%t.bc %s +// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-hotpatch-functions-list=this_gets_hotpatched -flto /Fo%t.bc %s // RUN: llvm-dis %t.bc -o - | FileCheck %s // // CHECK: ; Function Attrs: marked_for_windows_hot_patching mustprogress nofree noinline norecurse nosync nounwind sspstrong willreturn memory(none) uwtable diff --git a/clang/test/CodeGen/ms-hotpatch.c b/clang/test/CodeGen/ms-secure-hotpatch.c similarity index 83% rename from clang/test/CodeGen/ms-hotpatch.c rename to clang/test/CodeGen/ms-secure-hotpatch.c index 79da105f4cec3..71ae2be34a500 100644 --- a/clang/test/CodeGen/ms-hotpatch.c +++ b/clang/test/CodeGen/ms-secure-hotpatch.c @@ -1,6 +1,7 @@ // This verifies that hotpatch function attributes are correctly propagated when compiling directly to OBJ. // -// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-hotpatch-functions-file=%S/ms-hotpatch-functions.txt /Fo%t.obj %s +// RUN: echo this_gets_hotpatched > %t.patch-functions.txt +// RUN: %clang_cl -c --target=x86_64-windows-msvc -O2 /Z7 -fms-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(); diff --git a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-attr.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-attr.ll index 08fbc073e0716..11d99bae1ca8c 100644 --- a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-attr.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-attr.ll @@ -2,7 +2,7 @@ ; ; RUN: llc -mtriple=x86_64-windows < %s | FileCheck %s -source_filename = ".\\ms-hotpatch-attr.ll" +source_filename = ".\\ms-secure-hotpatch-attr.ll" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc19.36.32537" diff --git a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll index 4501863dd0bd2..8f8624ea0de49 100644 --- a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-bad-file.ll @@ -1,7 +1,7 @@ ; RUN: not llc -mtriple=x86_64-windows --ms-secure-hotpatch-functions-file=%S/this-file-is-intentionally-missing-do-not-create-it.txt < %s 2>&1 | FileCheck %s ; CHECK: failed to open hotpatch functions file -source_filename = ".\\ms-hotpatch.ll" +source_filename = ".\\ms-secure-hotpatch.ll" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc19.36.32537" diff --git a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-direct-global-access.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-direct-global-access.ll index eb8754ee6c3f7..960a76fe43f12 100644 --- a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-direct-global-access.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-direct-global-access.ll @@ -2,7 +2,7 @@ ; ; RUN: llc -mtriple=x86_64-windows < %s | FileCheck %s -source_filename = ".\\ms-hotpatch-direct-global-access.ll" +source_filename = ".\\ms-secure-hotpatch-direct-global-access.ll" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc19.36.32537" diff --git a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll index eef572832c726..bb79e08683aa7 100644 --- a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-file.ll @@ -3,7 +3,7 @@ ; RUN: echo this_gets_hotpatched > %t.patch-functions.txt ; RUN: llc -mtriple=x86_64-windows --ms-secure-hotpatch-functions-file=%t.patch-functions.txt < %s | FileCheck %s -source_filename = ".\\ms-hotpatch-functions-file.ll" +source_filename = ".\\ms-secure-hotpatch-functions-file.ll" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc19.36.32537" diff --git a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll index f841db41d3821..b1da1a2db66dc 100644 --- a/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll +++ b/llvm/test/CodeGen/Generic/ms-secure-hotpatch-functions-list.ll @@ -2,7 +2,7 @@ ; ; RUN: llc -mtriple=x86_64-windows --ms-secure-hotpatch-functions-list=this_gets_hotpatched < %s | FileCheck %s -source_filename = ".\\ms-hotpatch-functions-list.ll" +source_filename = ".\\ms-secure-hotpatch-functions-list.ll" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc19.36.32537" >From d015c8b1871bba466aed8e22dd7e1c63578b7cb6 Mon Sep 17 00:00:00 2001 From: sivadeilra <arlie.da...@microsoft.com> Date: Tue, 13 May 2025 11:08:02 -0700 Subject: [PATCH 4/4] finish renaming to SHP --- clang/include/clang/Basic/CodeGenOptions.h | 8 +++---- clang/include/clang/Driver/Options.td | 22 +++++++++++-------- clang/lib/CodeGen/CodeGenModule.cpp | 22 +++++++++---------- clang/lib/Driver/ToolChains/Clang.cpp | 10 ++++----- .../CodeGen/ms-secure-hotpatch-bad-file.c | 4 ++-- clang/test/CodeGen/ms-secure-hotpatch-cpp.cpp | 2 +- clang/test/CodeGen/ms-secure-hotpatch-lto.c | 2 +- clang/test/CodeGen/ms-secure-hotpatch.c | 2 +- 8 files changed, 36 insertions(+), 36 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index b0efc445b8450..5a5deb03847f1 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -502,12 +502,12 @@ 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-hot-patch-functions-file. - std::string MSHotPatchFunctionsFile; + /// hotpatching. See -fms-secure-hotpatch-functions-file. + std::string MSSecureHotPatchFunctionsFile; /// A list of functions which will be compiled for hotpatching. - /// See -fms-hot-patch-functions-list. - std::vector<std::string> MSHotPatchFunctionsList; + /// 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 9d1931381dee7..d47f88bf4eb8f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3830,20 +3830,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">>; -def fms_hotpatch_functions_file - : Joined<["-"], "fms-hotpatch-functions-file=">, + +// 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<"MSHotPatchFunctionsFile">>, - HelpText<"Path to a file that contains a list of mangled symbol names of " - "functions that should be hot-patched">; -def fms_hotpatch_functions_list - : CommaJoined<["-"], "fms-hotpatch-functions-list=">, + 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<"MSHotPatchFunctionsList">>, + MarshallingInfoStringVector<CodeGenOpts<"MSSecureHotPatchFunctionsList">>, HelpText<"List of mangled symbol names of functions that should be " - "hot-patched">; + "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/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index aa11487c4dce1..81eced29305fd 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -454,35 +454,33 @@ CodeGenModule::CodeGenModule(ASTContext &C, getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters", CodeGenOpts.NumRegisterParameters); - // If there are any functions that are marked for Windows hot-patching, + // If there are any functions that are marked for Windows secure hot-patching, // then build the list of functions now. - if (!CGO.MSHotPatchFunctionsFile.empty() || - !CGO.MSHotPatchFunctionsList.empty()) { - if (!CGO.MSHotPatchFunctionsFile.empty()) { - auto BufOrErr = llvm::MemoryBuffer::getFile(CGO.MSHotPatchFunctionsFile); + 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) { + 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.MSHotPatchFunctionsFile + DE.Report(DiagID) << CGO.MSSecureHotPatchFunctionsFile << BufOrErr.getError().message(); } } - for (const auto &FuncName : CGO.MSHotPatchFunctionsList) { + for (const auto &FuncName : CGO.MSSecureHotPatchFunctionsList) this->MSHotPatchFunctions.push_back(FuncName); - } - std::sort(this->MSHotPatchFunctions.begin(), - this->MSHotPatchFunctions.end()); + llvm::sort(this->MSHotPatchFunctions); } } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6a38a9ada42ec..574ebc26bc56f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6946,15 +6946,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch); - if (Arg *A = Args.getLastArg(options::OPT_fms_hotpatch_functions_file)) { - Args.AddLastArg(CmdArgs, options::OPT_fms_hotpatch_functions_file); - } + if (Arg *A = Args.getLastArg(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_hotpatch_functions_list)) { + Args.getAllArgValues(options::OPT_fms_secure_hotpatch_functions_list)) CmdArgs.push_back( - Args.MakeArgString("-fms-hotpatch-functions-list=" + Twine(A))); - } + Args.MakeArgString("-fms-secure-hotpatch-functions-list=" + Twine(A))); if (TC.SupportsProfiling()) { Args.AddLastArg(CmdArgs, options::OPT_pg); diff --git a/clang/test/CodeGen/ms-secure-hotpatch-bad-file.c b/clang/test/CodeGen/ms-secure-hotpatch-bad-file.c index 55304488175df..22f10b34d82fb 100644 --- a/clang/test/CodeGen/ms-secure-hotpatch-bad-file.c +++ b/clang/test/CodeGen/ms-secure-hotpatch-bad-file.c @@ -1,7 +1,7 @@ -// This verifies that we correctly handle a -fms-hotpatch-functions-file argument that points +// 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-hotpatch-functions-file=%S/this-file-is-intentionally-missing-do-not-create-it.txt /Fo%t.obj %s 2>&1 | FileCheck %s +// 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(); diff --git a/clang/test/CodeGen/ms-secure-hotpatch-cpp.cpp b/clang/test/CodeGen/ms-secure-hotpatch-cpp.cpp index 26e11f429c962..c8112ad54baab 100644 --- a/clang/test/CodeGen/ms-secure-hotpatch-cpp.cpp +++ b/clang/test/CodeGen/ms-secure-hotpatch-cpp.cpp @@ -1,7 +1,7 @@ // 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-hotpatch-functions-list=?this_gets_hotpatched@@YAHXZ /Fo%t.obj %s +// 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(); diff --git a/clang/test/CodeGen/ms-secure-hotpatch-lto.c b/clang/test/CodeGen/ms-secure-hotpatch-lto.c index e8791f1f0935e..6771d3e9f49cf 100644 --- a/clang/test/CodeGen/ms-secure-hotpatch-lto.c +++ b/clang/test/CodeGen/ms-secure-hotpatch-lto.c @@ -1,6 +1,6 @@ // 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-hotpatch-functions-list=this_gets_hotpatched -flto /Fo%t.bc %s +// 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: ; Function Attrs: marked_for_windows_hot_patching mustprogress nofree noinline norecurse nosync nounwind sspstrong willreturn memory(none) uwtable diff --git a/clang/test/CodeGen/ms-secure-hotpatch.c b/clang/test/CodeGen/ms-secure-hotpatch.c index 71ae2be34a500..f170de851ae51 100644 --- a/clang/test/CodeGen/ms-secure-hotpatch.c +++ b/clang/test/CodeGen/ms-secure-hotpatch.c @@ -1,7 +1,7 @@ // 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-hotpatch-functions-file=%t.patch-functions.txt /Fo%t.obj %s +// 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(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits