On Fri, Apr 24, 2026 at 11:45:30AM +0200, Peter Zijlstra wrote:
> On Thu, Apr 23, 2026 at 08:38:02PM -0700, Josh Poimboeuf wrote:
>
> > I discovered it's not just FineIBT, it's basically any CALL_PADDING+CFI,
> > like so:
>
> Indeed. This looks good, thanks!
That was unncessarily creating .cfi_sites for the CFI+CALL_THUNKS case,
folding in the below:
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index d8ce7ad8c2c9..7f803796d20c 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -200,8 +200,9 @@ objtool-cmds-$(CONFIG_HAVE_UACCESS_VALIDATION)
+= --uaccess
objtool-cmds-y += $(OBJTOOL_ARGS)
# objtool options
-ifdef CONFIG_CFI
-objtool-opts-$(CONFIG_CALL_PADDING) += --cfi
+ifdef CONFIG_CALL_PADDING
+objtool-opts-$(CONFIG_CFI) += --cfi
+objtool-opts-$(CONFIG_FINEIBT) += --fineibt
endif
ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
objtool-opts-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT) += --mnop
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 790de0cb445d..bd84f5b7c9ee 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -91,7 +91,8 @@ static const struct option check_options[] = {
OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata",
parse_dump),
OPT_GROUP("Options:"),
- OPT_BOOLEAN(0, "cfi", &opts.cfi, "annotate and grow kCFI
preamble symbols (use with --prefix)"),
+ OPT_BOOLEAN(0, "cfi", &opts.cfi, "grow kCFI preamble symbols
(use with --prefix)"),
+ OPT_BOOLEAN(0, "fineibt", &opts.fineibt, "create .cfi_sites
section for FineIBT"),
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on
error"),
OPT_BOOLEAN(0, "backup", &opts.backup, "create backup (.orig)
file on warning/error"),
OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write
modifications"),
@@ -163,6 +164,11 @@ static bool opts_valid(void)
return false;
}
+ if (opts.fineibt && !opts.cfi) {
+ ERROR("--fineibt requires --cfi");
+ return false;
+ }
+
if (opts.disas ||
opts.hack_jump_label ||
opts.hack_noinstr ||
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 11dad0d0b6ae..ac0a48145bf7 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -912,6 +912,29 @@ static int create_ibt_endbr_seal_sections(struct
objtool_file *file)
return 0;
}
+static int grow_cfi_symbols(struct objtool_file *file)
+{
+ struct symbol *sym;
+
+ for_each_sym(file->elf, sym) {
+ if (!is_func_sym(sym) || !strstarts(sym->name, "__cfi_"))
+ continue;
+
+ /*
+ * Grow the __cfi_ symbol to fill the NOP gap between the
+ * 'mov <hash>, %rax' and the start of the function.
+ */
+ if (sym->len == 5) {
+ sym->len += opts.prefix;
+ sym->sym.st_size = sym->len;
+ if (elf_write_symbol(file->elf, sym))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static int create_cfi_sections(struct objtool_file *file)
{
struct section *sec;
@@ -954,17 +977,6 @@ static int create_cfi_sections(struct objtool_file *file)
return -1;
idx++;
-
- /*
- * Grow the __cfi_ symbol to fill the NOP gap between the
- * 'mov <hash>, %rax' and the start of the function.
- */
- if (sym->len == 5) {
- sym->len += opts.prefix;
- sym->sym.st_size = sym->len;
- if (elf_write_symbol(file->elf, sym))
- return -1;
- }
}
return 0;
@@ -4885,12 +4897,6 @@ int check(struct objtool_file *file)
goto out;
}
- if (opts.cfi) {
- ret = create_cfi_sections(file);
- if (ret)
- goto out;
- }
-
if (opts.rethunk) {
ret = create_return_sites_sections(file);
if (ret)
@@ -4909,10 +4915,22 @@ int check(struct objtool_file *file)
goto out;
}
- if (opts.prefix && !opts.cfi) {
- ret = create_prefix_symbols(file);
- if (ret)
- goto out;
+ if (opts.prefix) {
+ if (!opts.cfi) {
+ ret = create_prefix_symbols(file);
+ if (ret)
+ goto out;
+ } else {
+ ret = grow_cfi_symbols(file);
+ if (ret)
+ goto out;
+
+ if (opts.fineibt) {
+ ret = create_cfi_sections(file);
+ if (ret)
+ goto out;
+ }
+ }
}
if (opts.ibt) {
diff --git a/tools/objtool/include/objtool/builtin.h
b/tools/objtool/include/objtool/builtin.h
index b9e229ed4dc0..e844e9c82b7b 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -9,8 +9,8 @@
struct opts {
/* actions: */
- bool cfi;
bool checksum;
+ const char *disas;
bool dump_orc;
bool hack_jump_label;
bool hack_noinstr;
@@ -20,6 +20,7 @@ struct opts {
bool noabs;
bool noinstr;
bool orc;
+ int prefix;
bool retpoline;
bool rethunk;
bool unret;
@@ -27,14 +28,14 @@ struct opts {
bool stackval;
bool static_call;
bool uaccess;
- int prefix;
- const char *disas;
/* options: */
bool backtrace;
bool backup;
+ bool cfi;
const char *debug_checksum;
bool dryrun;
+ bool fineibt;
bool link;
bool mnop;
bool module;