[llvm] [CodeGen][ARM64EC] Don't treat guest exit thunks as indirect calls (PR #165885)
Jacek Caban via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 31 12:07:43 PDT 2025
https://github.com/cjacek updated https://github.com/llvm/llvm-project/pull/165885
>From 5eccb7fa21d269303d1bb240b0110adbd3d420dc Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Fri, 31 Oct 2025 17:38:14 +0100
Subject: [PATCH] [CodeGen][ARM64EC] Don't treat guest exit thunks as indirect
calls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Guest exit thunks serve as glue for performing direct calls, so they shouldn’t treat the target as an indirect one.
Spotted by @coneco-cy in #165504.
---
.../AArch64/AArch64Arm64ECCallLowering.cpp | 14 ++----
llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll | 49 +++++++++++++++++--
2 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
index 1169f26a2ae37..97298f9d74171 100644
--- a/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp
@@ -655,16 +655,10 @@ Function *AArch64Arm64ECCallLowering::buildGuestExitThunk(Function *F) {
BasicBlock *BB = BasicBlock::Create(M->getContext(), "", GuestExit);
IRBuilder<> B(BB);
- // Load the global symbol as a pointer to the check function.
- Value *GuardFn;
- if (cfguard_module_flag == 2 && !F->hasFnAttribute("guard_nocf"))
- GuardFn = GuardFnCFGlobal;
- else
- GuardFn = GuardFnGlobal;
- LoadInst *GuardCheckLoad = B.CreateLoad(PtrTy, GuardFn);
-
- // Create new call instruction. The CFGuard check should always be a call,
- // even if the original CallBase is an Invoke or CallBr instruction.
+ // Create new call instruction. The call check should always be a call,
+ // even if the original CallBase is an Invoke or CallBr instructio.
+ // This is treated as a direct call, so do not use GuardFnCFGlobal.
+ LoadInst *GuardCheckLoad = B.CreateLoad(PtrTy, GuardFnGlobal);
Function *Thunk = buildExitThunk(F->getFunctionType(), F->getAttributes());
CallInst *GuardCheck = B.CreateCall(
GuardFnType, GuardCheckLoad, {F, Thunk});
diff --git a/llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll b/llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll
index bdbc99e2d98b0..75e7ac902274d 100644
--- a/llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll
+++ b/llvm/test/CodeGen/AArch64/cfguard-arm64ec.ll
@@ -2,15 +2,58 @@
declare void @called()
declare void @escaped()
-define void @f(ptr %dst) {
+define void @f(ptr %dst, ptr readonly %f) {
call void @called()
+; CHECK: bl "#called"
store ptr @escaped, ptr %dst
- ret void
+ call void %f()
+; CHECK: adrp x10, $iexit_thunk$cdecl$v$v
+; CHECK-NEXT: add x10, x10, :lo12:$iexit_thunk$cdecl$v$v
+; CHECK-NEXT: str x8, [x20]
+; CHECK-NEXT: adrp x8, __os_arm64x_check_icall_cfg
+; CHECK-NEXT: ldr x8, [x8, :lo12:__os_arm64x_check_icall_cfg]
+; CHECK-NEXT: mov x11,
+; CHECK-NEXT: blr x8
+; CHECK-NEXT: blr x11
+ ret void
}
+; CHECK-LABEL: .def "#called$exit_thunk";
+; CHECK-NEXT: .scl 2;
+; CHECK-NEXT: .type 32;
+; CHECK-NEXT: .endef
+; CHECK-NEXT: .section .wowthk$aa,"xr",discard,"#called$exit_thunk"
+; CHECK-NEXT: .globl "#called$exit_thunk" // -- Begin function #called$exit_thunk
+; CHECK-NEXT: .p2align 2
+; CHECK-NEXT: "#called$exit_thunk": // @"#called$exit_thunk"
+; CHECK-NEXT: .weak_anti_dep called
+; CHECK-NEXT: called = "#called"
+; CHECK-NEXT: .weak_anti_dep "#called"
+; CHECK-NEXT: "#called" = "#called$exit_thunk"
+; CHECK-NEXT: .seh_proc "#called$exit_thunk"
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT: .seh_save_reg_x x30, 16
+; CHECK-NEXT: .seh_endprologue
+; CHECK-NEXT: adrp x8, __os_arm64x_check_icall
+; CHECK-NEXT: adrp x11, called
+; CHECK-NEXT: add x11, x11, :lo12:called
+; CHECK-NEXT: ldr x8, [x8, :lo12:__os_arm64x_check_icall]
+; CHECK-NEXT: adrp x10, $iexit_thunk$cdecl$v$v
+; CHECK-NEXT: add x10, x10, :lo12:$iexit_thunk$cdecl$v$v
+; CHECK-NEXT: blr x8
+; CHECK-NEXT: .seh_startepilogue
+; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT: .seh_save_reg_x x30, 16
+; CHECK-NEXT: .seh_endepilogue
+; CHECK-NEXT: br x11
+; CHECK-NEXT: .seh_endfunclet
+; CHECK-NEXT: .seh_endproc
+
!llvm.module.flags = !{!0}
-!0 = !{i32 2, !"cfguard", i32 1}
+!0 = !{i32 2, !"cfguard", i32 2}
; CHECK-LABEL: .section .gfids$y,"dr"
; CHECK-NEXT: .symidx escaped
+; CHECK-NEXT: .symidx $iexit_thunk$cdecl$v$v
; CHECK-NOT: .symidx
More information about the llvm-commits
mailing list