Live Patching
 help / color / mirror / Atom feed
* Re: [PATCH 07/48] objtool/klp: Don't correlate absolute symbols
From: Miroslav Benes @ 2026-04-24 12:04 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <1dc8b127ff0b1252e53bb7e6130ed46c60f57c25.1776916871.git.jpoimboe@kernel.org>

On Wed, 22 Apr 2026 21:03:35 -0700, Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> Some arch/x86/crypto/*.S files define local .set/.equ constants that get
> duplicated in vmlinux.o.  This causes klp-diff to fail with "Multiple
> correlation candidates" errors since it can't uniquely match these
> between orig and patched builds.
> 
> Skip ABS symbols in dont_correlate().  They're purely compile-time
> assembly constants that are never referenced by relocations, so they
> don't need correlation.
> 
> [...]

Reviewed-by: Miroslav Benes <mbenes@suse.cz>

-- 
Miroslav


^ permalink raw reply

* Re: [PATCH 06/48] objtool/klp: Don't correlate rodata symbols
From: Miroslav Benes @ 2026-04-24 11:54 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <602e405888ab38cd08de4375060b56db0965651d.1776916871.git.jpoimboe@kernel.org>

On Wed, 22 Apr 2026 21:03:34 -0700, Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
> index ea9ccf8c4ea9..f6597015b33b 100644
> --- a/tools/objtool/klp-diff.c
> +++ b/tools/objtool/klp-diff.c
> @@ -374,6 +374,7 @@ static bool dont_correlate(struct symbol *sym)
>  	       is_uncorrelated_static_local(sym) ||
>  	       is_clang_tmp_label(sym) ||
>  	       is_string_sec(sym->sec) ||
> +	       is_rodata_sec(sym->sec) ||

Sashiko comments here [1] that the check is suddenly to broad and it
covers also global rodata symbols which might then be skipped in
klp_reloc_needed(). I think it has a point.

[1] https://sashiko.dev/#/patchset/cover.1776916871.git.jpoimboe%40kernel.org?part=6

-- 
Miroslav


^ permalink raw reply

* Re: [PATCH 05/48] objtool: Move mark_rodata() to elf.c
From: Miroslav Benes @ 2026-04-24 11:36 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <c32b3d8d0770c93f8c0d8e4a989f2f43c29e9a5f.1776916871.git.jpoimboe@kernel.org>

On Wed, 22 Apr 2026 21:03:33 -0700, Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> Move the sec->rodata marking from check.c to elf.c so it's set during
> ELF reading rather than during the check pipeline.  This makes the
> rodata flag available to all objtool users, including klp-diff which
> reads ELF files directly without running check().
> 
> Add an is_rodata_sec() helper to elf.h for consistency with
> is_text_sec() and is_string_sec().
> 
> [...]

Reviewed-by: Miroslav Benes <mbenes@suse.cz>

-- 
Miroslav


^ permalink raw reply

* Re: [PATCH 04/48] objtool/klp: Ignore __UNIQUE_ID_*() PCI stub functions
From: Miroslav Benes @ 2026-04-24 11:26 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: Song Liu, x86, linux-kernel, live-patching, Peter Zijlstra,
	Joe Lawrence, Petr Mladek
In-Reply-To: <l6spha5o4wl5ksczovjwxghb5lhe4parswxhtzk2ac4inxmmhc@h2hiehwqkgmx>

[-- Attachment #1: Type: text/plain, Size: 2059 bytes --]

On Thu, 23 Apr 2026, Josh Poimboeuf wrote:

> On Thu, Apr 23, 2026 at 02:33:00PM -0700, Song Liu wrote:
> > On Thu, Apr 23, 2026 at 12:31 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > >
> > > On Thu, Apr 23, 2026 at 12:05:03PM -0700, Song Liu wrote:
> > > > On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > > > >
> > > > > With Clang LTO enabled, DECLARE_PCI_FIXUP_SECTION() uses __UNIQUE_ID()
> > > > > to generate uniquely named wrapper functions, which are being reported
> > > > > as new functions and unnecessarily included in the patch module:
> > > > >
> > > > >   vmlinux.o: new function: __UNIQUE_ID_quirk_f0_vpd_link_661
> > > > >
> > > > > These stub functions only exist to make the compiler happy.  Just ignore
> > > > > them along with any other dont_correlate() symbols.  Note that
> > > > > dont_correlate() already includes prefix functions.
> > > > >
> > > > > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> > > >
> > > > The actual change appears to be much bigger than the subject line.
> > > > Maybe rephrase it a bit?
> > >
> > > Hm, in fact this is a relic from a previous iteration of the patches: it
> > > longer fixes what it claims to fix, as __UNIQUE_ID_ (other than
> > > __ADDRESSABLE()) are now correlated.  The claimed issue actually gets
> > > fixed later by the rewriting of the correlation algorithm.
> > >
> > > That said, I still think the below is needed, I just need to rewrite the
> > > commit log.
> > 
> > Agreed.
> 
> From: Josh Poimboeuf <jpoimboe@kernel.org>
> Subject: [PATCH] objtool/klp: Don't report uncorrelated functions as new
> 
> Clang LTO uses __UNIQUE_ID() to generate some uniquely named wrapper
> functions, like initstubs.  If they're uncorrelated, prevent them from
> being reported as new functions and included unnecessarily.
> 
> Note that dont_correlate() already includes prefix functions, so prefix
> functions are still being ignored here.
> 
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

Reviewed-by: Miroslav Benes <mbenes@suse.cz>

M

^ permalink raw reply

* Re: [PATCH 45/48] x86/Kconfig: Enable CONFIG_PREFIX_SYMBOLS for FineIBT
From: Peter Zijlstra @ 2026-04-24  9:45 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Joe Lawrence, Song Liu,
	Miroslav Benes, Petr Mladek
In-Reply-To: <c7vi7gpfrybjmngjoqu2jmirh6jp53bpw5edeoeupz5gwhw6gx@fvcn6l6vgl47>

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!

> From: Josh Poimboeuf <jpoimboe@kernel.org>
> Subject: [PATCH] objtool: Grow __cfi_* symbols for all kCFI+CALL_PADDING
> 
> For all CONFIG_CFI+CONFIG_CALL_PADDING configs, the __cfi_ symbols only
> cover the 5-byte kCFI type hash.  After that there also N bytes of NOP
> padding between the hash and the function entry which aren't associated
> with any symbol.
> 
> The NOPs can be replaced with actual code at runtime.  Without a symbol,
> unwinders and tooling have no way of knowing where those bytes belong.
> 
> Grow the existing __cfi_* symbols to fill that gap.
> 
> Also, CONFIG_PREFIX_SYMBOLS has no reason to exist: CONFIG_CALL_PADDING
> is what causes the compiler to emit NOP padding before function entry
> (via -fpatchable-function-entry), so it's the right condition for
> creating prefix symbols.
> 
> Remove CONFIG_PREFIX_SYMBOLS, as it's no longer needed.  Simplify the
> LONGEST_SYM_KUNIT_TEST dependency accordingly.
> 
> Update the --cfi and --prefix usage strings to reflect their current
> scope.
> 
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> ---
>  arch/x86/Kconfig                    |  4 ----
>  lib/Kconfig.debug                   |  2 +-
>  scripts/Makefile.lib                |  5 ++++-
>  tools/objtool/builtin-check.c       |  9 +++++++--
>  tools/objtool/check.c               | 13 ++++++++++++-
>  tools/objtool/elf.c                 | 20 ++++++++++++++++++++
>  tools/objtool/include/objtool/elf.h |  1 +
>  7 files changed, 45 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index f3f7cb01d69d..3eb3c48d764a 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2437,10 +2437,6 @@ config CALL_THUNKS
>  	def_bool n
>  	select CALL_PADDING
>  
> -config PREFIX_SYMBOLS
> -	def_bool y
> -	depends on CALL_PADDING && !CFI
> -
>  menuconfig CPU_MITIGATIONS
>  	bool "Mitigations for CPU vulnerabilities"
>  	default y
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 77c3774c1c49..8b41720069b3 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -3059,7 +3059,7 @@ config FORTIFY_KUNIT_TEST
>  config LONGEST_SYM_KUNIT_TEST
>  	tristate "Test the longest symbol possible" if !KUNIT_ALL_TESTS
>  	depends on KUNIT && KPROBES
> -	depends on !PREFIX_SYMBOLS && !CFI && !GCOV_KERNEL
> +	depends on !CALL_PADDING && !GCOV_KERNEL
>  	default KUNIT_ALL_TESTS
>  	help
>  	  Tests the longest symbol possible
> diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
> index 0718e39cedda..562d89f051f0 100644
> --- a/scripts/Makefile.lib
> +++ b/scripts/Makefile.lib
> @@ -187,7 +187,10 @@ objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK)		+= --hacks=jump_label
>  objtool-args-$(CONFIG_HAVE_NOINSTR_HACK)		+= --hacks=noinstr
>  objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING)	+= --hacks=skylake
>  objtool-args-$(CONFIG_X86_KERNEL_IBT)			+= --ibt
> -objtool-args-$(CONFIG_FINEIBT)				+= --cfi
> +objtool-args-$(CONFIG_CALL_PADDING)			+= --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
> +ifdef CONFIG_CFI
> +objtool-args-$(CONFIG_CALL_PADDING)			+= --cfi
> +endif
>  objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL)	+= --mcount
>  ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
>  objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT)		+= --mnop
> diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
> index ec7f10a5ef19..254ceb6b0e2c 100644
> --- a/tools/objtool/builtin-check.c
> +++ b/tools/objtool/builtin-check.c
> @@ -73,7 +73,6 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)
>  
>  static const struct option check_options[] = {
>  	OPT_GROUP("Actions:"),
> -	OPT_BOOLEAN(0,		 "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"),
>  	OPT_STRING_OPTARG('d',	 "disas", &opts.disas, "function-pattern", "disassemble functions", "*"),
>  	OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks),
>  	OPT_BOOLEAN('i',	 "ibt", &opts.ibt, "validate and annotate IBT"),
> @@ -84,7 +83,7 @@ static const struct option check_options[] = {
>  	OPT_BOOLEAN('r',	 "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
>  	OPT_BOOLEAN(0,		 "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
>  	OPT_BOOLEAN(0,		 "unret", &opts.unret, "validate entry unret placement"),
> -	OPT_INTEGER(0,		 "prefix", &opts.prefix, "generate prefix symbols"),
> +	OPT_INTEGER(0,		 "prefix", &opts.prefix, "generate or grow prefix symbols for N-byte function padding"),
>  	OPT_BOOLEAN('l',	 "sls", &opts.sls, "validate straight-line-speculation mitigations"),
>  	OPT_BOOLEAN('s',	 "stackval", &opts.stackval, "validate frame pointer rules"),
>  	OPT_BOOLEAN('t',	 "static-call", &opts.static_call, "annotate static calls"),
> @@ -92,6 +91,7 @@ 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,		 "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 +163,11 @@ static bool opts_valid(void)
>  		return false;
>  	}
>  
> +	if (opts.cfi && !opts.prefix) {
> +		ERROR("--cfi requires --prefix");
> +		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 410061aeed26..fb24fd284e09 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -923,6 +923,17 @@ 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;
> @@ -4927,7 +4938,7 @@ int check(struct objtool_file *file)
>  			goto out;
>  	}
>  
> -	if (opts.prefix) {
> +	if (opts.prefix && !opts.cfi) {
>  		ret = create_prefix_symbols(file);
>  		if (ret)
>  			goto out;
> diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
> index 2ca1151de815..ede87dd9644c 100644
> --- a/tools/objtool/elf.c
> +++ b/tools/objtool/elf.c
> @@ -983,6 +983,26 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name,
>  	return sym;
>  }
>  
> +int elf_write_symbol(struct elf *elf, struct symbol *sym)
> +{
> +	struct section *symtab, *symtab_shndx;
> +
> +	symtab = find_section_by_name(elf, ".symtab");
> +	if (!symtab) {
> +		ERROR("no .symtab");
> +		return -1;
> +	}
> +
> +	symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
> +
> +	if (elf_update_symbol(elf, symtab, symtab_shndx, sym))
> +		return -1;
> +
> +	mark_sec_changed(elf, symtab, true);
> +
> +	return 0;
> +}
> +
>  struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec)
>  {
>  	struct symbol *sym = calloc(1, sizeof(*sym));
> diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
> index 0fd1a9b563e9..4c8a67a68063 100644
> --- a/tools/objtool/include/objtool/elf.h
> +++ b/tools/objtool/include/objtool/elf.h
> @@ -199,6 +199,7 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
>  				      struct symbol *sym,
>  				      s64 addend);
>  
> +int elf_write_symbol(struct elf *elf, struct symbol *sym);
>  int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset,
>  		   unsigned int len, const char *insn);
>  
> -- 
> 2.53.0
> 

^ permalink raw reply

* Re: [PATCH 03/48] objtool/klp: Don't correlate __ADDRESSABLE() symbols
From: Miroslav Benes @ 2026-04-24  9:34 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Song Liu, Petr Mladek
In-Reply-To: <177702262868.199199.17632749620515020845.b4-review@b4>

On Fri, 24 Apr 2026, Miroslav Benes wrote:

> On Wed, 22 Apr 2026 21:03:31 -0700, Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > Symbols created by __ADDRESSABLE() are only used to convince the
> > toolchain not to optimize out the referenced symbol.
> 
> Reviewed-by: Miroslav Benes <mbenes@suse.cz>

Looking at it again... wouldn't it be better to address this in 
is_special_section() which is looking at .discard.addressable already 
(only the outcome is different)?

Miroslav

^ permalink raw reply

* Re: [PATCH 03/48] objtool/klp: Don't correlate __ADDRESSABLE() symbols
From: Miroslav Benes @ 2026-04-24  9:23 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <ea9af1b6136e9aa11589e592d0fc59e4ef414579.1776916871.git.jpoimboe@kernel.org>

On Wed, 22 Apr 2026 21:03:31 -0700, Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> Symbols created by __ADDRESSABLE() are only used to convince the
> toolchain not to optimize out the referenced symbol.

Reviewed-by: Miroslav Benes <mbenes@suse.cz>

-- 
Miroslav


^ permalink raw reply

* Re: [PATCH 02/48] objtool/klp: Fix .data..once static local non-correlation
From: Miroslav Benes @ 2026-04-24  9:21 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <f34990d29dd7642ada7843613c96c563043c28a5.1776916871.git.jpoimboe@kernel.org>

On Wed, 22 Apr 2026 21:03:30 -0700, Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> While there was once a section named .data.once, it has since been
> renamed to .data..once with commit dbefa1f31a91 ("Rename .data.once to
> .data..once to fix resetting WARN*_ONCE").  Fix it.

Reviewed-by: Miroslav Benes <mbenes@suse.cz>

-- 
Miroslav


^ permalink raw reply

* Re: [PATCH 01/48] objtool/klp: Fix is_uncorrelated_static_local() for Clang
From: Miroslav Benes @ 2026-04-24  9:17 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <f2a97da92796708f77c6fb3e07816f84874b79a4.1776916871.git.jpoimboe@kernel.org>

On Wed, 22 Apr 2026 21:03:29 -0700, Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> For naming function-local static locals, GCC uses <var>.<id>, e.g.
> __already_done.15, while Clang uses <func>.<var> with optional .<id>,
> e.g. create_worker.__already_done.111
> 
> The existing is_uncorrelated_static_local() check only matches the GCC
> convention where the variable name is a prefix.  Handle both cases by
> checking for a prefix match (GCC) and by checking after the first dot
> separator (Clang).
> 
> [...]

Reviewed-by: Miroslav Benes <mbenes@suse.cz>

-- 
Miroslav


^ permalink raw reply

* Re: [PATCH v2 2/2] module/kallsyms: sort function symbols and use binary search
From: Stanislaw Gruszka @ 2026-04-24  9:13 UTC (permalink / raw)
  To: Petr Pavlu
  Cc: linux-modules, Sami Tolvanen, Luis Chamberlain, linux-kernel,
	linux-trace-kernel, live-patching, Daniel Gomez, Aaron Tomlin,
	Steven Rostedt, Masami Hiramatsu, Jordan Rome, Viktor Malik
In-Reply-To: <11c8e139-f9f3-4b22-863a-4e021a3947e7@suse.com>

Hi Petr,

thanks for the review.

On Thu, Apr 23, 2026 at 04:00:04PM +0200, Petr Pavlu wrote:
> On 3/27/26 12:00 PM, Stanislaw Gruszka wrote:
> > Module symbol lookup via find_kallsyms_symbol() performs a linear scan
> > over the entire symtab when resolving an address. The number of symbols
> > in module symtabs has grown over the years, largely due to additional
> > metadata in non-standard sections, making this lookup very slow.
> > 
> > Improve this by separating function symbols during module load, placing
> > them at the beginning of the symtab, sorting them by address, and using
> > binary search when resolving addresses in module text.
> > 
> > This also should improve times for linear symbol name lookups, as valid
> > function symbols are now located at the beginning of the symtab.
> > 
> > The cost of sorting is small relative to module load time. In repeated
> > module load tests [1], depending on .config options, this change
> > increases load time between 2% and 4%. With cold caches, the difference
> > is not measurable, as memory access latency dominates.
> > 
> > The sorting theoretically could be done in compile time, but much more
> > complicated as we would have to simulate kernel addresses resolution
> > for symbols, and then correct relocation entries. That would be risky
> > if get out of sync.
> > 
> > The improvement can be observed when listing ftrace filter functions.
> > 
> > Before:
> > 
> > root@nano:~# time cat /sys/kernel/tracing/available_filter_functions | wc -l
> > 74908
> > 
> > real	0m1.315s
> > user	0m0.000s
> > sys	0m1.312s
> > 
> > After:
> > 
> > root@nano:~# time cat /sys/kernel/tracing/available_filter_functions | wc -l
> > 74911
> > 
> > real	0m0.167s
> > user	0m0.004s
> > sys	0m0.175s
> > 
> > (there are three more symbols introduced by the patch)
> > 
> > For livepatch modules, the symtab layout is preserved and the existing
> > linear search is used. For this case, it should be possible to keep
> > the original ELF symtab instead of copying it 1:1, but that is outside
> > the scope of this patch.
> > 
> > Link: https://gist.github.com/sgruszka/09f3fb1dad53a97b1aad96e1927ab117 [1]
> > Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
> 
> Sorry for the delay reviewing this patch.

No problem.

> > ---
> > v1 -> v2: 
> >  - fix searching data symbols for CONFIG_KALLSYMS_ALL
> >  - use kallsyms_symbol_value() in elf_sym_cmp()
> > 
> >  include/linux/module.h   |   1 +
> >  kernel/module/internal.h |   1 +
> >  kernel/module/kallsyms.c | 171 +++++++++++++++++++++++++++++----------
> >  3 files changed, 130 insertions(+), 43 deletions(-)
> > 
> > diff --git a/include/linux/module.h b/include/linux/module.h
> > index ac254525014c..67c053afa882 100644
> > --- a/include/linux/module.h
> > +++ b/include/linux/module.h
> > @@ -379,6 +379,7 @@ struct module_memory {
> >  struct mod_kallsyms {
> >  	Elf_Sym *symtab;
> >  	unsigned int num_symtab;
> > +	unsigned int num_func_syms;
> >  	char *strtab;
> >  	char *typetab;
> >  };
> > diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> > index 618202578b42..6a4d498619b1 100644
> > --- a/kernel/module/internal.h
> > +++ b/kernel/module/internal.h
> > @@ -73,6 +73,7 @@ struct load_info {
> >  	bool sig_ok;
> >  #ifdef CONFIG_KALLSYMS
> >  	unsigned long mod_kallsyms_init_off;
> > +	unsigned long num_func_syms;
> >  #endif
> >  #ifdef CONFIG_MODULE_DECOMPRESS
> >  #ifdef CONFIG_MODULE_STATS
> > diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
> > index f23126d804b2..d69e99e67707 100644
> > --- a/kernel/module/kallsyms.c
> > +++ b/kernel/module/kallsyms.c
> > @@ -10,6 +10,7 @@
> >  #include <linux/kallsyms.h>
> >  #include <linux/buildid.h>
> >  #include <linux/bsearch.h>
> > +#include <linux/sort.h>
> >  #include "internal.h"
> >  
> >  /* Lookup exported symbol in given range of kernel_symbols */
> > @@ -103,6 +104,95 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
> >  	return true;
> >  }
> >  
> > +static inline bool is_func_symbol(const Elf_Sym *sym)
> > +{
> > +	return sym->st_shndx != SHN_UNDEF && sym->st_size != 0 &&
> > +	       ELF_ST_TYPE(sym->st_info) == STT_FUNC;
> > +}
> > +
> > +static unsigned int bsearch_func_symbol(struct mod_kallsyms *kallsyms,
> > +					unsigned long addr,
> > +					unsigned long *bestval,
> > +					unsigned long *nextval)
> > +
> > +{
> > +	unsigned int mid, low = 1, high = kallsyms->num_func_syms + 1;
> > +	unsigned int best = 0;
> > +	unsigned long thisval;
> > +
> > +	while (low < high) {
> > +		mid = low + (high - low) / 2;
> > +		thisval = kallsyms_symbol_value(&kallsyms->symtab[mid]);
> > +
> > +		if (thisval <= addr) {
> > +			*bestval = thisval;
> > +			best = mid;
> > +			low = mid + 1;
> 
> If thisval == addr, the search moves to the right and finds the last
> symbol with the same address. I believe it should do the opposite and
> return the first symbol to match the behavior of
> search_kallsyms_symbol().

In the case of multiple symbols sharing the same address, we have
to pick one and ignore the others. I don’t think it matters much which
one is chosen in practice. Also, I expect function symbol addresses
to be unique, so this shouldn’t be a real issue.

> > +		} else {
> > +			*nextval = thisval;
> > +			high = mid;
> > +		}
> > +	}
> > +
> > +	return best;
> > +}
> > +
> > +static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms,
> > +					unsigned int symnum)
> > +{
> > +	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
> > +}
> > +
> > +static unsigned int search_kallsyms_symbol(struct mod_kallsyms *kallsyms,
> > +					   unsigned long addr,
> > +					   unsigned long *bestval,
> > +					   unsigned long *nextval)
> > +{
> > +	unsigned int i, best = 0;
> > +
> > +	/*
> > +	 * Scan for closest preceding symbol and next symbol. (ELF starts
> > +	 * real symbols at 1). Skip the initial function symbols range
> > +	 * if num_func_syms is non-zero, those are handled separately for
> > +	 * the core TEXT segment lookup.
> > +	 */
> > +	for (i = 1 + kallsyms->num_func_syms; i < kallsyms->num_symtab; i++) {
> > +		const Elf_Sym *sym = &kallsyms->symtab[i];
> > +		unsigned long thisval = kallsyms_symbol_value(sym);
> > +
> > +		if (sym->st_shndx == SHN_UNDEF)
> > +			continue;
> > +
> > +		/*
> > +		 * We ignore unnamed symbols: they're uninformative
> > +		 * and inserted at a whim.
> > +		 */
> > +		if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
> > +		    is_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
> > +			continue;
> > +
> > +		if (thisval <= addr && thisval > *bestval) {
> > +			best = i;
> > +			*bestval = thisval;
> > +		}
> > +		if (thisval > addr && thisval < *nextval)
> > +			*nextval = thisval;
> > +	}
> > +
> > +	return best;
> > +}
> > +
> > +static int elf_sym_cmp(const void *a, const void *b)
> > +{
> > +	unsigned long val_a = kallsyms_symbol_value((const Elf_Sym *)a);
> > +	unsigned long val_b = kallsyms_symbol_value((const Elf_Sym *)b);
> > +
> > +	if (val_a < val_b)
> > +		return -1;
> > +
> > +	return val_a > val_b;
> 
> Does this comparison function and the sort() call result in stable
> sorting? If val_a and val_b are the same, the sorting should preserve
> the original order.

The kernel’s sort() implementation is not stable.

> > +}
> > +
> >  /*
> >   * We only allocate and copy the strings needed by the parts of symtab
> >   * we keep.  This is simple, but has the effect of making multiple
> > @@ -115,9 +205,10 @@ void layout_symtab(struct module *mod, struct load_info *info)
> >  	Elf_Shdr *symsect = info->sechdrs + info->index.sym;
> >  	Elf_Shdr *strsect = info->sechdrs + info->index.str;
> >  	const Elf_Sym *src;
> > -	unsigned int i, nsrc, ndst, strtab_size = 0;
> > +	unsigned int i, nsrc, ndst, nfunc, strtab_size = 0;
> >  	struct module_memory *mod_mem_data = &mod->mem[MOD_DATA];
> >  	struct module_memory *mod_mem_init_data = &mod->mem[MOD_INIT_DATA];
> > +	bool is_lp_mod = is_livepatch_module(mod);
> >  
> >  	/* Put symbol section at end of init part of module. */
> >  	symsect->sh_flags |= SHF_ALLOC;
> > @@ -129,12 +220,14 @@ void layout_symtab(struct module *mod, struct load_info *info)
> >  	nsrc = symsect->sh_size / sizeof(*src);
> >  
> >  	/* Compute total space required for the core symbols' strtab. */
> > -	for (ndst = i = 0; i < nsrc; i++) {
> > -		if (i == 0 || is_livepatch_module(mod) ||
> > +	for (ndst = nfunc = i = 0; i < nsrc; i++) {
> > +		if (i == 0 || is_lp_mod ||
> >  		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
> >  				   info->index.pcpu)) {
> >  			strtab_size += strlen(&info->strtab[src[i].st_name]) + 1;
> >  			ndst++;
> > +			if (!is_lp_mod && is_func_symbol(src + i))
> > +				nfunc++;
> >  		}
> >  	}
> >  
> > @@ -156,6 +249,7 @@ void layout_symtab(struct module *mod, struct load_info *info)
> >  	mod_mem_init_data->size = ALIGN(mod_mem_init_data->size,
> >  					__alignof__(struct mod_kallsyms));
> >  	info->mod_kallsyms_init_off = mod_mem_init_data->size;
> > +	info->num_func_syms = nfunc;
> >  
> >  	mod_mem_init_data->size += sizeof(struct mod_kallsyms);
> >  	info->init_typeoffs = mod_mem_init_data->size;
> > @@ -169,7 +263,7 @@ void layout_symtab(struct module *mod, struct load_info *info)
> >   */
> >  void add_kallsyms(struct module *mod, const struct load_info *info)
> >  {
> > -	unsigned int i, ndst;
> > +	unsigned int i, di, nfunc, ndst;
> >  	const Elf_Sym *src;
> >  	Elf_Sym *dst;
> >  	char *s;
> > @@ -178,6 +272,7 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
> >  	void *data_base = mod->mem[MOD_DATA].base;
> >  	void *init_data_base = mod->mem[MOD_INIT_DATA].base;
> >  	struct mod_kallsyms *kallsyms;
> > +	bool is_lp_mod = is_livepatch_module(mod);
> >  
> >  	kallsyms = init_data_base + info->mod_kallsyms_init_off;
> 
> This code is followed by the initialization of kallsyms:
> 
> 	kallsyms->symtab = (void *)symsec->sh_addr;
> 	kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
> 	/* Make sure we get permanent strtab: don't use info->strtab. */
> 	kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
> 	kallsyms->typetab = init_data_base + info->init_typeoffs;
> 
> I suggest adding 'kallsyms->num_func_syms = 0;' after the initialization
> of kallsyms->num_symtab.

I relied on zeroed memory initialization, but I can add this explicitly
for clarity.

> > @@ -194,19 +289,28 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
> >  	mod->core_kallsyms.symtab = dst = data_base + info->symoffs;
> >  	mod->core_kallsyms.strtab = s = data_base + info->stroffs;
> >  	mod->core_kallsyms.typetab = data_base + info->core_typeoffs;
> > +
> >  	strtab_size = info->core_typeoffs - info->stroffs;
> >  	src = kallsyms->symtab;
> > -	for (ndst = i = 0; i < kallsyms->num_symtab; i++) {
> > +	ndst = info->num_func_syms + 1;
> > +
> > +	for (nfunc = i = 0; i < kallsyms->num_symtab; i++) {
> >  		kallsyms->typetab[i] = elf_type(src + i, info);
> > -		if (i == 0 || is_livepatch_module(mod) ||
> > +		if (i == 0 || is_lp_mod ||
> >  		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
> >  				   info->index.pcpu)) {
> >  			ssize_t ret;
> >  
> > -			mod->core_kallsyms.typetab[ndst] =
> > -				kallsyms->typetab[i];
> > -			dst[ndst] = src[i];
> > -			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
> > +			if (i == 0)
> > +				di = 0;
> > +			else if (!is_lp_mod && is_func_symbol(src + i))
> > +				di = 1 + nfunc++;
> > +			else
> > +				di = ndst++;
> > +
> > +			mod->core_kallsyms.typetab[di] = kallsyms->typetab[i];
> > +			dst[di] = src[i];
> > +			dst[di].st_name = s - mod->core_kallsyms.strtab;
> >  			ret = strscpy(s, &kallsyms->strtab[src[i].st_name],
> >  				      strtab_size);
> >  			if (ret < 0)
> > @@ -216,9 +320,13 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
> >  		}
> >  	}
> >  
> > +	WARN_ON_ONCE(nfunc != info->num_func_syms);
> > +	sort(dst + 1, nfunc, sizeof(Elf_Sym), elf_sym_cmp, NULL);
> > +
> 
> The code sorts mod->core_kallsyms.symtab but mod->core_kallsyms.typetab
> is not reordered accordingly.

Right, but for function symbols the typetab entries are all 't',
so swapping them does not change the type value. The 'T' vs 't'
distinction is handled later when printing (based on export status).
But the comment explaining skiping adjusting of
mod->core_kallsyms.typetab is needed.

> >  	/* Set up to point into init section. */
> >  	rcu_assign_pointer(mod->kallsyms, kallsyms);
> >  	mod->core_kallsyms.num_symtab = ndst;
> > +	mod->core_kallsyms.num_func_syms = nfunc;
> >  }
> >  
> >  #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> > @@ -241,11 +349,6 @@ void init_build_id(struct module *mod, const struct load_info *info)
> >  }
> >  #endif
> >  
> > -static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
> > -{
> > -	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
> > -}
> > -
> >  /*
> >   * Given a module and address, find the corresponding symbol and return its name
> >   * while providing its size and offset if needed.
> > @@ -255,7 +358,10 @@ static const char *find_kallsyms_symbol(struct module *mod,
> >  					unsigned long *size,
> >  					unsigned long *offset)
> >  {
> > -	unsigned int i, best = 0;
> > +	unsigned int (*search)(struct mod_kallsyms *kallsyms,
> > +			       unsigned long addr, unsigned long *bestval,
> > +			       unsigned long *nextval);
> > +	unsigned int best;
> >  	unsigned long nextval, bestval;
> >  	struct mod_kallsyms *kallsyms = rcu_dereference(mod->kallsyms);
> >  	struct module_memory *mod_mem = NULL;
> > @@ -266,6 +372,11 @@ static const char *find_kallsyms_symbol(struct module *mod,
> >  			continue;
> >  #endif
> >  		if (within_module_mem_type(addr, mod, type)) {
> > +			if (type == MOD_TEXT && kallsyms->num_func_syms > 0)
> > +				search = bsearch_func_symbol;
> 
> I'm not sure if it is ok to limit the search only to function symbols
> when the address lies in MOD_TEXT. The text can theoretically contain
> non-function symbols.

Yes, the patch assumes that the only valid symbols in the MOD_TEXT
are functions. If there are defined OBJECT symbols in .text, the patch
would break lookup for those.

While it’s theoretically possible (e.g. hand-written assembly placing
data in .text ?), I’m not sure this is a practical concern. In general,
having data in executable segments is discouraged for security reasons. 

> Could this optimization be adjusted to sort all
> MOD_TEXT symbols (excluding anonymous and mapping symbols) and move them
> to the front of the symbol table?

That’s possible. We could track .text sections indices in
__layout_sections() and include all valid symbols from those sections,
and also reorder typetab accordingly.

However, this adds complexity. I would prefer to first confirm whether
OBJECT symbols in MOD_TEXT is a real issue before going in that direction.

Regards
Stanislaw

> > +			else
> > +				search = search_kallsyms_symbol;
> > +
> >  			mod_mem = &mod->mem[type];
> >  			break;
> >  		}
> > @@ -278,33 +389,7 @@ static const char *find_kallsyms_symbol(struct module *mod,
> >  	nextval = (unsigned long)mod_mem->base + mod_mem->size;
> >  	bestval = (unsigned long)mod_mem->base - 1;
> >  
> > -	/*
> > -	 * Scan for closest preceding symbol, and next symbol. (ELF
> > -	 * starts real symbols at 1).
> > -	 */
> > -	for (i = 1; i < kallsyms->num_symtab; i++) {
> > -		const Elf_Sym *sym = &kallsyms->symtab[i];
> > -		unsigned long thisval = kallsyms_symbol_value(sym);
> > -
> > -		if (sym->st_shndx == SHN_UNDEF)
> > -			continue;
> > -
> > -		/*
> > -		 * We ignore unnamed symbols: they're uninformative
> > -		 * and inserted at a whim.
> > -		 */
> > -		if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
> > -		    is_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
> > -			continue;
> > -
> > -		if (thisval <= addr && thisval > bestval) {
> > -			best = i;
> > -			bestval = thisval;
> > -		}
> > -		if (thisval > addr && thisval < nextval)
> > -			nextval = thisval;
> > -	}
> > -
> > +	best = search(kallsyms, addr, &bestval, &nextval);
> >  	if (!best)
> >  		return NULL;
> >  
> 
> -- 
> Thanks,
> Petr

^ permalink raw reply

* Re: [PATCH 45/48] x86/Kconfig: Enable CONFIG_PREFIX_SYMBOLS for FineIBT
From: David Laight @ 2026-04-24  9:02 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Josh Poimboeuf, x86, linux-kernel, live-patching, Joe Lawrence,
	Song Liu, Miroslav Benes, Petr Mladek
In-Reply-To: <20260423162902.GC641209@noisy.programming.kicks-ass.net>

On Thu, 23 Apr 2026 18:29:02 +0200
Peter Zijlstra <peterz@infradead.org> wrote:

> On Thu, Apr 23, 2026 at 09:23:12AM -0700, Josh Poimboeuf wrote:
> 
> > > > Sorry, how do you get 64 here?  
> > > 
> > > DEBUG_FORCE_FUNCTION_ALIGNMENT_64B=y  
> > 
> > Ok, so in that case it would be 5-byte cfi symbol and 59-byte NOP gap.
> > Or a 64-byte pfx for the !CFI case.  
> 
> Just so.
> 

Isn't there also an average of 32 NOP bytes to align the 'gap' on a 64
byte boundary?
Has anyone looked at changing clang to take a parameter for the size
of the gap?
That would significantly reduce the overhead for small functions.

	David

^ permalink raw reply

* Re: [PATCH 45/48] x86/Kconfig: Enable CONFIG_PREFIX_SYMBOLS for FineIBT
From: Josh Poimboeuf @ 2026-04-24  3:38 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: x86, linux-kernel, live-patching, Joe Lawrence, Song Liu,
	Miroslav Benes, Petr Mladek
In-Reply-To: <d5ex4fawfive7trcvhsptu2dwr5l5yru5q6bsx5zh3sqlle26u@navby7ru5z6t>

On Thu, Apr 23, 2026 at 04:30:47PM -0700, Josh Poimboeuf wrote:
> On Thu, Apr 23, 2026 at 09:23:12AM -0700, Josh Poimboeuf wrote:
> > On Thu, Apr 23, 2026 at 05:19:25PM +0200, Peter Zijlstra wrote:
> > > On Thu, Apr 23, 2026 at 08:16:08AM -0700, Josh Poimboeuf wrote:
> > > > On Thu, Apr 23, 2026 at 10:47:58AM +0200, Peter Zijlstra wrote:
> > > > > On Wed, Apr 22, 2026 at 09:04:13PM -0700, Josh Poimboeuf wrote:
> > > > > > PREFIX_SYMBOLS has a !CFI dependency because the compiler already
> > > > > > generates __cfi_ prefix symbols for kCFI builds, so objtool-generated
> > > > > > __pfx_ symbols were considered redundant.
> > > > > > 
> > > > > > However, the __cfi_ symbols only cover the 5-byte kCFI type hash.  With
> > > > > > FUNCTION_CALL_PADDING, there are also 11 bytes of NOP padding between
> > > > > > the hash and the function entry which have no symbol to claim them.
> > > > > 
> > > > > If you force the function alignment to 64 bytes, the prefix will also be
> > > > > 64bytes, rather than the normal 16.
> > > > 
> > > > Sorry, how do you get 64 here?
> > > 
> > > DEBUG_FORCE_FUNCTION_ALIGNMENT_64B=y
> > 
> > Ok, so in that case it would be 5-byte cfi symbol and 59-byte NOP gap.
> > Or a 64-byte pfx for the !CFI case.
> > 
> > > > > > The NOPs can be rewritten with call depth tracking thunks at runtime.
> > > > > > Without a symbol, unwinders and other tools that symbolize code
> > > > > > locations misattribute those bytes.
> > > > > > 
> > > > > > Remove the !CFI guard so objtool creates __pfx_ symbols for all
> > > > > > CALL_PADDING configs, covering the full padding area regardless of
> > > > > > whether there's also a __cfi_ symbol.
> > > > > 
> > > > > Egads, that a ton of symbols :/ Does it not make sense to 'fix' up the
> > > > > __cfi_ symbols to cover the whole prefix?
> > > > 
> > > > Yeah, I suppose that would be better, via objtool I presume.
> > > 
> > > Yup.

I discovered it's not just FineIBT, it's basically any CALL_PADDING+CFI,
like so:

From: Josh Poimboeuf <jpoimboe@kernel.org>
Subject: [PATCH] objtool: Grow __cfi_* symbols for all kCFI+CALL_PADDING

For all CONFIG_CFI+CONFIG_CALL_PADDING configs, the __cfi_ symbols only
cover the 5-byte kCFI type hash.  After that there also N bytes of NOP
padding between the hash and the function entry which aren't associated
with any symbol.

The NOPs can be replaced with actual code at runtime.  Without a symbol,
unwinders and tooling have no way of knowing where those bytes belong.

Grow the existing __cfi_* symbols to fill that gap.

Also, CONFIG_PREFIX_SYMBOLS has no reason to exist: CONFIG_CALL_PADDING
is what causes the compiler to emit NOP padding before function entry
(via -fpatchable-function-entry), so it's the right condition for
creating prefix symbols.

Remove CONFIG_PREFIX_SYMBOLS, as it's no longer needed.  Simplify the
LONGEST_SYM_KUNIT_TEST dependency accordingly.

Update the --cfi and --prefix usage strings to reflect their current
scope.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
 arch/x86/Kconfig                    |  4 ----
 lib/Kconfig.debug                   |  2 +-
 scripts/Makefile.lib                |  5 ++++-
 tools/objtool/builtin-check.c       |  9 +++++++--
 tools/objtool/check.c               | 13 ++++++++++++-
 tools/objtool/elf.c                 | 20 ++++++++++++++++++++
 tools/objtool/include/objtool/elf.h |  1 +
 7 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f3f7cb01d69d..3eb3c48d764a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2437,10 +2437,6 @@ config CALL_THUNKS
 	def_bool n
 	select CALL_PADDING
 
-config PREFIX_SYMBOLS
-	def_bool y
-	depends on CALL_PADDING && !CFI
-
 menuconfig CPU_MITIGATIONS
 	bool "Mitigations for CPU vulnerabilities"
 	default y
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 77c3774c1c49..8b41720069b3 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -3059,7 +3059,7 @@ config FORTIFY_KUNIT_TEST
 config LONGEST_SYM_KUNIT_TEST
 	tristate "Test the longest symbol possible" if !KUNIT_ALL_TESTS
 	depends on KUNIT && KPROBES
-	depends on !PREFIX_SYMBOLS && !CFI && !GCOV_KERNEL
+	depends on !CALL_PADDING && !GCOV_KERNEL
 	default KUNIT_ALL_TESTS
 	help
 	  Tests the longest symbol possible
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 0718e39cedda..562d89f051f0 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -187,7 +187,10 @@ objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK)		+= --hacks=jump_label
 objtool-args-$(CONFIG_HAVE_NOINSTR_HACK)		+= --hacks=noinstr
 objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING)	+= --hacks=skylake
 objtool-args-$(CONFIG_X86_KERNEL_IBT)			+= --ibt
