aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2018-05-10 18:48:49 -0400
committerIngo Molnar <mingo@kernel.org>2018-05-14 04:20:54 -0400
commitfd35c88b74170d9335530d9abf271d5d73eb5401 (patch)
treec18e420a070213c083b80ef66dd386830b02f3a6
parent13810435b9a7014fb92eb715f77da488f3b65b99 (diff)
objtool: Support GCC 8 switch tables
With GCC 8, some issues were found with the objtool switch table detection. 1) In the .rodata section, immediately after the switch table, there can be another object which contains a pointer to the function which had the switch statement. In this case objtool wrongly considers the function pointer to be part of the switch table. Fix it by: a) making sure there are no pointers to the beginning of the function; and b) making sure there are no gaps in the switch table. Only the former was needed, the latter adds additional protection for future optimizations. 2) In find_switch_table(), case 1 and case 2 are missing the check to ensure that the .rodata switch table data is anonymous, i.e. that it isn't already associated with an ELF symbol. Fix it by adding the same find_symbol_containing() check which is used for case 3. This fixes the following warnings with GCC 8: drivers/block/virtio_blk.o: warning: objtool: virtio_queue_rq()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+72 net/ipv6/icmp.o: warning: objtool: icmpv6_rcv()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64 drivers/usb/core/quirks.o: warning: objtool: quirks_param_set()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+48 drivers/mtd/nand/raw/nand_hynix.o: warning: objtool: hynix_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+24 drivers/mtd/nand/raw/nand_samsung.o: warning: objtool: samsung_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+32 drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.o: warning: objtool: gk104_top_oneinit()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64 Reported-by: Arnd Bergmann <arnd@arndb.de> Reported-by: kbuild test robot <lkp@intel.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: David Laight <David.Laight@ACULAB.COM> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: damian <damian.tometzki@icloud.com> Link: http://lkml.kernel.org/r/20180510224849.xwi34d6tzheb5wgw@treble Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/objtool/check.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 14daf6a27d9f..9bb04fddd3c8 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -810,17 +810,28 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
810 struct rela *rela = table; 810 struct rela *rela = table;
811 struct instruction *alt_insn; 811 struct instruction *alt_insn;
812 struct alternative *alt; 812 struct alternative *alt;
813 struct symbol *pfunc = insn->func->pfunc;
814 unsigned int prev_offset = 0;
813 815
814 list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { 816 list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
815 if (rela == next_table) 817 if (rela == next_table)
816 break; 818 break;
817 819
820 /* Make sure the switch table entries are consecutive: */
821 if (prev_offset && rela->offset != prev_offset + 8)
822 break;
823
824 /* Detect function pointers from contiguous objects: */
825 if (rela->sym->sec == pfunc->sec &&
826 rela->addend == pfunc->offset)
827 break;
828
818 alt_insn = find_insn(file, rela->sym->sec, rela->addend); 829 alt_insn = find_insn(file, rela->sym->sec, rela->addend);
819 if (!alt_insn) 830 if (!alt_insn)
820 break; 831 break;
821 832
822 /* Make sure the jmp dest is in the function or subfunction: */ 833 /* Make sure the jmp dest is in the function or subfunction: */
823 if (alt_insn->func->pfunc != insn->func->pfunc) 834 if (alt_insn->func->pfunc != pfunc)
824 break; 835 break;
825 836
826 alt = malloc(sizeof(*alt)); 837 alt = malloc(sizeof(*alt));
@@ -831,6 +842,13 @@ static int add_switch_table(struct objtool_file *file, struct instruction *insn,
831 842
832 alt->insn = alt_insn; 843 alt->insn = alt_insn;
833 list_add_tail(&alt->list, &insn->alts); 844 list_add_tail(&alt->list, &insn->alts);
845 prev_offset = rela->offset;
846 }
847
848 if (!prev_offset) {
849 WARN_FUNC("can't find switch jump table",
850 insn->sec, insn->offset);
851 return -1;
834 } 852 }
835 853
836 return 0; 854 return 0;
@@ -887,7 +905,9 @@ static struct rela *find_switch_table(struct objtool_file *file,
887 struct instruction *orig_insn = insn; 905 struct instruction *orig_insn = insn;
888 906
889 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); 907 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
890 if (text_rela && text_rela->sym == file->rodata->sym) { 908 if (text_rela && text_rela->sym == file->rodata->sym &&
909 !find_symbol_containing(file->rodata, text_rela->addend)) {
910
891 /* case 1 */ 911 /* case 1 */
892 rodata_rela = find_rela_by_dest(file->rodata, 912 rodata_rela = find_rela_by_dest(file->rodata,
893 text_rela->addend); 913 text_rela->addend);