summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@kernel.org>2025-03-24 14:55:51 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-04-10 14:44:35 +0200
commit88e923d140fa77cad6d5d6ea44d6fa6b55c59d7b (patch)
tree4d8c38fdd78e668cf80ccce147b5862bcc3675e9 /tools
parenta7a8e0ccaf730b25b36d63bd4260307e99c5cda8 (diff)
downloadlinux-88e923d140fa77cad6d5d6ea44d6fa6b55c59d7b.tar.gz
linux-88e923d140fa77cad6d5d6ea44d6fa6b55c59d7b.tar.bz2
linux-88e923d140fa77cad6d5d6ea44d6fa6b55c59d7b.zip
objtool: Fix detection of consecutive jump tables on Clang 20
[ Upstream commit ef753d66051ca03bee1982ce047f9eaf90f81ab4 ] The jump table detection code assumes jump tables are in the same order as their corresponding indirect branches. That's apparently not always true with Clang 20. Fix that by changing how multiple jump tables are detected. In the first detection pass, mark the beginning of each jump table so the second pass can tell where one ends and the next one begins. Fixes the following warnings: vmlinux.o: warning: objtool: SiS_GetCRT2Ptr+0x1ad: stack state mismatch: cfa1=4+8 cfa2=5+16 sound/core/seq/snd-seq.o: warning: objtool: cc_ev_to_ump_midi2+0x589: return with modified stack frame Fixes: be2f0b1e1264 ("objtool: Get rid of reloc->jump_table_start") Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Cc: Nathan Chancellor <nathan@kernel.org> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lore.kernel.org/r/141752fff614eab962dba6bdfaa54aa67ff03bba.1742852846.git.jpoimboe@kernel.org Closes: https://lore.kernel.org/oe-kbuild-all/202503171547.LlCTJLQL-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202503200535.J3hAvcjw-lkp@intel.com/ Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/objtool/check.c26
-rw-r--r--tools/objtool/elf.c6
-rw-r--r--tools/objtool/include/objtool/elf.h27
3 files changed, 37 insertions, 22 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 12bf6c1f5071..813e708c1649 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1949,8 +1949,7 @@ __weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct relo
return reloc->sym->offset + reloc_addend(reloc);
}
-static int add_jump_table(struct objtool_file *file, struct instruction *insn,
- struct reloc *next_table)
+static int add_jump_table(struct objtool_file *file, struct instruction *insn)
{
unsigned long table_size = insn_jump_table_size(insn);
struct symbol *pfunc = insn_func(insn)->pfunc;
@@ -1970,7 +1969,7 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
/* 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)
+ if (reloc != table && is_jump_table(reloc))
break;
/* Make sure the table entries are consecutive: */
@@ -2061,8 +2060,10 @@ static void find_jump_table(struct objtool_file *file, struct symbol *func,
if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != func)
continue;
+ set_jump_table(table_reloc);
orig_insn->_jump_table = table_reloc;
orig_insn->_jump_table_size = table_size;
+
break;
}
}
@@ -2104,31 +2105,20 @@ static void mark_func_jump_tables(struct objtool_file *file,
static int add_func_jump_tables(struct objtool_file *file,
struct symbol *func)
{
- struct instruction *insn, *insn_t1 = NULL, *insn_t2;
- int ret = 0;
+ struct instruction *insn;
+ int ret;
func_for_each_insn(file, func, insn) {
if (!insn_jump_table(insn))
continue;
- if (!insn_t1) {
- insn_t1 = insn;
- continue;
- }
-
- insn_t2 = insn;
- ret = add_jump_table(file, insn_t1, insn_jump_table(insn_t2));
+ ret = add_jump_table(file, insn);
if (ret)
return ret;
-
- insn_t1 = insn_t2;
}
- if (insn_t1)
- ret = add_jump_table(file, insn_t1, NULL);
-
- return ret;
+ return 0;
}
/*
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 6f64d611faea..934855be631c 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -583,7 +583,7 @@ static int elf_update_sym_relocs(struct elf *elf, struct symbol *sym)
{
struct reloc *reloc;
- for (reloc = sym->relocs; reloc; reloc = reloc->sym_next_reloc)
+ for (reloc = sym->relocs; reloc; reloc = sym_next_reloc(reloc))
set_reloc_sym(elf, reloc, reloc->sym->idx);
return 0;
@@ -880,7 +880,7 @@ static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
set_reloc_addend(elf, reloc, addend);
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
- reloc->sym_next_reloc = sym->relocs;
+ set_sym_next_reloc(reloc, sym->relocs);
sym->relocs = reloc;
return reloc;
@@ -979,7 +979,7 @@ static int read_relocs(struct elf *elf)
}
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
- reloc->sym_next_reloc = sym->relocs;
+ set_sym_next_reloc(reloc, sym->relocs);
sym->relocs = reloc;
nr_reloc++;
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index d7e815c2fd15..764cba535f22 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -77,7 +77,7 @@ struct reloc {
struct elf_hash_node hash;
struct section *sec;
struct symbol *sym;
- struct reloc *sym_next_reloc;
+ unsigned long _sym_next_reloc;
};
struct elf {
@@ -297,6 +297,31 @@ static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned
mark_sec_changed(elf, reloc->sec, true);
}
+#define RELOC_JUMP_TABLE_BIT 1UL
+
+/* Does reloc mark the beginning of a jump table? */
+static inline bool is_jump_table(struct reloc *reloc)
+{
+ return reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
+}
+
+static inline void set_jump_table(struct reloc *reloc)
+{
+ reloc->_sym_next_reloc |= RELOC_JUMP_TABLE_BIT;
+}
+
+static inline struct reloc *sym_next_reloc(struct reloc *reloc)
+{
+ return (struct reloc *)(reloc->_sym_next_reloc & ~RELOC_JUMP_TABLE_BIT);
+}
+
+static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)
+{
+ unsigned long bit = reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
+
+ reloc->_sym_next_reloc = (unsigned long)next | bit;
+}
+
#define for_each_sec(file, sec) \
list_for_each_entry(sec, &file->elf->sections, list)