Re: [PATCH] modpost: Ignore Clang LTO suffixes in symbol matching

From: Petr Pavlu

Date: Wed Jun 17 2026 - 07:12:29 EST


On 6/16/26 12:43 AM, Rong Xu wrote:
> A more direct fix for the warnings in
> https://lore.kernel.org/oe-kbuild-all/202606111233.kM8oo8Df-lkp@xxxxxxxxx/
> looks like the following. But I believe the solution provided in the
> patch is more comprehensive.
>
> -Rong
>
> ======
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index abbcd3fc1394..1f0a379b43c8 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -967,7 +967,7 @@ static int secref_whitelist(const char *fromsec,
> const char *fromsym,
> /* symbols in data sections that may refer to any init/exit sections */
> if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
> match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
> - match(fromsym, PATTERNS("*_ops", "*_console")))
> + match(fromsym, PATTERNS("*_ops", "*_ops.llvm.*", "*_console")))
> return 0;
>
> /* Check for pattern 3 */
>

This variant makes more sense to me. The initially proposed patch
modifies the match() function, which is a generic function to check
whether a string matches any of the input patterns. The modpost utility
uses it to match both symbol and section names. Adding symbol-specific
knowledge to this function seems odd.

I noticed that LLVM has recently made improvements to reduce the number
of these ThinLTO renames [1], which might be worth checking out.

[1] https://github.com/llvm/llvm-project/commit/975dba28633d2f3746a8a370741b17024b0f5f9b

--
Thanks,
Petr

> On Mon, Jun 15, 2026 at 3:20 PM <xur@xxxxxxxxxx> wrote:
>>
>> From: Rong Xu <xur@xxxxxxxxxx>
>>
>> When building the kernel with Clang ThinLTO enabled, the compiler
>> can mangle static variable names by appending suffixes such as
>> ".llvm.<hash>" to prevent naming collisions across translation units.
>>
>> This name mangling breaks the section mismatch whitelisting in modpost.
>> modpost relies on glob patterns (e.g., "*_ops" or "*_probe") to identify
>> safe references between permanent data and initialization code. Because
>> the LTO suffix modifies the end of the symbol name, legitimately
>> whitelisted structures fail the match, resulting in false positive
>> warnings.
>>
>> For example, a static pernet_operations struct triggers the following:
>>
>> WARNING: modpost: vmlinux: section mismatch in reference: \
>> ping_v4_net_ops.llvm.5641696707737373282 (section: .data) -> \
>> ping_v4_proc_init_net (section: .init.text)
>>
>> Fix this by stripping ".llvm." suffixes from the symbol name in match().
>>
>> Reported-by: kernel test robot <lkp@xxxxxxxxx>
>> Closes: https://lore.kernel.org/oe-kbuild-all/202606111233.kM8oo8Df-lkp@xxxxxxxxx/
>> Signed-off-by: Rong Xu <xur@xxxxxxxxxx>
>> ---
>> scripts/mod/modpost.c | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
>> index abbcd3fc1394..1f5a64eeb048 100644
>> --- a/scripts/mod/modpost.c
>> +++ b/scripts/mod/modpost.c
>> @@ -727,6 +727,18 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym)
>> static bool match(const char *string, const char *const patterns[])
>> {
>> const char *pattern;
>> + char string_stripped[512];
>> + const char *ext = strstr(string, ".llvm.");
>> +
>> + /*
>> + * Clang LTO can append .llvm.<hash> to a variable. Safely strip
>> + * the suffix so glob whitelists (like *_ops) work.
>> + */
>> + if (ext && (ext - string) < sizeof(string_stripped)) {
>> + strncpy(string_stripped, string, ext - string);
>> + string_stripped[ext - string] = '\0';
>> + string = string_stripped;
>> + }
>>
>> while ((pattern = *patterns++)) {
>> if (!fnmatch(pattern, string, 0))
>>
>> base-commit: 2b414a95b8f7307d42173ba9e580d6d3e2bcbfce
>> --
>> 2.54.0.1136.gdb2ca164c4-goog
>>