-objtool-args-$(CONFIG_FINEIBT)				+= --cfi
+objtool-args-$(CONFIG_CALL_PADDING)			+= --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
+ifdef CONFIG_CFI
+objtool-args-$(CONFIG_CALL_PADDING)			+= --cfi
+endif
 objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL)	+= --mcount
 ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
 objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT)		+= --mnop
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index ec7f10a5ef19..254ceb6b0e2c 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -73,7 +73,6 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)
 
 static const struct option check_options[] = {
 	OPT_GROUP("Actions:"),
-	OPT_BOOLEAN(0,		 "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"),
 	OPT_STRING_OPTARG('d',	 "disas", &opts.disas, "function-pattern", "disassemble functions", "*"),
 	OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks),
 	OPT_BOOLEAN('i',	 "ibt", &opts.ibt, "validate and annotate IBT"),
@@ -84,7 +83,7 @@ static const struct option check_options[] = {
 	OPT_BOOLEAN('r',	 "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
 	OPT_BOOLEAN(0,		 "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
 	OPT_BOOLEAN(0,		 "unret", &opts.unret, "validate entry unret placement"),
-	OPT_INTEGER(0,		 "prefix", &opts.prefix, "generate prefix symbols"),
+	OPT_INTEGER(0,		 "prefix", &opts.prefix, "generate or grow prefix symbols for N-byte function padding"),
 	OPT_BOOLEAN('l',	 "sls", &opts.sls, "validate straight-line-speculation mitigations"),
 	OPT_BOOLEAN('s',	 "stackval", &opts.stackval, "validate frame pointer rules"),
 	OPT_BOOLEAN('t',	 "static-call", &opts.static_call, "annotate static calls"),
@@ -92,6 +91,7 @@ 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,		 "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 +163,11 @@ static bool opts_valid(void)
 		return false;
 	}
 
+	if (opts.cfi && !opts.prefix) {
+		ERROR("--cfi requires --prefix");
+		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 410061aeed26..fb24fd284e09 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -923,6 +923,17 @@ 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;
@@ -4927,7 +4938,7 @@ int check(struct objtool_file *file)
 			goto out;
 	}
 
-	if (opts.prefix) {
+	if (opts.prefix && !opts.cfi) {
 		ret = create_prefix_symbols(file);
 		if (ret)
 			goto out;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 2ca1151de815..ede87dd9644c 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -983,6 +983,26 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name,
 	return sym;
 }
 
+int elf_write_symbol(struct elf *elf, struct symbol *sym)
+{
+	struct section *symtab, *symtab_shndx;
+
+	symtab = find_section_by_name(elf, ".symtab");
+	if (!symtab) {
+		ERROR("no .symtab");
+		return -1;
+	}
+
+	symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+
+	if (elf_update_symbol(elf, symtab, symtab_shndx, sym))
+		return -1;
+
+	mark_sec_changed(elf, symtab, true);
+
+	return 0;
+}
+
 struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec)
 {
 	struct symbol *sym = calloc(1, sizeof(*sym));
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 0fd1a9b563e9..4c8a67a68063 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -199,6 +199,7 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
 				      struct symbol *sym,
 				      s64 addend);
 
+int elf_write_symbol(struct elf *elf, struct symbol *sym);
 int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset,
 		   unsigned int len, const char *insn);
 
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH 04/48] objtool/klp: Ignore __UNIQUE_ID_*() PCI stub functions
From: Song Liu @ 2026-04-23 23:54 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <l6spha5o4wl5ksczovjwxghb5lhe4parswxhtzk2ac4inxmmhc@h2hiehwqkgmx>

