aboutsummaryrefslogtreecommitdiffstats
path: root/tools/objtool
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2016-04-14 15:52:24 -0400
committerIngo Molnar <mingo@kernel.org>2016-04-15 05:42:13 -0400
commit7e578441a4a3bba2a79426ca0f709c801210d08e (patch)
treeba0a5c34fa911f60a86aec77bf36cd39cf40bace /tools/objtool
parent806fdcce017dc98c4dbf8ed001750a0d7d2bb0af (diff)
objtool: Add workaround for GCC switch jump table bug
GCC has a rare quirk, currently only seen in three driver functions in the kernel, and only with certain obscure non-distro configs, which can cause objtool to produce "unreachable instruction" false positive warnings. As part of an optimization, GCC makes a copy of an existing switch jump table, modifies it, and then hard-codes the jump (albeit with an indirect jump) to use a single entry in the table. The rest of the jump table and some of its jump targets remain as dead code. In such a case we can just crudely ignore all unreachable instruction warnings for the entire object file. Ideally we would just ignore them for the function, but that would require redesigning the code quite a bit. And honestly that's just not worth doing: unreachable instruction warnings are of questionable value anyway, and this is a very rare issue. kbuild reports: https://lkml.kernel.org/r/201603231906.LWcVUpxm%25fengguang.wu@intel.com https://lkml.kernel.org/r/201603271114.K9i45biy%25fengguang.wu@intel.com https://lkml.kernel.org/r/201603291058.zuJ6ben1%25fengguang.wu@intel.com GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70604 Reported-by: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/700fa029bbb0feff34f03ffc69d666a3c3b57a61.1460663532.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/objtool')
-rw-r--r--tools/objtool/builtin-check.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 7515cb2e879a..157a0f96d64d 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -66,6 +66,7 @@ struct objtool_file {
66 struct list_head insn_list; 66 struct list_head insn_list;
67 DECLARE_HASHTABLE(insn_hash, 16); 67 DECLARE_HASHTABLE(insn_hash, 16);
68 struct section *rodata, *whitelist; 68 struct section *rodata, *whitelist;
69 bool ignore_unreachables;
69}; 70};
70 71
71const char *objname; 72const char *objname;
@@ -664,13 +665,40 @@ static int add_func_switch_tables(struct objtool_file *file,
664 text_rela->addend); 665 text_rela->addend);
665 666
666 /* 667 /*
667 * TODO: Document where this is needed, or get rid of it.
668 *
669 * rare case: jmpq *[addr](%rip) 668 * rare case: jmpq *[addr](%rip)
669 *
670 * This check is for a rare gcc quirk, currently only seen in
671 * three driver functions in the kernel, only with certain
672 * obscure non-distro configs.
673 *
674 * As part of an optimization, gcc makes a copy of an existing
675 * switch jump table, modifies it, and then hard-codes the jump
676 * (albeit with an indirect jump) to use a single entry in the
677 * table. The rest of the jump table and some of its jump
678 * targets remain as dead code.
679 *
680 * In such a case we can just crudely ignore all unreachable
681 * instruction warnings for the entire object file. Ideally we
682 * would just ignore them for the function, but that would
683 * require redesigning the code quite a bit. And honestly
684 * that's just not worth doing: unreachable instruction
685 * warnings are of questionable value anyway, and this is such
686 * a rare issue.
687 *
688 * kbuild reports:
689 * - https://lkml.kernel.org/r/201603231906.LWcVUpxm%25fengguang.wu@intel.com
690 * - https://lkml.kernel.org/r/201603271114.K9i45biy%25fengguang.wu@intel.com
691 * - https://lkml.kernel.org/r/201603291058.zuJ6ben1%25fengguang.wu@intel.com
692 *
693 * gcc bug:
694 * - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70604
670 */ 695 */
671 if (!rodata_rela) 696 if (!rodata_rela) {
672 rodata_rela = find_rela_by_dest(file->rodata, 697 rodata_rela = find_rela_by_dest(file->rodata,
673 text_rela->addend + 4); 698 text_rela->addend + 4);
699 if (rodata_rela)
700 file->ignore_unreachables = true;
701 }
674 702
675 if (!rodata_rela) 703 if (!rodata_rela)
676 continue; 704 continue;
@@ -732,9 +760,6 @@ static int decode_sections(struct objtool_file *file)
732{ 760{
733 int ret; 761 int ret;
734 762
735 file->whitelist = find_section_by_name(file->elf, "__func_stack_frame_non_standard");
736 file->rodata = find_section_by_name(file->elf, ".rodata");
737
738 ret = decode_instructions(file); 763 ret = decode_instructions(file);
739 if (ret) 764 if (ret)
740 return ret; 765 return ret;
@@ -1056,13 +1081,14 @@ static int validate_functions(struct objtool_file *file)
1056 if (insn->visited) 1081 if (insn->visited)
1057 continue; 1082 continue;
1058 1083
1059 if (!ignore_unreachable_insn(func, insn) &&
1060 !warnings) {
1061 WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset);
1062 warnings++;
1063 }
1064
1065 insn->visited = true; 1084 insn->visited = true;
1085
1086 if (file->ignore_unreachables || warnings ||
1087 ignore_unreachable_insn(func, insn))
1088 continue;
1089
1090 WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset);
1091 warnings++;
1066 } 1092 }
1067 } 1093 }
1068 } 1094 }
@@ -1133,6 +1159,9 @@ int cmd_check(int argc, const char **argv)
1133 1159
1134 INIT_LIST_HEAD(&file.insn_list); 1160 INIT_LIST_HEAD(&file.insn_list);
1135 hash_init(file.insn_hash); 1161 hash_init(file.insn_hash);
1162 file.whitelist = find_section_by_name(file.elf, "__func_stack_frame_non_standard");
1163 file.rodata = find_section_by_name(file.elf, ".rodata");
1164 file.ignore_unreachables = false;
1136 1165
1137 ret = decode_sections(&file); 1166 ret = decode_sections(&file);
1138 if (ret < 0) 1167 if (ret < 0)