From: Julien Thierry <jthierry@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: jpoimboe@redhat.com, peterz@infradead.org, mbenes@suse.cz,
raphael.gault@arm.com, Julien Thierry <jthierry@redhat.com>
Subject: [PATCH 6/7] objtool: Refactor switch-tables code to support other architectures
Date: Mon, 8 Jun 2020 16:27:53 +0100 [thread overview]
Message-ID: <20200608152754.2483-7-jthierry@redhat.com> (raw)
In-Reply-To: <20200608152754.2483-1-jthierry@redhat.com>
From: Raphael Gault <raphael.gault@arm.com>
The way to identify switch-tables and retrieves all the data necessary
to handle the different execution branches is not the same on all
architecture. In order to be able to add other architecture support,
define an arch-dependent function to process jump-tables.
Signed-off-by: Raphael Gault <raphael.gault@arm.com>
[J.T.: Move arm64 bits out of this patch,
Have only one function to find the start of the jump table,
for now assume that the jump table format will be the same as
x86]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
tools/objtool/arch/x86/arch_special.c | 95 +++++++++++++++++++++++++++
tools/objtool/check.c | 88 +------------------------
tools/objtool/check.h | 1 -
tools/objtool/special.h | 4 ++
4 files changed, 102 insertions(+), 86 deletions(-)
diff --git a/tools/objtool/arch/x86/arch_special.c b/tools/objtool/arch/x86/arch_special.c
index 4931ad1a0ab5..fa4571c8ae5d 100644
--- a/tools/objtool/arch/x86/arch_special.c
+++ b/tools/objtool/arch/x86/arch_special.c
@@ -1,4 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
+
#include "../../special.h"
#include "../../builtin.h"
@@ -48,3 +50,96 @@ bool arch_support_alt_relocation(struct special_alt *special_alt,
return insn->offset == special_alt->new_off &&
(insn->type == INSN_CALL || is_static_jump(insn));
}
+
+/*
+ * There are 3 basic jump table patterns:
+ *
+ * 1. jmpq *[rodata addr](,%reg,8)
+ *
+ * This is the most common case by far. It jumps to an address in a simple
+ * jump table which is stored in .rodata.
+ *
+ * 2. jmpq *[rodata addr](%rip)
+ *
+ * This is caused by a rare GCC quirk, currently only seen in three driver
+ * functions in the kernel, only with certain obscure non-distro configs.
+ *
+ * As part of an optimization, GCC makes a copy of an existing switch jump
+ * table, modifies it, and then hard-codes the jump (albeit with an indirect
+ * jump) to use a single entry in the table. The rest of the jump table and
+ * some of its jump targets remain as dead code.
+ *
+ * In such a case we can just crudely ignore all unreachable instruction
+ * warnings for the entire object file. Ideally we would just ignore them
+ * for the function, but that would require redesigning the code quite a
+ * bit. And honestly that's just not worth doing: unreachable instruction
+ * warnings are of questionable value anyway, and this is such a rare issue.
+ *
+ * 3. mov [rodata addr],%reg1
+ * ... some instructions ...
+ * jmpq *(%reg1,%reg2,8)
+ *
+ * This is a fairly uncommon pattern which is new for GCC 6. As of this
+ * writing, there are 11 occurrences of it in the allmodconfig kernel.
+ *
+ * As of GCC 7 there are quite a few more of these and the 'in between' code
+ * is significant. Esp. with KASAN enabled some of the code between the mov
+ * and jmpq uses .rodata itself, which can confuse things.
+ *
+ * TODO: Once we have DWARF CFI and smarter instruction decoding logic,
+ * ensure the same register is used in the mov and jump instructions.
+ *
+ * NOTE: RETPOLINE made it harder still to decode dynamic jumps.
+ */
+struct rela *arch_find_switch_table(struct objtool_file *file,
+ struct instruction *insn)
+{
+ struct rela *text_rela, *rodata_rela;
+ struct section *table_sec;
+ unsigned long table_offset;
+
+ /* look for a relocation which references .rodata */
+ text_rela = find_rela_by_dest_range(file->elf, insn->sec,
+ insn->offset, insn->len);
+ if (!text_rela || text_rela->sym->type != STT_SECTION ||
+ !text_rela->sym->sec->rodata)
+ return NULL;
+
+ table_offset = text_rela->addend;
+ table_sec = text_rela->sym->sec;
+
+ if (text_rela->type == R_X86_64_PC32)
+ table_offset += 4;
+
+ /*
+ * Make sure the .rodata address isn't associated with a
+ * symbol. GCC jump tables are anonymous data.
+ *
+ * Also support C jump tables which are in the same format as
+ * switch jump tables. For objtool to recognize them, they
+ * need to be placed in the C_JUMP_TABLE_SECTION section. They
+ * have symbols associated with them.
+ */
+ if (find_symbol_containing(table_sec, table_offset) &&
+ strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
+ return NULL;
+
+ /*
+ * Each table entry has a rela associated with it. The rela
+ * should reference text in the same function as the original
+ * instruction.
+ */
+ rodata_rela = find_rela_by_dest(file->elf, table_sec, table_offset);
+ if (!rodata_rela)
+ return NULL;
+
+ /*
+ * 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;
+}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 738bfd458595..444688264c39 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -18,8 +18,6 @@
#define FAKE_JUMP_OFFSET -1
-#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
-
struct alternative {
struct list_head list;
struct instruction *insn;
@@ -1044,55 +1042,14 @@ static int add_jump_table(struct objtool_file *file, struct instruction *insn,
/*
* find_jump_table() - Given a dynamic jump, find the switch jump table in
- * .rodata associated with it.
- *
- * There are 3 basic patterns:
- *
- * 1. jmpq *[rodata addr](,%reg,8)
- *
- * This is the most common case by far. It jumps to an address in a simple
- * jump table which is stored in .rodata.
- *
- * 2. jmpq *[rodata addr](%rip)
- *
- * This is caused by a rare GCC quirk, currently only seen in three driver
- * functions in the kernel, only with certain obscure non-distro configs.
- *
- * As part of an optimization, GCC makes a copy of an existing switch jump
- * table, modifies it, and then hard-codes the jump (albeit with an indirect
- * jump) to use a single entry in the table. The rest of the jump table and
- * some of its jump targets remain as dead code.
- *
- * In such a case we can just crudely ignore all unreachable instruction
- * warnings for the entire object file. Ideally we would just ignore them
- * for the function, but that would require redesigning the code quite a
- * bit. And honestly that's just not worth doing: unreachable instruction
- * warnings are of questionable value anyway, and this is such a rare issue.
- *
- * 3. mov [rodata addr],%reg1
- * ... some instructions ...
- * jmpq *(%reg1,%reg2,8)
- *
- * This is a fairly uncommon pattern which is new for GCC 6. As of this
- * writing, there are 11 occurrences of it in the allmodconfig kernel.
- *
- * As of GCC 7 there are quite a few more of these and the 'in between' code
- * is significant. Esp. with KASAN enabled some of the code between the mov
- * and jmpq uses .rodata itself, which can confuse things.
- *
- * TODO: Once we have DWARF CFI and smarter instruction decoding logic,
- * ensure the same register is used in the mov and jump instructions.
- *
- * NOTE: RETPOLINE made it harder still to decode dynamic jumps.
+ * associated with it.
*/
static struct rela *find_jump_table(struct objtool_file *file,
struct symbol *func,
struct instruction *insn)
{
- struct rela *text_rela, *table_rela;
+ struct rela *table_rela;
struct instruction *dest_insn, *orig_insn = insn;
- struct section *table_sec;
- unsigned long table_offset;
/*
* Backward search using the @first_jump_src links, these help avoid
@@ -1113,52 +1070,13 @@ static struct rela *find_jump_table(struct objtool_file *file,
insn->jump_dest->offset > orig_insn->offset))
break;
- /* look for a relocation which references .rodata */
- text_rela = find_rela_by_dest_range(file->elf, insn->sec,
- insn->offset, insn->len);
- if (!text_rela || text_rela->sym->type != STT_SECTION ||
- !text_rela->sym->sec->rodata)
- continue;
-
- table_offset = text_rela->addend;
- table_sec = text_rela->sym->sec;
-
- if (text_rela->type == R_X86_64_PC32)
- table_offset += 4;
-
- /*
- * Make sure the .rodata address isn't associated with a
- * symbol. GCC jump tables are anonymous data.
- *
- * Also support C jump tables which are in the same format as
- * switch jump tables. For objtool to recognize them, they
- * need to be placed in the C_JUMP_TABLE_SECTION section. They
- * have symbols associated with them.
- */
- if (find_symbol_containing(table_sec, table_offset) &&
- strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
- continue;
-
- /*
- * Each table entry has a rela associated with it. The rela
- * should reference text in the same function as the original
- * instruction.
- */
- table_rela = find_rela_by_dest(file->elf, table_sec, table_offset);
+ table_rela = arch_find_switch_table(file, insn);
if (!table_rela)
continue;
dest_insn = find_insn(file, table_rela->sym->sec, table_rela->addend);
if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc != func)
continue;
- /*
- * 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 table_rela;
}
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index 785388cf3872..1ecf8f9125a6 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -62,5 +62,4 @@ struct instruction *find_insn(struct objtool_file *file,
insn->sec == sec; \
insn = list_next_entry(insn, list))
-
#endif /* _CHECK_H */
diff --git a/tools/objtool/special.h b/tools/objtool/special.h
index e15d52d3595d..0f35a67c93b8 100644
--- a/tools/objtool/special.h
+++ b/tools/objtool/special.h
@@ -10,6 +10,8 @@
#include "check.h"
#include "elf.h"
+#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
+
struct special_alt {
struct list_head list;
@@ -34,4 +36,6 @@ void arch_handle_alternative(unsigned short feature, struct special_alt *alt);
bool arch_support_alt_relocation(struct special_alt *special_alt,
struct instruction *insn,
struct rela *rela);
+struct rela *arch_find_switch_table(struct objtool_file *file,
+ struct instruction *insn);
#endif /* _SPECIAL_H */
--
2.21.1
next prev parent reply other threads:[~2020-06-08 15:28 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-08 15:27 [PATCH 0/7] Make check implementation arch agnostic Julien Thierry
2020-06-08 15:27 ` [PATCH 1/7] objtool: Group headers to check in a single list Julien Thierry
2020-06-08 15:27 ` [PATCH 2/7] objtool: Make sync-check consider the target architecture Julien Thierry
2020-06-08 15:27 ` [PATCH 3/7] objtool: Move macros describing structures to arch-dependent code Julien Thierry
2020-06-08 15:27 ` [PATCH 4/7] objtool: Abstract alternative special case handling Julien Thierry
2020-06-08 15:27 ` [PATCH 5/7] objtool: Make relocation in alternative handling arch dependent Julien Thierry
2020-06-08 15:27 ` Julien Thierry [this message]
2020-06-08 15:27 ` [RFC PATCH 7/7] objtool: Make unwind_hints available for all architectures Julien Thierry
2020-06-10 13:20 ` Miroslav Benes
2020-06-11 7:20 ` Julien Thierry
2020-06-10 13:20 ` [PATCH 0/7] Make check implementation arch agnostic Miroslav Benes
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=20200608152754.2483-7-jthierry@redhat.com \
--to=jthierry@redhat.com \
--cc=jpoimboe@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mbenes@suse.cz \
--cc=peterz@infradead.org \
--cc=raphael.gault@arm.com \
/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
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®