On Thu, Apr 23, 2026 at 4:50 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Thu, Apr 23, 2026 at 02:33:00PM -0700, Song Liu wrote:
> > On Thu, Apr 23, 2026 at 12:31 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > >
> > > On Thu, Apr 23, 2026 at 12:05:03PM -0700, Song Liu wrote:
> > > > On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > > > >
> > > > > With Clang LTO enabled, DECLARE_PCI_FIXUP_SECTION() uses __UNIQUE_ID()
> > > > > to generate uniquely named wrapper functions, which are being reported
> > > > > as new functions and unnecessarily included in the patch module:
> > > > >
> > > > >   vmlinux.o: new function: __UNIQUE_ID_quirk_f0_vpd_link_661
> > > > >
> > > > > These stub functions only exist to make the compiler happy.  Just ignore
> > > > > them along with any other dont_correlate() symbols.  Note that
> > > > > dont_correlate() already includes prefix functions.
> > > > >
> > > > > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> > > >
> > > > The actual change appears to be much bigger than the subject line.
> > > > Maybe rephrase it a bit?
> > >
> > > Hm, in fact this is a relic from a previous iteration of the patches: it
> > > longer fixes what it claims to fix, as __UNIQUE_ID_ (other than
> > > __ADDRESSABLE()) are now correlated.  The claimed issue actually gets
> > > fixed later by the rewriting of the correlation algorithm.
> > >
> > > That said, I still think the below is needed, I just need to rewrite the
> > > commit log.
> >
> > Agreed.
>
> From: Josh Poimboeuf <jpoimboe@kernel.org>
> Subject: [PATCH] objtool/klp: Don't report uncorrelated functions as new
>
> Clang LTO uses __UNIQUE_ID() to generate some uniquely named wrapper
> functions, like initstubs.  If they're uncorrelated, prevent them from
> being reported as new functions and included unnecessarily.
>
> Note that dont_correlate() already includes prefix functions, so prefix
> functions are still being ignored here.
>
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

