objtool: Make noinstr hacks optional

Objtool has some hacks in place to workaround toolchain limitations
which otherwise would break no-instrumentation rules.  Make the hacks
explicit (and optional for other arches) by turning it into a cmdline
option and kernel config option.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Link: https://lkml.kernel.org/r/b326eeb9c33231b9dfbb925f194ed7ee40edcd7c.1650300597.git.jpoimboe@redhat.com
This commit is contained in:
Josh Poimboeuf 2022-04-18 09:50:40 -07:00 committed by Peter Zijlstra
parent 4ab7674f59
commit 22102f4559
9 changed files with 23 additions and 6 deletions

View File

@ -1035,6 +1035,9 @@ config HAVE_OBJTOOL
config HAVE_JUMP_LABEL_HACK config HAVE_JUMP_LABEL_HACK
bool bool
config HAVE_NOINSTR_HACK
bool
config HAVE_STACK_VALIDATION config HAVE_STACK_VALIDATION
bool bool
help help

View File

@ -231,6 +231,7 @@ config X86
select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOD_ARCH_SPECIFIC
select HAVE_MOVE_PMD select HAVE_MOVE_PMD
select HAVE_MOVE_PUD select HAVE_MOVE_PUD
select HAVE_NOINSTR_HACK if HAVE_OBJTOOL
select HAVE_NMI select HAVE_NMI
select HAVE_OBJTOOL if X86_64 select HAVE_OBJTOOL if X86_64
select HAVE_OPTPROBES select HAVE_OPTPROBES

View File

@ -2036,11 +2036,11 @@ config KCOV
bool "Code coverage for fuzzing" bool "Code coverage for fuzzing"
depends on ARCH_HAS_KCOV depends on ARCH_HAS_KCOV
depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS
depends on !ARCH_WANTS_NO_INSTR || HAVE_OBJTOOL || \ depends on !ARCH_WANTS_NO_INSTR || HAVE_NOINSTR_HACK || \
GCC_VERSION >= 120000 || CLANG_VERSION >= 130000 GCC_VERSION >= 120000 || CLANG_VERSION >= 130000
select DEBUG_FS select DEBUG_FS
select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC
select OBJTOOL if HAVE_OBJTOOL select OBJTOOL if HAVE_NOINSTR_HACK
help help
KCOV exposes kernel code coverage information in a form suitable KCOV exposes kernel code coverage information in a form suitable
for coverage-guided fuzzing (randomized testing). for coverage-guided fuzzing (randomized testing).

View File

@ -187,8 +187,9 @@ config KCSAN_WEAK_MEMORY
# We can either let objtool nop __tsan_func_{entry,exit}() and builtin # We can either let objtool nop __tsan_func_{entry,exit}() and builtin
# atomics instrumentation in .noinstr.text, or use a compiler that can # atomics instrumentation in .noinstr.text, or use a compiler that can
# implement __no_kcsan to really remove all instrumentation. # implement __no_kcsan to really remove all instrumentation.
depends on HAVE_OBJTOOL || CC_IS_GCC || CLANG_VERSION >= 140000 depends on !ARCH_WANTS_NO_INSTR || HAVE_NOINSTR_HACK || \
select OBJTOOL if HAVE_OBJTOOL CC_IS_GCC || CLANG_VERSION >= 140000
select OBJTOOL if HAVE_NOINSTR_HACK
help help
Enable support for modeling a subset of weak memory, which allows Enable support for modeling a subset of weak memory, which allows
detecting a subset of data races due to missing memory barriers. detecting a subset of data races due to missing memory barriers.

View File

@ -228,6 +228,7 @@ objtool := $(objtree)/tools/objtool/objtool
objtool_args = \ objtool_args = \
$(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \ $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label) \
$(if $(CONFIG_HAVE_NOINSTR_HACK), --hacks=noinstr) \
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \ $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \ $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
$(if $(CONFIG_UNWINDER_ORC), --orc) \ $(if $(CONFIG_UNWINDER_ORC), --orc) \

View File

@ -121,6 +121,10 @@ objtool_link()
objtoolopt="${objtoolopt} --hacks=jump_label" objtoolopt="${objtoolopt} --hacks=jump_label"
fi fi
if is_enabled CONFIG_HAVE_NOINSTR_HACK; then
objtoolopt="${objtoolopt} --hacks=noinstr"
fi
if is_enabled CONFIG_X86_KERNEL_IBT; then if is_enabled CONFIG_X86_KERNEL_IBT; then
objtoolopt="${objtoolopt} --ibt" objtoolopt="${objtoolopt} --ibt"
fi fi

View File

@ -47,12 +47,17 @@ static int parse_hacks(const struct option *opt, const char *str, int unset)
found = true; found = true;
} }
if (!str || strstr(str, "noinstr")) {
opts.hack_noinstr = true;
found = true;
}
return found ? 0 : -1; return found ? 0 : -1;
} }
const struct option check_options[] = { const struct option check_options[] = {
OPT_GROUP("Actions:"), OPT_GROUP("Actions:"),
OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label", "patch toolchain bugs/limitations", parse_hacks), OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr", "patch toolchain bugs/limitations", parse_hacks),
OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"),
OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"), OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"),
OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"), OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
@ -108,6 +113,7 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
static bool opts_valid(void) static bool opts_valid(void)
{ {
if (opts.hack_jump_label || if (opts.hack_jump_label ||
opts.hack_noinstr ||
opts.ibt || opts.ibt ||
opts.mcount || opts.mcount ||
opts.noinstr || opts.noinstr ||

View File

@ -1144,7 +1144,7 @@ static void annotate_call_site(struct objtool_file *file,
* attribute so they need a little help, NOP out any such calls from * attribute so they need a little help, NOP out any such calls from
* noinstr text. * noinstr text.
*/ */
if (insn->sec->noinstr && sym->profiling_func) { if (opts.hack_noinstr && insn->sec->noinstr && sym->profiling_func) {
if (reloc) { if (reloc) {
reloc->type = R_NONE; reloc->type = R_NONE;
elf_write_reloc(file->elf, reloc); elf_write_reloc(file->elf, reloc);

View File

@ -13,6 +13,7 @@ struct opts {
/* actions: */ /* actions: */
bool dump_orc; bool dump_orc;
bool hack_jump_label; bool hack_jump_label;
bool hack_noinstr;
bool ibt; bool ibt;
bool mcount; bool mcount;
bool noinstr; bool noinstr;