[PATCH v3 45/64] x86/static_call: Define ELF section entry size of static calls

From: Josh Poimboeuf
Date: Thu Jun 26 2025 - 20:05:11 EST


In preparation for the objtool klp diff subcommand, define the entry
size for the .static_call_sites section in its ELF header. This will
allow tooling to extract individual entries.

Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
arch/x86/include/asm/static_call.h | 3 ++-
include/linux/static_call.h | 6 ------
include/linux/static_call_types.h | 6 ++++++
kernel/bounds.c | 4 ++++
tools/include/linux/static_call_types.h | 6 ++++++
tools/objtool/check.c | 11 +++++++++--
6 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/static_call.h b/arch/x86/include/asm/static_call.h
index 41502bd2afd6..e03ad9bbbf59 100644
--- a/arch/x86/include/asm/static_call.h
+++ b/arch/x86/include/asm/static_call.h
@@ -58,7 +58,8 @@
ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)

#define ARCH_ADD_TRAMP_KEY(name) \
- asm(".pushsection .static_call_tramp_key, \"a\" \n" \
+ asm(".pushsection .static_call_tramp_key, \"aM\", @progbits, " \
+ __stringify(STATIC_CALL_TRAMP_KEY_SIZE) "\n" \
".long " STATIC_CALL_TRAMP_STR(name) " - . \n" \
".long " STATIC_CALL_KEY_STR(name) " - . \n" \
".popsection \n")
diff --git a/include/linux/static_call.h b/include/linux/static_call.h
index 78a77a4ae0ea..5210612817f2 100644
--- a/include/linux/static_call.h
+++ b/include/linux/static_call.h
@@ -172,12 +172,6 @@ struct static_call_mod {
struct static_call_site *sites;
};

-/* For finding the key associated with a trampoline */
-struct static_call_tramp_key {
- s32 tramp;
- s32 key;
-};
-
extern void __static_call_update(struct static_call_key *key, void *tramp, void *func);
extern int static_call_mod_init(struct module *mod);
extern int static_call_text_reserved(void *start, void *end);
diff --git a/include/linux/static_call_types.h b/include/linux/static_call_types.h
index 5a00b8b2cf9f..eb772df625d4 100644
--- a/include/linux/static_call_types.h
+++ b/include/linux/static_call_types.h
@@ -34,6 +34,12 @@ struct static_call_site {
s32 key;
};

+/* For finding the key associated with a trampoline */
+struct static_call_tramp_key {
+ s32 tramp;
+ s32 key;
+};
+
#define DECLARE_STATIC_CALL(name, func) \
extern struct static_call_key STATIC_CALL_KEY(name); \
extern typeof(func) STATIC_CALL_TRAMP(name);
diff --git a/kernel/bounds.c b/kernel/bounds.c
index e4c7ded3dc48..21c37e3ea629 100644
--- a/kernel/bounds.c
+++ b/kernel/bounds.c
@@ -14,6 +14,7 @@
#include <linux/log2.h>
#include <linux/spinlock_types.h>
#include <linux/jump_label.h>
+#include <linux/static_call_types.h>

int main(void)
{
@@ -33,6 +34,9 @@ int main(void)
#endif
#if defined(CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE) && defined(CONFIG_JUMP_LABEL)
DEFINE(JUMP_ENTRY_SIZE, sizeof(struct jump_entry));
+#endif
+#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
+ DEFINE(STATIC_CALL_TRAMP_KEY_SIZE, sizeof(struct static_call_tramp_key));
#endif
/* End of constants */

diff --git a/tools/include/linux/static_call_types.h b/tools/include/linux/static_call_types.h
index 5a00b8b2cf9f..eb772df625d4 100644
--- a/tools/include/linux/static_call_types.h
+++ b/tools/include/linux/static_call_types.h
@@ -34,6 +34,12 @@ struct static_call_site {
s32 key;
};

+/* For finding the key associated with a trampoline */
+struct static_call_tramp_key {
+ s32 tramp;
+ s32 key;
+};
+
#define DECLARE_STATIC_CALL(name, func) \
extern struct static_call_key STATIC_CALL_KEY(name); \
extern typeof(func) STATIC_CALL_TRAMP(name);
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3afc748ba516..c3e1ca3dba06 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -650,8 +650,15 @@ static int create_static_call_sections(struct objtool_file *file)
if (!sec)
return -1;

- /* Allow modules to modify the low bits of static_call_site::key */
- sec->sh.sh_flags |= SHF_WRITE;
+ /*
+ * Set SHF_MERGE to prevent tooling from stripping entsize.
+ *
+ * SHF_WRITE would also get set here to allow modules to modify the low
+ * bits of static_call_site::key, but the LLVM linker doesn't allow
+ * SHF_MERGE+SHF_WRITE for whatever reason. That gets fixed up by the
+ * makefiles with CONFIG_NEED_MODULE_PERMISSIONS_FIX.
+ */
+ sec->sh.sh_flags |= SHF_MERGE;

idx = 0;
list_for_each_entry(insn, &file->static_call_list, call_node) {
--
2.49.0