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

From: Carlos Llamas

Date: Mon Mar 09 2026 - 23:31:29 EST


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);