From: Josh Poimboeuf <jpoimboe@redhat.com>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org, Peter Zijlstra <peterz@infradead.org>
Subject: [PATCH] objtool: Detect RIP-relative switch table references, part 2
Date: Fri, 18 May 2018 15:10:34 -0500
Message-ID: <f400541613d45689086329432f3095119ffbc328.1526674218.git.jpoimboe@redhat.com> (raw)
With the following commit:
fd35c88b7417 ("objtool: Support GCC 8 switch tables")
I added a "can't find switch jump table" warning, to stop covering up
silent failures if add_switch_table() can't find anything.
That warning found yet another bug in the objtool switch table detection
logic. For cases 1 and 2 (as described in the comments of
find_switch_table), the find_symbol_containing() check doesn't adjust
the offset for RIP-relative switch jumps.
Incidentally, this bug was already fixed for case 3 with:
6f5ec2993b1f ("objtool: Detect RIP-relative switch table references")
However, that commit missed the fix for cases 1 and 2.
The different cases are now starting to look more and more alike. So
fix the bug by consolidating them into a single case, by checking the
original dynamic jump instruction in the case 3 loop.
This also simplifies the code and makes it more robust against future
switch table detection issues -- of which I'm sure there will be many...
Switch table detection has been the most fragile area of objtool, by
far. I long for the day when we'll have a GCC plugin for annotating
switch tables. Linus asked me to delay such a plugin due to the
flakiness of the plugin infrastructure in older versions of GCC, so this
rickety code is what we're stuck with for now. At least the code is now
a little simpler than it was.
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
---
tools/objtool/check.c | 37 ++++++++++++-------------------------
1 file changed, 12 insertions(+), 25 deletions(-)
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4d387448519f..bd26d57accc7 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -905,40 +905,19 @@ static struct rela *find_switch_table(struct objtool_file *file,
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);
- if (text_rela && text_rela->sym == file->rodata->sym &&
- !find_symbol_containing(file->rodata, text_rela->addend)) {
-
- table_offset = text_rela->addend;
- if (text_rela->type == R_X86_64_PC32) {
- /* case 2 */
- table_offset += 4;
- file->ignore_unreachables = true;
- }
-
- rodata_rela = find_rela_by_dest(file->rodata, table_offset);
- if (!rodata_rela)
- return NULL;
-
- return rodata_rela;
- }
-
- /* case 3 */
/*
* Backward search using the @first_jump_src links, these help avoid
* much of the 'in between' code. Which avoids us getting confused by
* it.
*/
- for (insn = list_prev_entry(insn, list);
-
+ for (;
&insn->list != &file->insn_list &&
insn->sec == func->sec &&
insn->offset >= func->offset;
insn = insn->first_jump_src ?: list_prev_entry(insn, list)) {
- if (insn->type == INSN_JUMP_DYNAMIC)
+ if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
break;
/* allow small jumps within the range */
@@ -965,10 +944,18 @@ static struct rela *find_switch_table(struct objtool_file *file,
if (find_symbol_containing(file->rodata, table_offset))
continue;
- /* mov [rodata addr], %reg */
rodata_rela = find_rela_by_dest(file->rodata, table_offset);
- if (rodata_rela)
+ if (rodata_rela) {
+ /*
+ * Use of RIP-relative switch jumps is quite rare, and
+ * indicates a rare GCC quirk/bug which can leave dead
+ * code behind.
+ */
+ if (text_rela->type == R_X86_64_PC32)
+ file->ignore_unreachables = true;
+
return rodata_rela;
+ }
}
return NULL;
--
2.17.0
next reply index
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-18 20:10 Josh Poimboeuf [this message]
2018-05-19 6:13 ` [tip:core/urgent] " tip-bot for Josh Poimboeuf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f400541613d45689086329432f3095119ffbc328.1526674218.git.jpoimboe@redhat.com \
--to=jpoimboe@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
LKML Archive on lore.kernel.org
Archives are clonable:
git clone --mirror https://lore.kernel.org/lkml/0 lkml/git/0.git
git clone --mirror https://lore.kernel.org/lkml/1 lkml/git/1.git
git clone --mirror https://lore.kernel.org/lkml/2 lkml/git/2.git
git clone --mirror https://lore.kernel.org/lkml/3 lkml/git/3.git
git clone --mirror https://lore.kernel.org/lkml/4 lkml/git/4.git
git clone --mirror https://lore.kernel.org/lkml/5 lkml/git/5.git
git clone --mirror https://lore.kernel.org/lkml/6 lkml/git/6.git
git clone --mirror https://lore.kernel.org/lkml/7 lkml/git/7.git
git clone --mirror https://lore.kernel.org/lkml/8 lkml/git/8.git
git clone --mirror https://lore.kernel.org/lkml/9 lkml/git/9.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 lkml lkml/ https://lore.kernel.org/lkml \
linux-kernel@vger.kernel.org
public-inbox-index lkml
Example config snippet for mirrors
Newsgroup available over NNTP:
nntp://nntp.lore.kernel.org/org.kernel.vger.linux-kernel
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git