diff --git a/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp b/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp index 1a1e6f0117e2b8..663be65b7b9a8a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp @@ -49,26 +49,32 @@ static bool isPossibleIndirectCallTarget(const Function *F) { const Value *FnOrCast = Users.pop_back_val(); for (const Use &U : FnOrCast->uses()) { const User *FnUser = U.getUser(); - if (isa(FnUser)) + if (isa(FnUser)) { + // Block addresses are illegal to call. continue; + } if (const auto *Call = dyn_cast(FnUser)) { - if (!Call->isCallee(&U)) + if ((!Call->isCallee(&U) || U.get() != F) && + !Call->getFunction()->getName().ends_with("$exit_thunk")) { + // Passing a function pointer to a call may lead to an indirect + // call. As an exception, ignore ARM64EC exit thunks. return true; + } } else if (isa(FnUser)) { // Consider any other instruction to be an escape. This has some weird // consequences like no-op intrinsics being an escape or a store *to* a // function address being an escape. return true; - } else if (const auto *C = dyn_cast(FnUser)) { - // If this is a constant pointer cast of the function, don't consider - // this escape. Analyze the uses of the cast as well. This ensures that - // direct calls with mismatched prototypes don't end up in the CFG - // table. Consider other constants, such as vtable initializers, to - // escape the function. - if (C->stripPointerCasts() == F) - Users.push_back(FnUser); - else - return true; + } else if (const auto *G = dyn_cast(FnUser)) { + // Ignore llvm.arm64ec.symbolmap; it doesn't lower to an actual address. + if (G->getName() == "llvm.arm64ec.symbolmap") + continue; + // Globals (for example, vtables) are escapes. + return true; + } else if (isa(FnUser)) { + // Constants which aren't a global are intermediate values; recursively + // analyze the users to see if they actually escape. + Users.push_back(FnUser); } } } diff --git a/llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll b/llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll new file mode 100644 index 00000000000000..bdbc99e2d98b0a --- /dev/null +++ b/llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll @@ -0,0 +1,16 @@ +; RUN: llc < %s -mtriple=arm64ec-pc-windows-msvc | FileCheck %s + +declare void @called() +declare void @escaped() +define void @f(ptr %dst) { + call void @called() + store ptr @escaped, ptr %dst + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"cfguard", i32 1} + +; CHECK-LABEL: .section .gfids$y,"dr" +; CHECK-NEXT: .symidx escaped +; CHECK-NOT: .symidx