[PATCH 14/18] objtool: Add toolchain hacks cmdline option

From: Josh Poimboeuf
Date: Wed Apr 13 2022 - 19:21:16 EST


Objtool secretly does a few awful hacks to overcome toolchain
limitations. Make those hacks explicit (and optional for other arches)
by associating them with a new '--hacks' cmdline option and
corresponding CONFIG_HAVE_TOOLCHAIN_HACKS.

Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
arch/Kconfig | 4 ++++
arch/x86/Kconfig | 1 +
arch/x86/include/asm/jump_label.h | 6 +++---
lib/Kconfig.debug | 4 ++--
lib/Kconfig.kcsan | 4 ++--
scripts/Makefile.build | 1 +
scripts/link-vmlinux.sh | 4 ++++
tools/objtool/builtin-check.c | 4 +++-
tools/objtool/check.c | 4 ++--
tools/objtool/include/objtool/builtin.h | 1 +
10 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index 04cdef16db24..cb5fc88cb996 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -1031,6 +1031,10 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
config HAVE_OBJTOOL
bool

+config HAVE_TOOLCHAIN_HACKS
+ bool
+ select OBJTOOL
+
config HAVE_STACK_VALIDATION
bool
help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bce0c23f3550..410c4e2c7390 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -232,6 +232,7 @@ config X86
select HAVE_MOVE_PUD
select HAVE_NMI
select HAVE_OBJTOOL if X86_64
+ select HAVE_TOOLCHAIN_HACKS if HAVE_OBJTOOL
select HAVE_OPTPROBES
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index 3ce0e67c579c..032434791bf1 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -20,7 +20,7 @@
_ASM_PTR "%c0 + %c1 - .\n\t" \
".popsection \n\t"

-#ifdef CONFIG_OBJTOOL
+#ifdef CONFIG_HAVE_TOOLCHAIN_HACKS

static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
@@ -34,7 +34,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran
return true;
}

-#else /* !CONFIG_OBJTOOL */
+#else /* !CONFIG_HAVE_TOOLCHAIN_HACKS */

static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
{
@@ -48,7 +48,7 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co
return true;
}

-#endif /* CONFIG_OBJTOOL */
+#endif /* CONFIG_HAVE_TOOLCHAIN_HACKS */

static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
{
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index c0e4e47f3ce3..616b93d5db6d 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2036,11 +2036,11 @@ config KCOV
bool "Code coverage for fuzzing"
depends on ARCH_HAS_KCOV
depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS
- depends on !ARCH_WANTS_NO_INSTR || HAVE_OBJTOOL || \
+ depends on !ARCH_WANTS_NO_INSTR || HAVE_TOOLCHAIN_HACKS || \
GCC_VERSION >= 120000 || CLANG_VERSION >= 130000
select DEBUG_FS
select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC
- select OBJTOOL if HAVE_OBJTOOL
+ select OBJTOOL if HAVE_TOOLCHAIN_HACKS
help
KCOV exposes kernel code coverage information in a form suitable
for coverage-guided fuzzing (randomized testing).
diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan
index 901c3b509aca..2bdb46354d6a 100644
--- a/lib/Kconfig.kcsan
+++ b/lib/Kconfig.kcsan
@@ -187,8 +187,8 @@ config KCSAN_WEAK_MEMORY
# We can either let objtool nop __tsan_func_{entry,exit}() and builtin
# atomics instrumentation in .noinstr.text, or use a compiler that can
# implement __no_kcsan to really remove all instrumentation.
- depends on HAVE_OBJTOOL || CC_IS_GCC || CLANG_VERSION >= 140000
- select OBJTOOL if HAVE_OBJTOOL
+ depends on HAVE_TOOLCHAIN_HACKS || CC_IS_GCC || CLANG_VERSION >= 140000
+ select OBJTOOL if HAVE_TOOLCHAIN_HACKS
help
Enable support for modeling a subset of weak memory, which allows
detecting a subset of data races due to missing memory barriers.
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 3f20d565733c..3b53de3dec67 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -227,6 +227,7 @@ ifdef CONFIG_OBJTOOL
objtool := $(objtree)/tools/objtool/objtool

objtool_args = \
+ $(if $(CONFIG_HAVE_TOOLCHAIN_HACKS), --hacks) \
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
$(if $(CONFIG_UNWINDER_ORC), --orc) \
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 33f14fe1ddde..480a49e47fbc 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -117,6 +117,10 @@ objtool_link()
# Don't perform vmlinux validation unless explicitly requested,
# but run objtool on vmlinux.o now that we have an object file.

+ if is_enabled CONFIG_HAVE_TOOLCHAIN_HACKS; then
+ objtoolopt="${objtoolopt} --hacks"
+ fi
+
if is_enabled CONFIG_X86_KERNEL_IBT; then
objtoolopt="${objtoolopt} --ibt"
fi
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index c663828834e1..13e1c46f155a 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -38,6 +38,7 @@ static int parse_dumpstr(const struct option *opt, const char *str, int unset)

const struct option check_options[] = {
OPT_GROUP("Actions:"),
+ OPT_BOOLEAN('h', "hacks", &opts.hacks, "patch some toolchain bugs/limitations"),
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
@@ -91,7 +92,8 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])

static bool opts_valid(void)
{
- if (opts.ibt ||
+ if (opts.hacks ||
+ opts.ibt ||
opts.mcount ||
opts.noinstr ||
opts.orc ||
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 511b76aaa6de..273ba6840ed2 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1145,7 +1145,7 @@ static void annotate_call_site(struct objtool_file *file,
* attribute so they need a little help, NOP out any such calls from
* noinstr text.
*/
- if (insn->sec->noinstr && sym->profiling_func) {
+ if (opts.hacks && insn->sec->noinstr && sym->profiling_func) {
if (reloc) {
reloc->type = R_NONE;
elf_write_reloc(file->elf, reloc);
@@ -1593,7 +1593,7 @@ static int handle_jump_alt(struct objtool_file *file,
return -1;
}

- if (special_alt->key_addend & 2) {
+ if (opts.hacks && special_alt->key_addend & 2) {
struct reloc *reloc = insn_reloc(file, orig_insn);

if (reloc) {
diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h
index 6ffa6b5dc276..7bc76edb0a85 100644
--- a/tools/objtool/include/objtool/builtin.h
+++ b/tools/objtool/include/objtool/builtin.h
@@ -17,6 +17,7 @@ enum dump {
struct opts {
/* actions: */
enum dump dump;
+ bool hacks;
bool ibt;
bool mcount;
bool noinstr;
--
2.34.1