LGTM.

Acked-by: Song Liu <song@kernel.org>

^ permalink raw reply

* Re: [PATCH 02/48] objtool/klp: Fix .data..once static local non-correlation
From: Song Liu @ 2026-04-23 23:54 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <tzunpmsnca3pi5ziak6cwrqftdl7oa34jcuy7cm4nrzzfd6276@jkates4giayx>

On Thu, Apr 23, 2026 at 4:34 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Thu, Apr 23, 2026 at 11:54:39AM -0700, Song Liu wrote:
> > On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > >
> > > While there was once a section named .data.once, it has since been
> > > renamed to .data..once with commit dbefa1f31a91 ("Rename .data.once to
> > > .data..once to fix resetting WARN*_ONCE").  Fix it.
> > >
> > > Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
> > > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> >
> > Acked-by: Song Liu <song@kernel.org>
> >
> > Nitpick: shall we match both ".data.once" and ".data..once", so that whoever
> > backports klp-build to older kernels will not have a surprise.
>
> Hm, I'm a bit hesitant to do that.  One of the nice things about having
> this code upstream is that we don't have to start collecting all the
> cruft for old kernels.

Agreed. Instead of matching both, we can probably cover this with a
test case.

Thanks,
Song

^ permalink raw reply

* Re: [PATCH 04/48] objtool/klp: Ignore __UNIQUE_ID_*() PCI stub functions
From: Josh Poimboeuf @ 2026-04-23 23:50 UTC (permalink / raw)
  To: Song Liu
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <CAPhsuW6VWk43z+BYCYRxo56w-4VKw8W3nmvVfCLh=ouN7a2Cqg@mail.gmail.com>

On Thu, Apr 23, 2026 at 02:33:00PM -0700, Song Liu wrote:
> On Thu, Apr 23, 2026 at 12:31 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >
> > On Thu, Apr 23, 2026 at 12:05:03PM -0700, Song Liu wrote:
> > > On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > > >
> > > > With Clang LTO enabled, DECLARE_PCI_FIXUP_SECTION() uses __UNIQUE_ID()
> > > > to generate uniquely named wrapper functions, which are being reported
> > > > as new functions and unnecessarily included in the patch module:
> > > >
> > > >   vmlinux.o: new function: __UNIQUE_ID_quirk_f0_vpd_link_661
> > > >
> > > > These stub functions only exist to make the compiler happy.  Just ignore
> > > > them along with any other dont_correlate() symbols.  Note that
> > > > dont_correlate() already includes prefix functions.
> > > >
> > > > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> > >
> > > The actual change appears to be much bigger than the subject line.
> > > Maybe rephrase it a bit?
> >
> > Hm, in fact this is a relic from a previous iteration of the patches: it
> > longer fixes what it claims to fix, as __UNIQUE_ID_ (other than
> > __ADDRESSABLE()) are now correlated.  The claimed issue actually gets
> > fixed later by the rewriting of the correlation algorithm.
> >
> > That said, I still think the below is needed, I just need to rewrite the
> > commit log.
> 
> Agreed.

From: Josh Poimboeuf <jpoimboe@kernel.org>
Subject: [PATCH] objtool/klp: Don't report uncorrelated functions as new

Clang LTO uses __UNIQUE_ID() to generate some uniquely named wrapper
functions, like initstubs.  If they're uncorrelated, prevent them from
being reported as new functions and included unnecessarily.

Note that dont_correlate() already includes prefix functions, so prefix
functions are still being ignored here.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
 tools/objtool/klp-diff.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 36753eeba58c..ea9ccf8c4ea9 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -786,7 +786,7 @@ static int mark_changed_functions(struct elfs *e)
 
 	/* Find changed functions */
 	for_each_sym(e->orig, sym_orig) {
-		if (!is_func_sym(sym_orig) || is_prefix_func(sym_orig))
+		if (!is_func_sym(sym_orig) || dont_correlate(sym_orig))
 			continue;
 
 		patched_sym = sym_orig->twin;
@@ -802,7 +802,7 @@ static int mark_changed_functions(struct elfs *e)
 
 	/* Find added functions and print them */
 	for_each_sym(e->patched, patched_sym) {
-		if (!is_func_sym(patched_sym) || is_prefix_func(patched_sym))
+		if (!is_func_sym(patched_sym) || dont_correlate(patched_sym))
 			continue;
 
 		if (!patched_sym->twin) {
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH 02/48] objtool/klp: Fix .data..once static local non-correlation
From: Josh Poimboeuf @ 2026-04-23 23:34 UTC (permalink / raw)
  To: Song Liu
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <CAPhsuW7rmG_tybJwKdrX+DsKx9a7xA-Qa57njW5r+NyvhT3DUA@mail.gmail.com>

On Thu, Apr 23, 2026 at 11:54:39AM -0700, Song Liu wrote:
> On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >
> > While there was once a section named .data.once, it has since been
> > renamed to .data..once with commit dbefa1f31a91 ("Rename .data.once to
> > .data..once to fix resetting WARN*_ONCE").  Fix it.
> >
> > Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
> > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> 
> Acked-by: Song Liu <song@kernel.org>
> 
> Nitpick: shall we match both ".data.once" and ".data..once", so that whoever
> backports klp-build to older kernels will not have a surprise.

Hm, I'm a bit hesitant to do that.  One of the nice things about having
this code upstream is that we don't have to start collecting all the
cruft for old kernels.

-- 
Josh

^ permalink raw reply

* Re: [PATCH 45/48] x86/Kconfig: Enable CONFIG_PREFIX_SYMBOLS for FineIBT
From: Josh Poimboeuf @ 2026-04-23 23:30 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: x86, linux-kernel, live-patching, Joe Lawrence, Song Liu,
	Miroslav Benes, Petr Mladek
In-Reply-To: <gpq7mfal5gydlrqsm5mza5hzx5aa2rq7yk6olozlzotdnl7e24@ljzzzwwsputr>

On Thu, Apr 23, 2026 at 09:23:12AM -0700, Josh Poimboeuf wrote:
> On Thu, Apr 23, 2026 at 05:19:25PM +0200, Peter Zijlstra wrote:
> > On Thu, Apr 23, 2026 at 08:16:08AM -0700, Josh Poimboeuf wrote:
> > > On Thu, Apr 23, 2026 at 10:47:58AM +0200, Peter Zijlstra wrote:
> > > > On Wed, Apr 22, 2026 at 09:04:13PM -0700, Josh Poimboeuf wrote:
> > > > > PREFIX_SYMBOLS has a !CFI dependency because the compiler already
> > > > > generates __cfi_ prefix symbols for kCFI builds, so objtool-generated
> > > > > __pfx_ symbols were considered redundant.
> > > > > 
> > > > > However, the __cfi_ symbols only cover the 5-byte kCFI type hash.  With
> > > > > FUNCTION_CALL_PADDING, there are also 11 bytes of NOP padding between
> > > > > the hash and the function entry which have no symbol to claim them.
> > > > 
> > > > If you force the function alignment to 64 bytes, the prefix will also be
> > > > 64bytes, rather than the normal 16.
> > > 
> > > Sorry, how do you get 64 here?
> > 
> > DEBUG_FORCE_FUNCTION_ALIGNMENT_64B=y
> 
> Ok, so in that case it would be 5-byte cfi symbol and 59-byte NOP gap.
> Or a 64-byte pfx for the !CFI case.
> 
> > > > > The NOPs can be rewritten with call depth tracking thunks at runtime.
> > > > > Without a symbol, unwinders and other tools that symbolize code
> > > > > locations misattribute those bytes.
> > > > > 
> > > > > Remove the !CFI guard so objtool creates __pfx_ symbols for all
> > > > > CALL_PADDING configs, covering the full padding area regardless of
> > > > > whether there's also a __cfi_ symbol.
> > > > 
> > > > Egads, that a ton of symbols :/ Does it not make sense to 'fix' up the
> > > > __cfi_ symbols to cover the whole prefix?
> > > 
> > > Yeah, I suppose that would be better, via objtool I presume.
> > 
> > Yup.

From: Josh Poimboeuf <jpoimboe@kernel.org>
Subject: [PATCH] objtool: Grow __cfi_* symbols for FineIBT

For FineIBT, the __cfi_ symbols only cover the 5-byte kCFI type hash.
After that there also N bytes of NOP padding between the hash and the
function entry which aren't associated with any symbol.

The NOPs can be replaced with actual code at runtime.  Without a symbol,
unwinders, objtool, and other tools have no way of knowing where those
bytes belong.

Grow the existing __cfi_* symbols to fill that gap.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
 scripts/Makefile.lib                |  2 +-
 tools/objtool/check.c               | 13 ++++++++++++-
 tools/objtool/elf.c                 | 20 ++++++++++++++++++++
 tools/objtool/include/objtool/elf.h |  1 +
 4 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 0718e39cedda..baaf9f6c6bb5 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -187,7 +187,7 @@ objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK)		+= --hacks=jump_label
 objtool-args-$(CONFIG_HAVE_NOINSTR_HACK)		+= --hacks=noinstr
 objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING)	+= --hacks=skylake
 objtool-args-$(CONFIG_X86_KERNEL_IBT)			+= --ibt
-objtool-args-$(CONFIG_FINEIBT)				+= --cfi
+objtool-args-$(CONFIG_FINEIBT)				+= --cfi --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
 objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL)	+= --mcount
 ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
 objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT)		+= --mnop
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 410061aeed26..fb24fd284e09 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -923,6 +923,17 @@ 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;
@@ -4927,7 +4938,7 @@ int check(struct objtool_file *file)
 			goto out;
 	}
 
