]>
Commit | Line | Data |
---|---|---|
9ff8ff93 GKH |
1 | From 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 Mon Sep 17 00:00:00 2001 |
2 | From: Josh Poimboeuf <jpoimboe@redhat.com> | |
3 | Date: Mon, 14 May 2018 08:53:24 -0500 | |
4 | Subject: objtool: Detect RIP-relative switch table references | |
5 | ||
6 | From: Josh Poimboeuf <jpoimboe@redhat.com> | |
7 | ||
8 | commit 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 upstream. | |
9 | ||
10 | Typically a switch table can be found by detecting a .rodata access | |
11 | followed an indirect jump: | |
12 | ||
13 | 1969: 4a 8b 0c e5 00 00 00 mov 0x0(,%r12,8),%rcx | |
14 | 1970: 00 | |
15 | 196d: R_X86_64_32S .rodata+0x438 | |
16 | 1971: e9 00 00 00 00 jmpq 1976 <dispc_runtime_suspend+0xb6a> | |
17 | 1972: R_X86_64_PC32 __x86_indirect_thunk_rcx-0x4 | |
18 | ||
19 | Randy Dunlap reported a case (seen with GCC 4.8) where the .rodata | |
20 | access uses RIP-relative addressing: | |
21 | ||
22 | 19bd: 48 8b 3d 00 00 00 00 mov 0x0(%rip),%rdi # 19c4 <dispc_runtime_suspend+0xbb8> | |
23 | 19c0: R_X86_64_PC32 .rodata+0x45c | |
24 | 19c4: e9 00 00 00 00 jmpq 19c9 <dispc_runtime_suspend+0xbbd> | |
25 | 19c5: R_X86_64_PC32 __x86_indirect_thunk_rdi-0x4 | |
26 | ||
27 | In this case the relocation addend needs to be adjusted accordingly in | |
28 | order to find the location of the switch table. | |
29 | ||
30 | The fix is for case 3 (as described in the comments), but also make the | |
31 | existing case 1 & 2 checks more precise by only adjusting the addend for | |
32 | R_X86_64_PC32 relocations. | |
33 | ||
34 | This fixes the following warnings: | |
35 | ||
36 | drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_suspend()+0xbb8: sibling call from callable instruction with modified stack frame | |
37 | drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_resume()+0xcc5: sibling call from callable instruction with modified stack frame | |
38 | ||
39 | Reported-by: Randy Dunlap <rdunlap@infradead.org> | |
40 | Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> | |
41 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
42 | Cc: Peter Zijlstra <peterz@infradead.org> | |
43 | Cc: Thomas Gleixner <tglx@linutronix.de> | |
44 | Link: http://lkml.kernel.org/r/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com | |
45 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
46 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
47 | ||
48 | --- | |
49 | tools/objtool/check.c | 33 ++++++++++++++++++--------------- | |
50 | 1 file changed, 18 insertions(+), 15 deletions(-) | |
51 | ||
52 | --- a/tools/objtool/check.c | |
53 | +++ b/tools/objtool/check.c | |
54 | @@ -898,24 +898,24 @@ static struct rela *find_switch_table(st | |
55 | { | |
56 | struct rela *text_rela, *rodata_rela; | |
57 | struct instruction *orig_insn = insn; | |
58 | + unsigned long table_offset; | |
59 | ||
60 | + /* case 1 & 2 */ | |
61 | text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); | |
62 | if (text_rela && text_rela->sym == file->rodata->sym && | |
63 | !find_symbol_containing(file->rodata, text_rela->addend)) { | |
64 | ||
65 | - /* case 1 */ | |
66 | - rodata_rela = find_rela_by_dest(file->rodata, | |
67 | - text_rela->addend); | |
68 | - if (rodata_rela) | |
69 | - return rodata_rela; | |
70 | + table_offset = text_rela->addend; | |
71 | + if (text_rela->type == R_X86_64_PC32) { | |
72 | + /* case 2 */ | |
73 | + table_offset += 4; | |
74 | + file->ignore_unreachables = true; | |
75 | + } | |
76 | ||
77 | - /* case 2 */ | |
78 | - rodata_rela = find_rela_by_dest(file->rodata, | |
79 | - text_rela->addend + 4); | |
80 | + rodata_rela = find_rela_by_dest(file->rodata, table_offset); | |
81 | if (!rodata_rela) | |
82 | return NULL; | |
83 | ||
84 | - file->ignore_unreachables = true; | |
85 | return rodata_rela; | |
86 | } | |
87 | ||
88 | @@ -949,18 +949,21 @@ static struct rela *find_switch_table(st | |
89 | if (!text_rela || text_rela->sym != file->rodata->sym) | |
90 | continue; | |
91 | ||
92 | + table_offset = text_rela->addend; | |
93 | + if (text_rela->type == R_X86_64_PC32) | |
94 | + table_offset += 4; | |
95 | + | |
96 | /* | |
97 | * Make sure the .rodata address isn't associated with a | |
98 | * symbol. gcc jump tables are anonymous data. | |
99 | */ | |
100 | - if (find_symbol_containing(file->rodata, text_rela->addend)) | |
101 | + if (find_symbol_containing(file->rodata, table_offset)) | |
102 | continue; | |
103 | ||
104 | - rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend); | |
105 | - if (!rodata_rela) | |
106 | - continue; | |
107 | - | |
108 | - return rodata_rela; | |
109 | + /* mov [rodata addr], %reg */ | |
110 | + rodata_rela = find_rela_by_dest(file->rodata, table_offset); | |
111 | + if (rodata_rela) | |
112 | + return rodata_rela; | |
113 | } | |
114 | ||
115 | return NULL; |