Subject: Re: [PATCH v4 09/17] perf/core: Use static_call to optimize perf_guest_info_callbacks

From: Carlos Llamas <[email-masked]>
Date: Tue, 10 Mar 2026 03:26:44 +0000

On Mon, Mar 09, 2026 at 10:31:56PM +0000, Sami Tolvanen wrote:
> Hi Carlos,
> 
> If you need a stub with a matching CFI type for an arbitrary function,
> perhaps you can do something like this (arm64, untested):
> 
>   #define DEFINE_TYPED_STUB_RET0(name, reffunc)			\
> 	typeof(reffunc) name;					\
> 	__ADDRESSABLE(name);					\
> 	asm(							\
> 	"	" __ALIGN_STR "				\n"	\
> 	"	.4byte	__kcfi_typeid_" #name "		\n"	\
> 	#name ":					\n"	\
> 	"	bti c					\n"	\
> 	"	mov x0, xzr				\n"	\
> 	"	ret					"	\
> 	)
> 
> For the !CONFIG_CFI case, or architectures that implement static calls,
> you can probably just point the stub to __static_call_return0:
> 
>   #define DEFINE_TYPED_STUB_RET0(name, reffunc) \
> 	typeof(reffunc) name __asm__("__static_call_return0")
> 
> Sami

Oh that is pretty cool it worked for me. This is the patch I tested
with. Still needs a bit more plumbing but no more CFI issues.

---
diff --git a/arch/arm64/include/asm/linkage.h b/arch/arm64/include/asm/linkage.h
index 40bd17add539..708dbdf2c9fe 100644
--- a/arch/arm64/include/asm/linkage.h
+++ b/arch/arm64/include/asm/linkage.h
@@ -5,8 +5,10 @@
 #include <asm/assembler.h>
 #endif
 
+#include <linux/stringify.h>
+
 #define __ALIGN		.balign CONFIG_FUNCTION_ALIGNMENT
-#define __ALIGN_STR	".balign " #CONFIG_FUNCTION_ALIGNMENT
+#define __ALIGN_STR	__stringify(__ALIGN)
 
 /*
  * When using in-kernel BTI we need to ensure that PCS-conformant
diff --git a/include/linux/static_call.h b/include/linux/static_call.h
index 78a77a4ae0ea..8b96eb66d2c8 100644
--- a/include/linux/static_call.h
+++ b/include/linux/static_call.h
@@ -184,6 +184,9 @@ extern int static_call_text_reserved(void *start, void *end);
 
 extern long __static_call_return0(void);
 
+#define static_call_update_stub(name)					\
+	static_call_update(name, __static_call_return0)
+
 #define DEFINE_STATIC_CALL(name, _func)					\
 	DECLARE_STATIC_CALL(name, _func);				\
 	struct static_call_key STATIC_CALL_KEY(name) = {		\
@@ -270,6 +273,9 @@ static inline int static_call_text_reserved(void *start, void *end)
 
 extern long __static_call_return0(void);
 
+#define static_call_update_stub(name)					\
+	static_call_update(name, __static_call_return0)
+
 #define EXPORT_STATIC_CALL(name)					\
 	EXPORT_SYMBOL(STATIC_CALL_KEY(name));				\
 	EXPORT_SYMBOL(STATIC_CALL_TRAMP(name))
@@ -306,8 +312,25 @@ static inline long __static_call_return0(void)
 #define DEFINE_STATIC_CALL_NULL(name, _func)				\
 	__DEFINE_STATIC_CALL(name, _func, NULL)
 
+/* Move somewhere under arch/arm64/... */
+#define ARCH_DEFINE_TYPED_STUB_RET0(name, reffunc)			\
+	typeof(reffunc) name;						\
+	__ADDRESSABLE(name);						\
+	asm(								\
+	"	" __ALIGN_STR "\n"					\
+	"	.4byte	__kcfi_typeid_" #name "\n"			\
+	#name ":\n"							\
+	"	bti c\n"						\
+	"	mov x0, xzr\n"						\
+	"	ret"							\
+	);
+
 #define DEFINE_STATIC_CALL_RET0(name, _func)				\
-	__DEFINE_STATIC_CALL(name, _func, __static_call_return0)
+	ARCH_DEFINE_TYPED_STUB_RET0(__static_call_##name, _func)	\
+	__DEFINE_STATIC_CALL(name, _func, __static_call_##name)
+
+#define static_call_update_stub(name)					\
+	static_call_update(name, __static_call_##name)
 
 static inline void __static_call_nop(void) { }
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1f5699b339ec..b60a1991474b 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7701,10 +7701,10 @@ void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
 		return;
 
 	rcu_assign_pointer(perf_guest_cbs, NULL);
-	static_call_update(__perf_guest_state, (void *)&__static_call_return0);
-	static_call_update(__perf_guest_get_ip, (void *)&__static_call_return0);
-	static_call_update(__perf_guest_handle_intel_pt_intr, (void *)&__static_call_return0);
-	static_call_update(__perf_guest_handle_mediated_pmi, (void *)&__static_call_return0);
+	static_call_update_stub(__perf_guest_state);
+	static_call_update_stub(__perf_guest_get_ip);
+	static_call_update_stub(__perf_guest_handle_intel_pt_intr);
+	static_call_update_stub(__perf_guest_handle_mediated_pmi);
 	synchronize_rcu();
 }
 EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);