-	if (opts.prefix) {
+	if (opts.prefix && !opts.cfi) {
 		ret = create_prefix_symbols(file);
 		if (ret)
 			goto out;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 2ca1151de815..ede87dd9644c 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -983,6 +983,26 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name,
 	return sym;
 }
 
+int elf_write_symbol(struct elf *elf, struct symbol *sym)
+{
+	struct section *symtab, *symtab_shndx;
+
+	symtab = find_section_by_name(elf, ".symtab");
+	if (!symtab) {
+		ERROR("no .symtab");
+		return -1;
+	}
+
+	symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+
+	if (elf_update_symbol(elf, symtab, symtab_shndx, sym))
+		return -1;
+
+	mark_sec_changed(elf, symtab, true);
+
+	return 0;
+}
+
 struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec)
 {
 	struct symbol *sym = calloc(1, sizeof(*sym));
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 0fd1a9b563e9..4c8a67a68063 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -199,6 +199,7 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
 				      struct symbol *sym,
 				      s64 addend);
 
+int elf_write_symbol(struct elf *elf, struct symbol *sym);
 int elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset,
 		   unsigned int len, const char *insn);
 
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH 04/48] objtool/klp: Ignore __UNIQUE_ID_*() PCI stub functions
From: Song Liu @ 2026-04-23 21:33 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <gmjxp6lzlwjfdp4gf2nktoqfwrdx4bapf2mnnezo2gjyjj6yqf@if35zh3xa7t6>

