objtool: optimize add_dead_ends for split sections
authorSami Tolvanen <samitolvanen@google.com>
Tue, 21 Apr 2020 22:08:43 +0000 (15:08 -0700)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 15 May 2020 08:35:13 +0000 (10:35 +0200)
Instead of iterating through all instructions to find the last
instruction each time .rela.discard.(un)reachable points beyond the
section, use find_insn to locate the last instruction by looking at
the last bytes of the section instead.

Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20200421220843.188260-3-samitolvanen@google.com
tools/objtool/check.c

index 196a551..6b2b458 100644 (file)
@@ -322,6 +322,19 @@ err:
        return ret;
 }
 
+static struct instruction *find_last_insn(struct objtool_file *file,
+                                         struct section *sec)
+{
+       struct instruction *insn = NULL;
+       unsigned int offset;
+       unsigned int end = (sec->len > 10) ? sec->len - 10 : 0;
+
+       for (offset = sec->len - 1; offset >= end && !insn; offset--)
+               insn = find_insn(file, sec, offset);
+
+       return insn;
+}
+
 /*
  * Mark "ud2" instructions and manually annotated dead ends.
  */
@@ -330,7 +343,6 @@ static int add_dead_ends(struct objtool_file *file)
        struct section *sec;
        struct rela *rela;
        struct instruction *insn;
-       bool found;
 
        /*
         * By default, "ud2" is a dead end unless otherwise annotated, because
@@ -356,15 +368,8 @@ static int add_dead_ends(struct objtool_file *file)
                if (insn)
                        insn = list_prev_entry(insn, list);
                else if (rela->addend == rela->sym->sec->len) {
-                       found = false;
-                       list_for_each_entry_reverse(insn, &file->insn_list, list) {
-                               if (insn->sec == rela->sym->sec) {
-                                       found = true;
-                                       break;
-                               }
-                       }
-
-                       if (!found) {
+                       insn = find_last_insn(file, rela->sym->sec);
+                       if (!insn) {
                                WARN("can't find unreachable insn at %s+0x%x",
                                     rela->sym->sec->name, rela->addend);
                                return -1;
@@ -398,15 +403,8 @@ reachable:
                if (insn)
                        insn = list_prev_entry(insn, list);
                else if (rela->addend == rela->sym->sec->len) {
-                       found = false;
-                       list_for_each_entry_reverse(insn, &file->insn_list, list) {
-                               if (insn->sec == rela->sym->sec) {
-                                       found = true;
-                                       break;
-                               }
-                       }
-
-                       if (!found) {
+                       insn = find_last_insn(file, rela->sym->sec);
+                       if (!insn) {
                                WARN("can't find reachable insn at %s+0x%x",
                                     rela->sym->sec->name, rela->addend);
                                return -1;