mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-11-08 15:30:18 +00:00
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>
This commit is contained in:
parent
fd35c88b74
commit
6f5ec2993b
@ -903,24 +903,24 @@ static struct rela *find_switch_table(struct objtool_file *file,
|
|||||||
{
|
{
|
||||||
struct rela *text_rela, *rodata_rela;
|
struct rela *text_rela, *rodata_rela;
|
||||||
struct instruction *orig_insn = insn;
|
struct instruction *orig_insn = insn;
|
||||||
|
unsigned long table_offset;
|
||||||
|
|
||||||
|
/* case 1 & 2 */
|
||||||
text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
|
text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
|
||||||
if (text_rela && text_rela->sym == file->rodata->sym &&
|
if (text_rela && text_rela->sym == file->rodata->sym &&
|
||||||
!find_symbol_containing(file->rodata, text_rela->addend)) {
|
!find_symbol_containing(file->rodata, text_rela->addend)) {
|
||||||
|
|
||||||
/* case 1 */
|
table_offset = text_rela->addend;
|
||||||
rodata_rela = find_rela_by_dest(file->rodata,
|
if (text_rela->type == R_X86_64_PC32) {
|
||||||
text_rela->addend);
|
/* case 2 */
|
||||||
if (rodata_rela)
|
table_offset += 4;
|
||||||
return rodata_rela;
|
file->ignore_unreachables = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* case 2 */
|
rodata_rela = find_rela_by_dest(file->rodata, table_offset);
|
||||||
rodata_rela = find_rela_by_dest(file->rodata,
|
|
||||||
text_rela->addend + 4);
|
|
||||||
if (!rodata_rela)
|
if (!rodata_rela)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
file->ignore_unreachables = true;
|
|
||||||
return rodata_rela;
|
return rodata_rela;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -954,18 +954,21 @@ static struct rela *find_switch_table(struct objtool_file *file,
|
|||||||
if (!text_rela || text_rela->sym != file->rodata->sym)
|
if (!text_rela || text_rela->sym != file->rodata->sym)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
table_offset = text_rela->addend;
|
||||||
|
if (text_rela->type == R_X86_64_PC32)
|
||||||
|
table_offset += 4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure the .rodata address isn't associated with a
|
* Make sure the .rodata address isn't associated with a
|
||||||
* symbol. gcc jump tables are anonymous data.
|
* symbol. gcc jump tables are anonymous data.
|
||||||
*/
|
*/
|
||||||
if (find_symbol_containing(file->rodata, text_rela->addend))
|
if (find_symbol_containing(file->rodata, table_offset))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend);
|
/* mov [rodata addr], %reg */
|
||||||
if (!rodata_rela)
|
rodata_rela = find_rela_by_dest(file->rodata, table_offset);
|
||||||
continue;
|
if (rodata_rela)
|
||||||
|
return rodata_rela;
|
||||||
return rodata_rela;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user