On Thu, Apr 23, 2026 at 12:31 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Thu, Apr 23, 2026 at 12:05:03PM -0700, Song Liu wrote:
> > On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > >
> > > With Clang LTO enabled, DECLARE_PCI_FIXUP_SECTION() uses __UNIQUE_ID()
> > > to generate uniquely named wrapper functions, which are being reported
> > > as new functions and unnecessarily included in the patch module:
> > >
> > >   vmlinux.o: new function: __UNIQUE_ID_quirk_f0_vpd_link_661
> > >
> > > These stub functions only exist to make the compiler happy.  Just ignore
> > > them along with any other dont_correlate() symbols.  Note that
> > > dont_correlate() already includes prefix functions.
> > >
> > > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> >
> > The actual change appears to be much bigger than the subject line.
> > Maybe rephrase it a bit?
>
> Hm, in fact this is a relic from a previous iteration of the patches: it
> longer fixes what it claims to fix, as __UNIQUE_ID_ (other than
> __ADDRESSABLE()) are now correlated.  The claimed issue actually gets
> fixed later by the rewriting of the correlation algorithm.
>
> That said, I still think the below is needed, I just need to rewrite the
> commit log.

Agreed.

Thanks,
Song

^ permalink raw reply

* Re: [PATCH 04/48] objtool/klp: Ignore __UNIQUE_ID_*() PCI stub functions
From: Josh Poimboeuf @ 2026-04-23 19:31 UTC (permalink / raw)
  To: Song Liu
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <CAPhsuW6_FzbAeqOduv56jZEk2E1xm+RqAxOHdekUHJwezvGOyw@mail.gmail.com>

