aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2017-03-02 17:57:23 -0500
committerIngo Molnar <mingo@kernel.org>2017-03-07 02:42:55 -0500
commit5c51f4ae84df0f9df33ac08aa5be50061a8b4242 (patch)
tree9e301e1fb51b970b742c6bf37e4f4ec622d1322c
parentbb35e4515411396219431fa235bf21bf9c2794e9 (diff)
objtool: Fix another GCC jump table detection issue
Arnd Bergmann reported a (false positive) objtool warning: drivers/infiniband/sw/rxe/rxe_resp.o: warning: objtool: rxe_responder()+0xfe: sibling call from callable instruction with changed frame pointer The issue is in find_switch_table(). It tries to find a switch statement's jump table by walking backwards from an indirect jump instruction, looking for a relocation to the .rodata section. In this case it stopped walking prematurely: the first .rodata relocation it encountered was for a variable (resp_state_name) instead of a jump table, so it just assumed there wasn't a jump table. The fix is to ignore any .rodata relocation which refers to an ELF object symbol. This works because the jump tables are anonymous and have no symbols associated with them. Reported-by: Arnd Bergmann <arnd@arndb.de> Tested-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Fixes: 3732710ff6f2 ("objtool: Improve rare switch jump table pattern detection") Link: http://lkml.kernel.org/r/20170302225723.3ndbsnl4hkqbne7a@treble Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/objtool/builtin-check.c15
-rw-r--r--tools/objtool/elf.c12
-rw-r--r--tools/objtool/elf.h1
3 files changed, 25 insertions, 3 deletions
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 4cfdbb5b6967..066086dd59a8 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -805,11 +805,20 @@ static struct rela *find_switch_table(struct objtool_file *file,
805 insn->jump_dest->offset > orig_insn->offset)) 805 insn->jump_dest->offset > orig_insn->offset))
806 break; 806 break;
807 807
808 /* look for a relocation which references .rodata */
808 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, 809 text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
809 insn->len); 810 insn->len);
810 if (text_rela && text_rela->sym == file->rodata->sym) 811 if (!text_rela || text_rela->sym != file->rodata->sym)
811 return find_rela_by_dest(file->rodata, 812 continue;
812 text_rela->addend); 813
814 /*
815 * Make sure the .rodata address isn't associated with a
816 * symbol. gcc jump tables are anonymous data.
817 */
818 if (find_symbol_containing(file->rodata, text_rela->addend))
819 continue;
820
821 return find_rela_by_dest(file->rodata, text_rela->addend);
813 } 822 }
814 823
815 return NULL; 824 return NULL;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 0d7983ac63ef..d897702ce742 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -85,6 +85,18 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
85 return NULL; 85 return NULL;
86} 86}
87 87
88struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
89{
90 struct symbol *sym;
91
92 list_for_each_entry(sym, &sec->symbol_list, list)
93 if (sym->type != STT_SECTION &&
94 offset >= sym->offset && offset < sym->offset + sym->len)
95 return sym;
96
97 return NULL;
98}
99
88struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 100struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
89 unsigned int len) 101 unsigned int len)
90{ 102{
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index aa1ff6596684..731973e1a3f5 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -79,6 +79,7 @@ struct elf {
79struct elf *elf_open(const char *name); 79struct elf *elf_open(const char *name);
80struct section *find_section_by_name(struct elf *elf, const char *name); 80struct section *find_section_by_name(struct elf *elf, const char *name);
81struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); 81struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
82struct symbol *find_symbol_containing(struct section *sec, unsigned long offset);
82struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); 83struct rela *find_rela_by_dest(struct section *sec, unsigned long offset);
83struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 84struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
84 unsigned int len); 85 unsigned int len);