]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
objtool: Allow arch code to discover jump table size
authorArd Biesheuvel <ardb@kernel.org>
Fri, 11 Oct 2024 17:08:50 +0000 (19:08 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 2 Dec 2024 11:24:29 +0000 (12:24 +0100)
In preparation for adding support for annotated jump tables, where
ELF relocations and symbols are used to describe the locations of jump
tables in the executable, refactor the jump table discovery logic so the
table size can be returned from arch_find_switch_table().

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20241011170847.334429-12-ardb+git@google.com
tools/objtool/arch/loongarch/special.c
tools/objtool/arch/powerpc/special.c
tools/objtool/arch/x86/special.c
tools/objtool/check.c
tools/objtool/include/objtool/check.h
tools/objtool/include/objtool/special.h

index 9bba1e9318e0ba9ba2c7b79c9c980c8309a507e1..87230ed570fd0706620014928cedf8c60f299ae8 100644 (file)
@@ -9,7 +9,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
 }
 
 struct reloc *arch_find_switch_table(struct objtool_file *file,
-                                    struct instruction *insn)
+                                    struct instruction *insn,
+                                    unsigned long *table_size)
 {
        return NULL;
 }
index d33868147196a763d3234eb1fdc26bceb7e09fce..51610689abf72a8b1bb3ca2716aeb933653d8e91 100644 (file)
@@ -13,7 +13,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
 }
 
 struct reloc *arch_find_switch_table(struct objtool_file *file,
-                                   struct instruction *insn)
+                                    struct instruction *insn,
+                                    unsigned long *table_size)
 {
        exit(-1);
 }
index 4ea0f9815fda4e6ca3709d1491f37ce29d2e2b40..9c1c9df09aaa4b4a41b31d1142bf4d8a26664dff 100644 (file)
@@ -109,7 +109,8 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
  *    NOTE: MITIGATION_RETPOLINE made it harder still to decode dynamic jumps.
  */
 struct reloc *arch_find_switch_table(struct objtool_file *file,
-                                   struct instruction *insn)
+                                    struct instruction *insn,
+                                    unsigned long *table_size)
 {
        struct reloc  *text_reloc, *rodata_reloc;
        struct section *table_sec;
@@ -158,5 +159,6 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
        if (reloc_type(text_reloc) == R_X86_64_PC32)
                file->ignore_unreachables = true;
 
+       *table_size = 0;
        return rodata_reloc;
 }
index bfb407f3ac9686288127167b660ea61b5afe98c5..e92c5564d9ca808be99ff09b7f6871fd5e76fccb 100644 (file)
@@ -150,6 +150,15 @@ static inline struct reloc *insn_jump_table(struct instruction *insn)
        return NULL;
 }
 
+static inline unsigned long insn_jump_table_size(struct instruction *insn)
+{
+       if (insn->type == INSN_JUMP_DYNAMIC ||
+           insn->type == INSN_CALL_DYNAMIC)
+               return insn->_jump_table_size;
+
+       return 0;
+}
+
 static bool is_jump_table_jump(struct instruction *insn)
 {
        struct alt_group *alt_group = insn->alt_group;
@@ -1937,6 +1946,7 @@ out:
 static int add_jump_table(struct objtool_file *file, struct instruction *insn,
                          struct reloc *next_table)
 {
+       unsigned long table_size = insn_jump_table_size(insn);
        struct symbol *pfunc = insn_func(insn)->pfunc;
        struct reloc *table = insn_jump_table(insn);
        struct instruction *dest_insn;
@@ -1951,6 +1961,8 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
        for_each_reloc_from(table->sec, reloc) {
 
                /* Check for the end of the table: */
+               if (table_size && reloc_offset(reloc) - reloc_offset(table) >= table_size)
+                       break;
                if (reloc != table && reloc == next_table)
                        break;
 
@@ -1995,12 +2007,12 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
  * find_jump_table() - Given a dynamic jump, find the switch jump table
  * associated with it.
  */
-static struct reloc *find_jump_table(struct objtool_file *file,
-                                     struct symbol *func,
-                                     struct instruction *insn)
+static void find_jump_table(struct objtool_file *file, struct symbol *func,
+                           struct instruction *insn)
 {
        struct reloc *table_reloc;
        struct instruction *dest_insn, *orig_insn = insn;
+       unsigned long table_size;
 
        /*
         * Backward search using the @first_jump_src links, these help avoid
@@ -2021,17 +2033,17 @@ static struct reloc *find_jump_table(struct objtool_file *file,
                     insn->jump_dest->offset > orig_insn->offset))
                    break;
 
-               table_reloc = arch_find_switch_table(file, insn);
+               table_reloc = arch_find_switch_table(file, insn, &table_size);
                if (!table_reloc)
                        continue;
                dest_insn = find_insn(file, table_reloc->sym->sec, reloc_addend(table_reloc));
                if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
                        continue;
 
-               return table_reloc;
+               orig_insn->_jump_table = table_reloc;
+               orig_insn->_jump_table_size = table_size;
+               break;
        }
-
-       return NULL;
 }
 
 /*
@@ -2042,7 +2054,6 @@ static void mark_func_jump_tables(struct objtool_file *file,
                                    struct symbol *func)
 {
        struct instruction *insn, *last = NULL;
-       struct reloc *reloc;
 
        func_for_each_insn(file, func, insn) {
                if (!last)
@@ -2065,9 +2076,7 @@ static void mark_func_jump_tables(struct objtool_file *file,
                if (insn->type != INSN_JUMP_DYNAMIC)
                        continue;
 
-               reloc = find_jump_table(file, func, insn);
-               if (reloc)
-                       insn->_jump_table = reloc;
+               find_jump_table(file, func, insn);
        }
 }
 
index daa46f1f0965ad7f390bef7c6dc2e1e9eb2fd2cd..e1cd13cd28a377840a48d2d6eb3bca8a356c0463 100644 (file)
@@ -71,7 +71,10 @@ struct instruction {
        struct instruction *first_jump_src;
        union {
                struct symbol *_call_dest;
-               struct reloc *_jump_table;
+               struct {
+                       struct reloc *_jump_table;
+                       unsigned long _jump_table_size;
+               };
        };
        struct alternative *alts;
        struct symbol *sym;
index 86d4af9c5aa9dc83cd543a140ab1979979a1d6fa..e7ee7ffccefd4d4ef520767b1c3a4f86f042780b 100644 (file)
@@ -38,5 +38,6 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
                                 struct instruction *insn,
                                 struct reloc *reloc);
 struct reloc *arch_find_switch_table(struct objtool_file *file,
-                                   struct instruction *insn);
+                                    struct instruction *insn,
+                                    unsigned long *table_size);
 #endif /* _SPECIAL_H */