On Thu, Apr 23, 2026 at 12:05:03PM -0700, Song Liu wrote:
> On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >
> > With Clang LTO enabled, DECLARE_PCI_FIXUP_SECTION() uses __UNIQUE_ID()
> > to generate uniquely named wrapper functions, which are being reported
> > as new functions and unnecessarily included in the patch module:
> >
> >   vmlinux.o: new function: __UNIQUE_ID_quirk_f0_vpd_link_661
> >
> > These stub functions only exist to make the compiler happy.  Just ignore
> > them along with any other dont_correlate() symbols.  Note that
> > dont_correlate() already includes prefix functions.
> >
> > Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> 
> The actual change appears to be much bigger than the subject line.
> Maybe rephrase it a bit?

Hm, in fact this is a relic from a previous iteration of the patches: it
longer fixes what it claims to fix, as __UNIQUE_ID_ (other than
__ADDRESSABLE()) are now correlated.  The claimed issue actually gets
fixed later by the rewriting of the correlation algorithm.

That said, I still think the below is needed, I just need to rewrite the
commit log.

> 
> > ---
> >  tools/objtool/klp-diff.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
> > index 36753eeba58c..ea9ccf8c4ea9 100644
> > --- a/tools/objtool/klp-diff.c
> > +++ b/tools/objtool/klp-diff.c
> > @@ -786,7 +786,7 @@ static int mark_changed_functions(struct elfs *e)
> >
> >         /* Find changed functions */
> >         for_each_sym(e->orig, sym_orig) {
> > -               if (!is_func_sym(sym_orig) || is_prefix_func(sym_orig))
> > +               if (!is_func_sym(sym_orig) || dont_correlate(sym_orig))
> >                         continue;
> >
> >                 patched_sym = sym_orig->twin;
> > @@ -802,7 +802,7 @@ static int mark_changed_functions(struct elfs *e)
> >
> >         /* Find added functions and print them */
> >         for_each_sym(e->patched, patched_sym) {
> > -               if (!is_func_sym(patched_sym) || is_prefix_func(patched_sym))
> > +               if (!is_func_sym(patched_sym) || dont_correlate(patched_sym))
> >                         continue;
> >
> >                 if (!patched_sym->twin) {
> > --
> > 2.53.0
> >

-- 
Josh

^ permalink raw reply

* Re: [PATCH 32/48] objtool: Add is_cold_func() helper
From: Josh Poimboeuf @ 2026-04-23 19:23 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: x86, linux-kernel, live-patching, Joe Lawrence, Song Liu,
	Miroslav Benes, Petr Mladek
In-Reply-To: <20260423151405.GF1064669@noisy.programming.kicks-ass.net>

On Thu, Apr 23, 2026 at 05:14:05PM +0200, Peter Zijlstra wrote:
> On Thu, Apr 23, 2026 at 08:12:07AM -0700, Josh Poimboeuf wrote:
> > On Thu, Apr 23, 2026 at 10:38:49AM +0200, Peter Zijlstra wrote:
> > > On Wed, Apr 22, 2026 at 09:04:00PM -0700, Josh Poimboeuf wrote:
> > > 
> > > > diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
> > > > index 00c2389f345f..8a6e1338af97 100644
> > > > --- a/tools/objtool/elf.c
> > > > +++ b/tools/objtool/elf.c
> > > > @@ -586,8 +586,11 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym)
> > > >  	if (strstarts(sym->name, ".klp.sym"))
> > > >  		sym->klp = 1;
> > > >  
> > > > +	sym->pfunc = sym->cfunc = sym;
> > > > +
> > > >  	if (!sym->klp && !is_sec_sym(sym) && strstr(sym->name, ".cold")) {
> > > > -		sym->cold = 1;
> > > > +		/* Tell read_symbols() this is a cold subfunction */
> > > > +		sym->pfunc = NULL;
> > > >  
> > > >  		/*
> > > >  		 * Clang doesn't mark cold subfunctions as STT_FUNC, which
> > > > @@ -596,8 +599,6 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym)
> > > >  		sym->type = STT_FUNC;
> > > >  	}
> > > >  
> > > > -	sym->pfunc = sym->cfunc = sym;
> > > > -
> > > >  	return 0;
> > > >  }
> > > 
> > > So now the cold subfunction has a NULL parent-function and a
> > > child-function that points to the parent?
> > > 
> > > I'm confused.
> > 
> > It's a bit clunky.  As the comment implies, 'sym->pfunc = NULL' is a
> > signal to it caller read_symbols() that this is a .cold function.  Then,
> > after all the symbols have been added, read_symbols() goes and finds the
> > parent.
> > 
> > I think I did it this way because klp-diff.c calls elf_add_symbol() (via
> > elf_create_symbol()) and later needs to call is_cold_func() on it.  In
> > that case, even though the parent isn't set, it still works because
> > is_cold_func() returns true for sym->pfunc != sym;
> 
> I'm thinking this needs more comments if it stays like this. Is most
> confusing.

So we can just keep the 'cold' bit and keep the confusingness at its
current level :-)

From: Josh Poimboeuf <jpoimboe@kernel.org>
Subject: [PATCH] objtool: Add is_cold_func() helper

Add an is_cold_func() helper.  No functional changes intended.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
 tools/objtool/check.c               | 6 +++---
 tools/objtool/include/objtool/elf.h | 5 +++++
 tools/objtool/klp-diff.c            | 3 ++-
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4c18d6e7f6c3..4ed27c53c718 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2614,7 +2614,7 @@ static void mark_holes(struct objtool_file *file)
 		if (insn->jump_dest) {
 			struct symbol *dest_func = insn_func(insn->jump_dest);
 
-			if (dest_func && dest_func->cold)
+			if (dest_func && is_cold_func(dest_func))
 				dest_func->ignore = true;
 		}
 	}
@@ -4426,8 +4426,8 @@ static int create_prefix_symbol(struct objtool_file *file, struct symbol *func)
 	char name[SYM_NAME_LEN];
 	struct cfi_state *cfi;
 
-	if (!is_func_sym(func) || is_prefix_func(func) ||
-	    func->cold || func->static_call_tramp)
+	if (!is_func_sym(func) || is_prefix_func(func) || is_cold_func(func) ||
+	    func->static_call_tramp)
 		return 0;
 
 	if ((strlen(func->name) + sizeof("__pfx_") > SYM_NAME_LEN)) {
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 3abe4cbc584c..ad0cc57a9d5f 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -289,6 +289,11 @@ static inline bool is_prefix_func(struct symbol *sym)
 	return sym->prefix;
 }
 
+static inline bool is_cold_func(struct symbol *sym)
+{
+	return sym->cold;
+}
+
 static inline bool is_reloc_sec(struct section *sec)
 {
 	return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 1951a8b2df44..266f0d2ba4fe 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1718,7 +1718,8 @@ static int create_klp_sections(struct elfs *e)
 		unsigned long sympos;
 		void *func_data;
 
-		if (!is_func_sym(sym) || sym->cold || !sym->clone || !sym->clone->changed)
+		if (!is_func_sym(sym) || is_cold_func(sym) ||
+		    !sym->clone || !sym->clone->changed)
 			continue;
 
 		/* allocate klp_func_ext */
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH 04/48] objtool/klp: Ignore __UNIQUE_ID_*() PCI stub functions
From: Song Liu @ 2026-04-23 19:05 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <93c7c80130375edd22874a57cdea132b0edbb0e4.1776916871.git.jpoimboe@kernel.org>

On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> With Clang LTO enabled, DECLARE_PCI_FIXUP_SECTION() uses __UNIQUE_ID()
> to generate uniquely named wrapper functions, which are being reported
> as new functions and unnecessarily included in the patch module:
>
>   vmlinux.o: new function: __UNIQUE_ID_quirk_f0_vpd_link_661
>
> These stub functions only exist to make the compiler happy.  Just ignore
> them along with any other dont_correlate() symbols.  Note that
> dont_correlate() already includes prefix functions.
>
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

The actual change appears to be much bigger than the subject line.
Maybe rephrase it a bit?

> ---
>  tools/objtool/klp-diff.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
> index 36753eeba58c..ea9ccf8c4ea9 100644
> --- a/tools/objtool/klp-diff.c
> +++ b/tools/objtool/klp-diff.c
> @@ -786,7 +786,7 @@ static int mark_changed_functions(struct elfs *e)
>
>         /* Find changed functions */
>         for_each_sym(e->orig, sym_orig) {
> -               if (!is_func_sym(sym_orig) || is_prefix_func(sym_orig))
> +               if (!is_func_sym(sym_orig) || dont_correlate(sym_orig))
>                         continue;
>
>                 patched_sym = sym_orig->twin;
> @@ -802,7 +802,7 @@ static int mark_changed_functions(struct elfs *e)
>
>         /* Find added functions and print them */
>         for_each_sym(e->patched, patched_sym) {
> -               if (!is_func_sym(patched_sym) || is_prefix_func(patched_sym))
> +               if (!is_func_sym(patched_sym) || dont_correlate(patched_sym))
>                         continue;
>
>                 if (!patched_sym->twin) {
> --
> 2.53.0
>

^ permalink raw reply

* Re: [PATCH 02/48] objtool/klp: Fix .data..once static local non-correlation
From: Song Liu @ 2026-04-23 18:54 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <f34990d29dd7642ada7843613c96c563043c28a5.1776916871.git.jpoimboe@kernel.org>

On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> While there was once a section named .data.once, it has since been
> renamed to .data..once with commit dbefa1f31a91 ("Rename .data.once to
> .data..once to fix resetting WARN*_ONCE").  Fix it.
>
> Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

Acked-by: Song Liu <song@kernel.org>

Nitpick: shall we match both ".data.once" and ".data..once", so that whoever
backports klp-build to older kernels will not have a surprise.

> ---
>  tools/objtool/klp-diff.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
> index b1b068e9b4c7..cb26c1c92a74 100644
> --- a/tools/objtool/klp-diff.c
> +++ b/tools/objtool/klp-diff.c
> @@ -257,7 +257,8 @@ static bool is_uncorrelated_static_local(struct symbol *sym)
>         if (!is_object_sym(sym) || !is_local_sym(sym))
>                 return false;
>
> -       if (!strcmp(sym->sec->name, ".data.once"))
> +       /* WARN_ONCE, etc */
> +       if (!strcmp(sym->sec->name, ".data..once"))
>                 return true;
>
>         dot = strchr(sym->name, '.');
> --
> 2.53.0
>
>

^ permalink raw reply

* Re: [PATCH 01/48] objtool/klp: Fix is_uncorrelated_static_local() for Clang
From: Song Liu @ 2026-04-23 18:45 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Peter Zijlstra, Joe Lawrence,
	Miroslav Benes, Petr Mladek
In-Reply-To: <f2a97da92796708f77c6fb3e07816f84874b79a4.1776916871.git.jpoimboe@kernel.org>

On Wed, Apr 22, 2026 at 9:04 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> From: Joe Lawrence <joe.lawrence@redhat.com>
>
> For naming function-local static locals, GCC uses <var>.<id>, e.g.
> __already_done.15, while Clang uses <func>.<var> with optional .<id>,
> e.g. create_worker.__already_done.111
>
> The existing is_uncorrelated_static_local() check only matches the GCC
> convention where the variable name is a prefix.  Handle both cases by
> checking for a prefix match (GCC) and by checking after the first dot
> separator (Clang).
>
> Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
> Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

Acked-by: Song Liu <song@kernel.org>

^ permalink raw reply

* Re: [PATCH 17/48] objtool: Fix reloc hash collision in find_reloc_by_dest_range()
From: Josh Poimboeuf @ 2026-04-23 16:34 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: x86, linux-kernel, live-patching, Joe Lawrence, Song Liu,
	Miroslav Benes, Petr Mladek
In-Reply-To: <20260423083231.GS3126523@noisy.programming.kicks-ass.net>

On Thu, Apr 23, 2026 at 10:32:31AM +0200, Peter Zijlstra wrote:
> On Wed, Apr 22, 2026 at 09:03:45PM -0700, Josh Poimboeuf wrote:
> > In find_reloc_by_dest_range(), hash collisions can cause a high-offset
> > relocation to appear when probing a low-offset hash bucket.
> > 
> > Only return early when the best match found so far genuinely belongs to
> > the current bucket (its offset is within the bucket's stride range).
> > Otherwise, continue scanning later buckets which may contain
> > lower-offset matches.
> 
> Maybe mention (and or add a comment to the function) that in case of
> multiple matches in the given range, it will return the lowest address
> one.
> 
> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index c4cb371e72b2..af2841b8e095 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -347,8 +347,9 @@ void iterate_sym_by_name(const struct elf *elf, const char *name,
 	}
 }
 
+/* If there are multiple matches, return the first one in the range */
 struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
-				     unsigned long offset, unsigned int len)
+				       unsigned long offset, unsigned int len)
 {
 	struct reloc *reloc, *r = NULL;
 	struct section *rsec;

^ permalink raw reply related

* Re: [PATCH 45/48] x86/Kconfig: Enable CONFIG_PREFIX_SYMBOLS for FineIBT
From: Peter Zijlstra @ 2026-04-23 16:29 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: x86, linux-kernel, live-patching, Joe Lawrence, Song Liu,
	Miroslav Benes, Petr Mladek
In-Reply-To: <gpq7mfal5gydlrqsm5mza5hzx5aa2rq7yk6olozlzotdnl7e24@ljzzzwwsputr>

On Thu, Apr 23, 2026 at 09:23:12AM -0700, Josh Poimboeuf wrote:

> > > Sorry, how do you get 64 here?
> > 
> > DEBUG_FORCE_FUNCTION_ALIGNMENT_64B=y
> 
> Ok, so in that case it would be 5-byte cfi symbol and 59-byte NOP gap.
> Or a 64-byte pfx for the !CFI case.

Just so.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox