public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Yonghong Song <yonghong.song@linux.dev>
To: Josh Poimboeuf <jpoimboe@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <song@kernel.org>, LKML <linux-kernel@vger.kernel.org>,
	Kernel Team <kernel-team@fb.com>
Subject: Re: objtool failure caused some kernel functionality not working
Date: Wed, 29 Jan 2025 23:21:00 -0800	[thread overview]
Message-ID: <df858dd3-bc4f-4aa3-afe7-15d60cc63afb@linux.dev> (raw)
In-Reply-To: <0bf90fc0-2287-4ce0-b810-6e383e695981@linux.dev>




On 1/29/25 11:10 PM, Yonghong Song wrote:
> In Meta, when I tried to use llvm19 compiler to build a kernel with 
> PGO ([1]) support for 6.13 kernel, Ihit the following objtool warning: 
>   warning: objtool: __htab_map_lookup_elem+0x3fb: can't find switch 
> jump table
>
> The kernel is built successfully, but after booting the kernel, 
> /sys/kernel/debug/tracing/available_filter_functionsand 
> /sys/kernel/debug/tracing/available_filter_functions_addrs are empty. 
> I did some investigation and found that the warning is at func 
> add_jump_table(): static int add_jump_table(struct objtool_file *file, 
> struct instruction *insn, struct reloc *next_table) { struct symbol 
> *pfunc = insn_func(insn)->pfunc; struct reloc *table = 
> insn_jump_table(insn); struct instruction *dest_insn; unsigned int 
> prev_offset = 0; struct reloc *reloc = table; struct alternative *alt; 
> /* * Each @reloc is a switch table relocation which points to the 
> target * instruction. */ for_each_reloc_from(table->sec, reloc) { /* 
> Check for the end of the table: */ if (reloc != table && reloc == 
> next_table) break; /* Make sure the table entries are consecutive: */ 
> if (prev_offset && reloc_offset(reloc) != prev_offset + 8) break; /* 
> Detect function pointers from contiguous objects: */ if 
> (reloc->sym->sec == pfunc->sec && reloc_addend(reloc) == 
> pfunc->offset) break; dest_insn = find_insn(file, reloc->sym->sec, 
> reloc_addend(reloc)); <===== find_insn return a NULL dest_insn with 
> prev_offset == 0 if (!dest_insn) break; /* Make sure the destination 
> is in the same function: */ if (!insn_func(dest_insn) || 
> insn_func(dest_insn)->pfunc != pfunc) break; alt = 
> malloc(sizeof(*alt)); if (!alt) { WARN("malloc failed"); return -1; } 
> alt->insn = dest_insn; alt->next = insn->alts; insn->alts = alt; 
> prev_offset = reloc_offset(reloc); } if (!prev_offset) { 
> WARN_INSN(insn, "can't find switch jump table"); <===== error message 
> here. return -1; } return 0; } The find_insn failed for 'prev_offset 
> == 0' at the second iteration and finally the function return -1, 
> which propagated to decode_sections() in func check(). Since 
> decode_sections() got an error ret the later 
> create_mcount_loc_sections() will not be called. This caused the above 
> available_filter_functions issue.

Sorry for the mess-up for the above code.  The summary is:

The kernel is built successfully, but after booting the kernel,
/sys/kernel/debug/tracing/available_filter_functions and
/sys/kernel/debug/tracing/available_filter_functions_addrs
are empty. I did some investigation and found that the warning is at func
add_jump_table().

The find_insn() failed for 'prev_offset == 0' at the second
iteration and finally the function return -1, which propagated to
decode_sections() in func check(). Since decode_sections() got an error
ret the later create_mcount_loc_sections() will not be called. This
caused the above available_filter_functions issue.


