aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2018-05-14 09:53:24 -0400
committerIngo Molnar <mingo@kernel.org>2018-05-15 01:30:59 -0400
commit6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 (patch)
tree9069cef5fd4a462096ba7a7c7b82b2a494dab094
parentfd35c88b74170d9335530d9abf271d5d73eb5401 (diff)
objtool: Detect RIP-relative switch table references
Typically a switch table can be found by detecting a .rodata access followed an indirect jump: 1969: 4a 8b 0c e5 00 00 00 mov 0x0(,%r12,8),%rcx 1970: 00 196d: R_X86_64_32S .rodata+0x438 1971: e9 00 00 00 00 jmpq 1976 <dispc_runtime_suspend+0xb6a> 1972: R_X86_64_PC32 __x86_indirect_thunk_rcx-0x4 Randy Dunlap reported a case (seen with GCC 4.8) where the .rodata access uses RIP-relative addressing: 19bd: 48 8b 3d 00 00 00 00 mov 0x0(%rip),%rdi # 19c4 <dispc_runtime_suspend+0xbb8> 19c0: R_X86_64_PC32 .rodata+0x45c 19c4: e9 00 00 00 00 jmpq 19c9 <dispc_runtime_suspend+0xbbd> 19c5: R_X86_64_PC32 __x86_indirect_thunk_rdi-0x4 In this case the relocation addend needs to be adjusted accordingly in order to find the location of the switch table. The fix is for case 3 (as described in the comments), but also make the existing case 1 & 2 checks more precise by only adjusting the addend for R_X86_64_PC32 relocations. This fixes the following warnings: drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_suspend()+0xbb8: sibling call from callable instruction with modified stack frame drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_resume()+0xcc5: sibling call from callable instruction with modified stack frame Reported-by: Randy Dunlap <rdunlap@infradead.org> 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/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/objtool/check.c33
1 files changed, 18 insertions, 15 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 9bb04fddd3c8..f4bbce838433 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -903,24 +903,24 @@ static struct rela *find_switch_table(struct objtool_file *file,
903{ 903{
904 struct rela *text_rela, *rodata_rela; 904 struct rela *text_rela, *rodata_rela;
905 struct instruction *orig_insn = insn; 905 struct instruction *orig_insn = insn;
906 unsigned long table_offset;
906 907
908 /* case 1 & 2 */
907 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); 909 text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
908 if (text_rela && text_rela->sym == file->rodata->sym && 910 if (text_rela && text_rela->sym == file->rodata->sym &&
909 !find_symbol_containing(file->rodata, text_rela->addend)) { 911 !find_symbol_containing(file->rodata, text_rela->addend)) {
910 912
911 /* case 1 */ 913 table_offset = text_rela->addend;
912 rodata_rela = find_rela_by_dest(file->rodata, 914 if (text_rela->type == R_X86_64_PC32) {
913 text_rela->addend); 915 /* case 2 */
914 if (rodata_rela) 916 table_offset += 4;
915 return rodata_rela; 917 file->ignore_unreachables = true;
918 }
916 919
917 /* case 2 */ 920 rodata_rela = find_rela_by_dest(file->rodata, table_offset);
918 rodata_rela = find_rela_by_dest(file->rodata,
919 text_rela->addend + 4);
920 if (!rodata_rela) 921 if (!rodata_rela)
921 return NULL; 922 return NULL;
922 923
923 file->ignore_unreachables = true;
924 return rodata_rela; 924 return rodata_rela;
925 } 925 }
926 926
@@ -954,18 +954,21 @@ static struct rela *find_switch_table(struct objtool_file *file,
954 if (!text_rela || text_rela->sym != file->rodata->sym) 954 if (!text_rela || text_rela->sym != file->rodata->sym)
955 continue; 955 continue;
956 956
957 table_offset = text_rela->addend;
958 if (text_rela->type == R_X86_64_PC32)
959 table_offset += 4;
960
957 /* 961 /*
958 * Make sure the .rodata address isn't associated with a 962 * Make sure the .rodata address isn't associated with a
959 * symbol. gcc jump tables are anonymous data. 963 * symbol. gcc jump tables are anonymous data.
960 */ 964 */
961 if (find_symbol_containing(file->rodata, text_rela->addend)) 965 if (find_symbol_containing(file->rodata, table_offset))
962 continue;
963
964 rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend);
965 if (!rodata_rela)
966 continue; 966 continue;
967 967
968 return rodata_rela; 968 /* mov [rodata addr], %reg */
969 rodata_rela = find_rela_by_dest(file->rodata, table_offset);
970 if (rodata_rela)
971 return rodata_rela;
969 } 972 }
970 973
971 return NULL; 974 return NULL;