Skip to content

Commit 0171f77

Browse files
committed
[CodeGen][ARM64EC] Don't treat guest exit thunks as indirect calls
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.
1 parent f5e175f commit 0171f77

File tree

2 files changed

+93
-10
lines changed

2 files changed

+93
-10
lines changed

llvm/lib/Target/AArch64/AArch64Arm64ECCallLowering.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -655,16 +655,10 @@ Function *AArch64Arm64ECCallLowering::buildGuestExitThunk(Function *F) {
655655
BasicBlock *BB = BasicBlock::Create(M->getContext(), "", GuestExit);
656656
IRBuilder<> B(BB);
657657

658-
// Load the global symbol as a pointer to the check function.
659-
Value *GuardFn;
660-
if (cfguard_module_flag == 2 && !F->hasFnAttribute("guard_nocf"))
661-
GuardFn = GuardFnCFGlobal;
662-
else
663-
GuardFn = GuardFnGlobal;
664-
LoadInst *GuardCheckLoad = B.CreateLoad(PtrTy, GuardFn);
665-
666-
// Create new call instruction. The CFGuard check should always be a call,
667-
// even if the original CallBase is an Invoke or CallBr instruction.
658+
// Create new call instruction. The call check should always be a call,
659+
// even if the original CallBase is an Invoke or CallBr instructio.
660+
// This is treated as a direct call, so do not use GuardFnCFGlobal.
661+
LoadInst *GuardCheckLoad = B.CreateLoad(PtrTy, GuardFnGlobal);
668662
Function *Thunk = buildExitThunk(F->getFunctionType(), F->getAttributes());
669663
CallInst *GuardCheck = B.CreateCall(
670664
GuardFnType, GuardCheckLoad, {F, Thunk});
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
; REQUIRES: aarch64-registered-target
2+
; RUN: llc < %s -mtriple=arm64ec-windows | FileCheck %s
3+
4+
; This file was generated from the following source, using this command line:
5+
; clang -target arm64ec-windows cfguard-arm64ec.c -S -emit-llvm -o cfguard-arm64ec.ll -O -Xclang -cfguard
6+
;
7+
;-------------------------------------------------------------------------------
8+
; extern void ext(void);
9+
;
10+
; void func(void (*f)())
11+
; {
12+
; ext();
13+
; f();
14+
; }
15+
;-------------------------------------------------------------------------------
16+
17+
; ModuleID = 'cfguard-arm64ec.c'
18+
source_filename = "cfguard-arm64ec.c"
19+
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32"
20+
target triple = "arm64ec-unknown-windows-msvc19.33.0"
21+
22+
; CHECK: "@feat.00" = 2048
23+
24+
; Function Attrs: nounwind uwtable
25+
define dso_local void @func(ptr noundef readonly captures(none) %f) local_unnamed_addr #0 {
26+
entry:
27+
tail call void @ext() #2
28+
; CHECK: bl "#ext"
29+
tail call void %f() #2
30+
; CHECK-NEXT: adrp x8, __os_arm64x_check_icall_cfg
31+
; CHECK-NEXT: adrp x10, $iexit_thunk$cdecl$v$v
32+
; CHECK-NEXT: add x10, x10, :lo12:$iexit_thunk$cdecl$v$v
33+
; CHECK-NEXT: ldr x8, [x8, :lo12:__os_arm64x_check_icall_cfg]
34+
; CHECK-NEXT: mov x11, x19
35+
; CHECK-NEXT: blr x8
36+
ret void
37+
}
38+
39+
declare dso_local void @ext() local_unnamed_addr #1
40+
41+
; CHECK: .def "#ext$exit_thunk";
42+
; CHECK-NEXT: .scl 2;
43+
; CHECK-NEXT: .type 32;
44+
; CHECK-NEXT: .endef
45+
; CHECK-NEXT: .section .wowthk$aa,"xr",discard,"#ext$exit_thunk"
46+
; CHECK-NEXT: .globl "#ext$exit_thunk" // -- Begin function #ext$exit_thunk
47+
; CHECK-NEXT: .p2align 2
48+
; CHECK-NEXT: "#ext$exit_thunk": // @"#ext$exit_thunk"
49+
; CHECK-NEXT: .weak_anti_dep ext
50+
; CHECK-NEXT: ext = "#ext"
51+
; CHECK-NEXT: .weak_anti_dep "#ext"
52+
; CHECK-NEXT: "#ext" = "#ext$exit_thunk"
53+
; CHECK-NEXT: .seh_proc "#ext$exit_thunk"
54+
; CHECK-NEXT: // %bb.0:
55+
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
56+
; CHECK-NEXT: .seh_save_reg_x x30, 16
57+
; CHECK-NEXT: .seh_endprologue
58+
; CHECK-NEXT: adrp x8, __os_arm64x_check_icall
59+
; CHECK-NEXT: adrp x11, ext
60+
; CHECK-NEXT: add x11, x11, :lo12:ext
61+
; CHECK-NEXT: ldr x8, [x8, :lo12:__os_arm64x_check_icall]
62+
; CHECK-NEXT: adrp x10, $iexit_thunk$cdecl$v$v
63+
; CHECK-NEXT: add x10, x10, :lo12:$iexit_thunk$cdecl$v$v
64+
; CHECK-NEXT: blr x8
65+
; CHECK-NEXT: .seh_startepilogue
66+
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
67+
; CHECK-NEXT: .seh_save_reg_x x30, 16
68+
; CHECK-NEXT: .seh_endepilogue
69+
; CHECK-NEXT: br x11
70+
; CHECK-NEXT: .seh_endfunclet
71+
; CHECK-NEXT: .seh_endproc
72+
73+
attributes #0 = { nounwind uwtable "frame-pointer"="reserved" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+v8a,-fmv" }
74+
attributes #1 = { "frame-pointer"="reserved" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+v8a,-fmv" }
75+
attributes #2 = { nounwind }
76+
77+
!llvm.dbg.cu = !{!0}
78+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
79+
!llvm.ident = !{!8}
80+
81+
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git", isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None)
82+
!1 = !DIFile(filename: "cfguard-arm64ec.c", directory: "/home/jacek/vbox-shared")
83+
!2 = !{i32 2, !"cfguard", i32 2}
84+
!3 = !{i32 2, !"Debug Info Version", i32 3}
85+
!4 = !{i32 1, !"wchar_size", i32 2}
86+
!5 = !{i32 8, !"PIC Level", i32 2}
87+
!6 = !{i32 7, !"uwtable", i32 2}
88+
!7 = !{i32 7, !"frame-pointer", i32 3}
89+
!8 = !{!"clang version 22.0.0git"}

0 commit comments

Comments
 (0)