objtool: Don't set 'jump_dest' for sibling calls
authorJosh Poimboeuf <jpoimboe@redhat.com>
Mon, 11 Apr 2022 23:10:30 +0000 (16:10 -0700)
committerPeter Zijlstra <peterz@infradead.org>
Tue, 19 Apr 2022 19:58:53 +0000 (21:58 +0200)
For most sibling calls, 'jump_dest' is NULL because objtool treats the
jump like a call and sets 'call_dest'.  But there are a few edge cases
where that's not true.  Make it consistent to avoid unexpected behavior.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/8737d6b9d1691831aed73375f444f0f42da3e2c9.1649718562.git.jpoimboe@redhat.com
tools/objtool/check.c

index bd0c2c8..6f49278 100644 (file)
@@ -1271,7 +1271,7 @@ static bool is_first_func_insn(struct objtool_file *file, struct instruction *in
  */
 static int add_jump_destinations(struct objtool_file *file)
 {
-       struct instruction *insn;
+       struct instruction *insn, *jump_dest;
        struct reloc *reloc;
        struct section *dest_sec;
        unsigned long dest_off;
@@ -1291,7 +1291,10 @@ static int add_jump_destinations(struct objtool_file *file)
                        add_retpoline_call(file, insn);
                        continue;
                } else if (insn->func) {
-                       /* internal or external sibling call (with reloc) */
+                       /*
+                        * External sibling call or internal sibling call with
+                        * STT_FUNC reloc.
+                        */
                        add_call_dest(file, insn, reloc->sym, true);
                        continue;
                } else if (reloc->sym->sec->idx) {
@@ -1303,8 +1306,8 @@ static int add_jump_destinations(struct objtool_file *file)
                        continue;
                }
 
-               insn->jump_dest = find_insn(file, dest_sec, dest_off);
-               if (!insn->jump_dest) {
+               jump_dest = find_insn(file, dest_sec, dest_off);
+               if (!jump_dest) {
 
                        /*
                         * This is a special case where an alt instruction
@@ -1323,8 +1326,8 @@ static int add_jump_destinations(struct objtool_file *file)
                /*
                 * Cross-function jump.
                 */
-               if (insn->func && insn->jump_dest->func &&
-                   insn->func != insn->jump_dest->func) {
+               if (insn->func && jump_dest->func &&
+                   insn->func != jump_dest->func) {
 
                        /*
                         * For GCC 8+, create parent/child links for any cold
@@ -1342,16 +1345,22 @@ static int add_jump_destinations(struct objtool_file *file)
                         * subfunction is through a jump table.
                         */
                        if (!strstr(insn->func->name, ".cold") &&
-                           strstr(insn->jump_dest->func->name, ".cold")) {
-                               insn->func->cfunc = insn->jump_dest->func;
-                               insn->jump_dest->func->pfunc = insn->func;
+                           strstr(jump_dest->func->name, ".cold")) {
+                               insn->func->cfunc = jump_dest->func;
+                               jump_dest->func->pfunc = insn->func;
 
-                       } else if (!same_function(insn, insn->jump_dest) &&
-                                  is_first_func_insn(file, insn->jump_dest)) {
-                               /* internal sibling call (without reloc) */
-                               add_call_dest(file, insn, insn->jump_dest->func, true);
+                       } else if (!same_function(insn, jump_dest) &&
+                                  is_first_func_insn(file, jump_dest)) {
+                               /*
+                                * Internal sibling call without reloc or with
+                                * STT_SECTION reloc.
+                                */
+                               add_call_dest(file, insn, jump_dest->func, true);
+                               continue;
                        }
                }
+
+               insn->jump_dest = jump_dest;
        }
 
        return 0;