Messages in this thread Patch in this message |  | | Date | Tue, 10 Mar 2026 03:26:44 +0000 | | From | Carlos Llamas <> | | Subject | Re: [PATCH v4 09/17] perf/core: Use static_call to optimize perf_guest_info_callbacks |
| |
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);
|  |