>
> The following are some codes related to func__htab_map_lookup_elem():
>
> Disassembly of section .text.hot.__htab_map_lookup_elem:
>        0000000000000000 <__htab_map_lookup_elem>:
>        0: e8 00 00 00 00                callq   0x5 
> <__htab_map_lookup_elem+0x5>
>                 0000000000000001:  R_X86_64_PLT32 __fentry__-0x4
>        5: 55                            pushq   %rbp
> ...
>      3f3: e9 03 fe ff ff                jmp     0x1fb 
> <__htab_map_lookup_elem+0x1fb>
>      3f8: 41 ff c8                      decl    %r8d
>      3fb: 42 ff 24 c5 00 00 00 00       jmpq    *(,%r8,8)
>                 00000000000003ff:  R_X86_64_32S 
> .rodata.hot.__htab_map_lookup_elem
>      403: 44 0f b6 42 0a                movzbl  0xa(%rdx), %r8d
>      408: 41 c1 e0 10                   shll    $0x10, %r8d
> ...
>      45b: 44 0f b6 42 02                movzbl  0x2(%rdx), %r8d
>      460: 41 c1 e0 10                   shll    $0x10, %r8d
>      464: 44 01 c0                      addl    %r8d, %eax
>      467: e9 26 fe ff ff                jmp     0x292 
> <__htab_map_lookup_elem+0x292>
>      46c: 41 89 d8                      movl    %ebx, %r8d
>      46f: 89 c1                         movl    %eax, %ecx
>      471: 89 c5                         movl    %eax, %ebp
>      473: 48 89 f2                      movq    %rsi, %rdx
>      476: e9 0d fe ff ff                jmp     0x288 
> <__htab_map_lookup_elem+0x288>
>      47b: 44 0f b6 42 0b                movzbl  0xb(%rdx), %r8d
>      480: 41 c1 e0 18                   shll    $0x18, %r8d
>      484: 44 01 c5                      addl    %r8d, %ebp
>      487: e9 77 ff ff ff                jmp     0x403 
> <__htab_map_lookup_elem+0x403>
>
> Disassembly of section .text.unlikely.bpf_percpu_hash_update:
>
> So the func __htab_map_lookup_elem() size is 0x48c.
>
> Here, insn 0x3fb is a jump table insn, the following is the actual 
> jump table:
> RELOCATION RECORDS FOR [.rodata.hot.__htab_map_lookup_elem]:
> OFFSET           TYPE                     VALUE
> 0000000000000000 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x29e
> 0000000000000008 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x48c
>                                           <==== problematic one
> 0000000000000010 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x45b
> 0000000000000018 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x44f
> 0000000000000020 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x447
> 0000000000000028 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x43b
> 0000000000000030 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x42f
> 0000000000000038 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x423
> 0000000000000040 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x41b
> 0000000000000048 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x40f
> 0000000000000050 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x403
> 0000000000000058 R_X86_64_64 .text.hot.__htab_map_lookup_elem+0x47b
>
> Note that for the second entry which has 
> .text.hot.__htab_map_lookup_elem+0x48c
> which is right after the last insn. This caused the problem for 
> objtool since
> jump target is not within the function, rather immediately after the 
> function.
>
> There are quite some similar cases in my build.
>
> The llvm18 does not have issues. I tried to bisect what changed in 
> llvm19 and
> found the following llvm patch is responsible:
>
> https://github.com/llvm/llvm-project/pull/96089
>
> Basically, the compiler might be able to create a jump target which 
> actually
> not possible at runtime. For example, in one of examples in the above 
> llvm patch, something
> like
>        if i >= 3 goto out;  /* i unsigned */
>    switch i, label default_unreachable:
>      case 0:  goto label1;
>      case 1:  goto label2;
>      case 2:  goto label3;
>    label1: ...; return;
>    label2: ...; return;
>    label3: ...; return;
>    default_unreachable:
>
> I think that this should be a valid code from compiler perspective.
>
> Can we fix objtool to handle jump target which is immediately after 
> the func body?Thanks, Yonghong
>
>
>   [1] 
> https://patchwork.kernel.org/project/linux-kbuild/patch/20210407211704.367039-1-morbo@google.com/#24246189


  reply	other threads:[~2025-01-30  7:21 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-30  7:10 objtool failure caused some kernel functionality not working Yonghong Song
2025-01-30  7:21 ` Yonghong Song [this message]
2025-01-30  8:25 ` Josh Poimboeuf
2025-01-30 16:30   ` Yonghong Song
2025-02-08  2:16     ` Josh Poimboeuf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=df858dd3-bc4f-4aa3-afe7-15d60cc63afb@linux.dev \
    --to=yonghong.song@linux.dev \
    --cc=jpoimboe@kernel.org \
    --cc=kernel-team@fb.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=peterz@infradead.org \
    --cc=song@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox