[llvm] d540ebf - [ARM64EC] Avoid emitting unnecessary symbol references with /guard:cf. (#123235)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 21 16:29:26 PST 2025
Author: Eli Friedman
Date: 2025-01-21T16:29:23-08:00
New Revision: d540ebf6cbf97b8bac45af837a741bcb5bd1e1f6
URL: https://github.com/llvm/llvm-project/commit/d540ebf6cbf97b8bac45af837a741bcb5bd1e1f6
DIFF: https://github.com/llvm/llvm-project/commit/d540ebf6cbf97b8bac45af837a741bcb5bd1e1f6.diff
LOG: [ARM64EC] Avoid emitting unnecessary symbol references with /guard:cf. (#123235)
.gfids$y contains a list of indirect calls for Control Flow Guard. This
wasn't working properly for ARM64EC: direct calls were being treated as
indirect calls. Make sure we correctly filter out direct calls.
This improves the protection from Control Flow Guard, and also fixes a
link error when using certain functions from oldnames.lib.
Added:
llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll
Modified:
llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
Removed:
################################################################################
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<BlockAddress>(FnUser))
+ if (isa<BlockAddress>(FnUser)) {
+ // Block addresses are illegal to call.
continue;
+ }
if (const auto *Call = dyn_cast<CallBase>(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<Instruction>(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<Constant>(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<GlobalValue>(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<Constant>(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
More information about the llvm-commits
mailing list