On 5/9/25 4:16 PM, Josh Poimboeuf wrote:
> The add_jump_destinations() logic is a bit weird and convoluted after
> being incrementally tweaked over the years.  Refactor it to hopefully be
> more logical and straightforward.
> 
> Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org>
> ---
>  tools/objtool/check.c               | 227 +++++++++++++---------------
>  tools/objtool/include/objtool/elf.h |   4 +-
>  2 files changed, 104 insertions(+), 127 deletions(-)
> 
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index 66cbeebd16ea..e4ca5edf73ad 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -1439,9 +1439,14 @@ static void add_return_call(struct objtool_file *file, 
> struct instruction *insn,
>  }
>  
>  static bool is_first_func_insn(struct objtool_file *file,
> -                            struct instruction *insn, struct symbol *sym)
> +                            struct instruction *insn)
>  {
> -     if (insn->offset == sym->offset)
> +     struct symbol *func = insn_func(insn);
> +
> +     if (!func)
> +             return false;
> +
> +     if (insn->offset == func->offset)
>               return true;
>  
>       /* Allow direct CALL/JMP past ENDBR */
> @@ -1449,52 +1454,32 @@ static bool is_first_func_insn(struct objtool_file 
> *file,
>               struct instruction *prev = prev_insn_same_sym(file, insn);
>  
>               if (prev && prev->type == INSN_ENDBR &&
> -                 insn->offset == sym->offset + prev->len)
> +                 insn->offset == func->offset + prev->len)
>                       return true;
>       }
>  
>       return false;
>  }
>  
> -/*
> - * A sibling call is a tail-call to another symbol -- to differentiate from a
> - * recursive tail-call which is to the same symbol.
> - */
> -static bool jump_is_sibling_call(struct objtool_file *file,
> -                              struct instruction *from, struct instruction 
> *to)
> -{
> -     struct symbol *fs = from->sym;
> -     struct symbol *ts = to->sym;
> -
> -     /* Not a sibling call if from/to a symbol hole */
> -     if (!fs || !ts)
> -             return false;
> -
> -     /* Not a sibling call if not targeting the start of a symbol. */
> -     if (!is_first_func_insn(file, to, ts))
> -             return false;
> -
> -     /* Disallow sibling calls into STT_NOTYPE */
> -     if (is_notype_sym(ts))
> -             return false;
> -
> -     /* Must not be self to be a sibling */
> -     return fs->pfunc != ts->pfunc;
> -}
> -
>  /*
>   * Find the destination instructions for all jumps.
>   */
>  static int add_jump_destinations(struct objtool_file *file)
>  {
> -     struct instruction *insn, *jump_dest;
> +     struct instruction *insn;
>       struct reloc *reloc;
> -     struct section *dest_sec;
> -     unsigned long dest_off;
>       int ret;
>  
>       for_each_insn(file, insn) {
>               struct symbol *func = insn_func(insn);
> +             struct instruction *dest_insn;
> +             struct section *dest_sec;
> +             struct symbol *dest_sym;
> +             unsigned long dest_off;
> +             bool dest_undef = false;
> +
> +             if (!is_static_jump(insn))
> +                     continue;
>  
>               if (insn->jump_dest) {
>                       /*
> @@ -1503,129 +1488,121 @@ static int add_jump_destinations(struct 
> objtool_file *file)
>                        */
>                       continue;
>               }
> -             if (!is_static_jump(insn))
> -                     continue;
>  
>               reloc = insn_reloc(file, insn);
>               if (!reloc) {
>                       dest_sec = insn->sec;
>                       dest_off = arch_jump_destination(insn);
> -             } else if (is_sec_sym(reloc->sym)) {
> +             } else if (is_undef_sym(reloc->sym)) {
> +                     dest_sym = reloc->sym;
> +                     dest_undef = true;
> +             } else {
>                       dest_sec = reloc->sym->sec;
> -                     dest_off = arch_insn_adjusted_addend(insn, reloc);
> -             } else if (reloc->sym->retpoline_thunk) {
> +                     dest_off = reloc->sym->sym.st_value +
> +                                arch_insn_adjusted_addend(insn, reloc);
> +             }
> +
> +             if (!dest_undef) {
> +                     dest_insn = find_insn(file, dest_sec, dest_off);
> +                     if (!dest_insn) {
> +                             struct symbol *sym = 
> find_symbol_by_offset(dest_sec, dest_off);
> +
> +                             /*
> +                              * retbleed_untrain_ret() jumps to
> +                              * __x86_return_thunk(), but objtool can't find
> +                              * the thunk's starting RET instruction,
> +                              * because the RET is also in the middle of
> +                              * another instruction.  Objtool only knows
> +                              * about the outer instruction.
> +                              */
> +                             if (sym && sym->embedded_insn) {
> +                                     add_return_call(file, insn, false);
> +                                     continue;
> +                             }
> +
> +                             /*
> +                              * GCOV/KCOV dead code can jump to the end of
> +                              * the function/section.
> +                              */
> +                             if (file->ignore_unreachables && func &&
> +                                 dest_sec == insn->sec &&
> +                                 dest_off == func->offset + func->len)
> +                                     continue;
> +
> +                             ERROR_INSN(insn, "can't find jump dest 
> instruction at %s+0x%lx",
> +                                       dest_sec->name, dest_off);
> +                             return -1;
> +                     }
> +
> +                     dest_sym = dest_insn->sym;
> +                     if (!dest_sym)
> +                             goto set_jump_dest;
> +             }
> +
> +             if (dest_sym->retpoline_thunk) {
>                       ret = add_retpoline_call(file, insn);
>                       if (ret)
>                               return ret;
>                       continue;
> -             } else if (reloc->sym->return_thunk) {
> +             }
> +
> +             if (dest_sym->return_thunk) {
>                       add_return_call(file, insn, true);
>                       continue;
> -             } else if (func) {
> -                     /*
> -                      * External sibling call or internal sibling call with
> -                      * STT_FUNC reloc.
> -                      */
> -                     ret = add_call_dest(file, insn, reloc->sym, true);
> -                     if (ret)
> -                             return ret;
> -                     continue;
> -             } else if (reloc->sym->sec->idx) {
> -                     dest_sec = reloc->sym->sec;
> -                     dest_off = reloc->sym->sym.st_value +
> -                                arch_dest_reloc_offset(reloc_addend(reloc));

Way back in ("[PATCH v2 18/62] objtool: Fix x86 addend calculation"),
arch_dest_reloc_offset() was replaced with arch_insn_adjusted_addend(),
so I think that patch missed this callsite and breaks bisectability.

-- 
Joe


Reply via email to