objtool: Make jump label hack optional
authorJosh Poimboeuf <jpoimboe@redhat.com>
Mon, 18 Apr 2022 16:50:39 +0000 (09:50 -0700)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 22 Apr 2022 10:32:04 +0000 (12:32 +0200)
Objtool secretly does a jump label hack to overcome the limitations of
the toolchain.  Make the hack 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/3bdcbfdd27ecb01ddec13c04bdf756a583b13d24.1650300597.git.jpoimboe@redhat.com
arch/Kconfig
arch/x86/Kconfig
arch/x86/include/asm/jump_label.h
scripts/Makefile.build
scripts/link-vmlinux.sh
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/include/objtool/builtin.h

index 04cdef1..9dce6d6 100644 (file)
@@ -46,6 +46,7 @@ config JUMP_LABEL
        bool "Optimize very unlikely/likely branches"
        depends on HAVE_ARCH_JUMP_LABEL
        depends on CC_HAS_ASM_GOTO
+       select OBJTOOL if HAVE_JUMP_LABEL_HACK
        help
         This option enables a transparent branch optimization that
         makes certain almost-always-true or almost-always-false branch
@@ -1031,6 +1032,9 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
 config HAVE_OBJTOOL
        bool
 
+config HAVE_JUMP_LABEL_HACK
+       bool
+
 config HAVE_STACK_VALIDATION
        bool
        help
index 43e26ee..26d012f 100644 (file)
@@ -212,6 +212,7 @@ config X86
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_EXIT_ON_IRQ_STACK       if X86_64
        select HAVE_IRQ_TIME_ACCOUNTING
+       select HAVE_JUMP_LABEL_HACK             if HAVE_OBJTOOL
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZ4
index 3ce0e67..071572e 100644 (file)
@@ -20,7 +20,7 @@
        _ASM_PTR "%c0 + %c1 - .\n\t"                    \
        ".popsection \n\t"
 
-#ifdef CONFIG_OBJTOOL
+#ifdef CONFIG_HAVE_JUMP_LABEL_HACK
 
 static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
 {
@@ -34,7 +34,7 @@ l_yes:
        return true;
 }
 
-#else /* !CONFIG_OBJTOOL */
+#else /* !CONFIG_HAVE_JUMP_LABEL_HACK */
 
 static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
 {
@@ -48,7 +48,7 @@ l_yes:
        return true;
 }
 
-#endif /* CONFIG_OBJTOOL */
+#endif /* CONFIG_HAVE_JUMP_LABEL_HACK */
 
 static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
 {
index 3f20d56..f1d2c2e 100644 (file)
@@ -227,6 +227,7 @@ ifdef CONFIG_OBJTOOL
 objtool := $(objtree)/tools/objtool/objtool
 
 objtool_args =                                                         \
+       $(if $(CONFIG_HAVE_JUMP_LABEL_HACK), --hacks=jump_label)        \
        $(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt)                     \
        $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount)             \
        $(if $(CONFIG_UNWINDER_ORC), --orc)                             \
index 33f14fe..fa1f168 100755 (executable)
@@ -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_JUMP_LABEL_HACK; then
+                       objtoolopt="${objtoolopt} --hacks=jump_label"
+               fi
+
                if is_enabled CONFIG_X86_KERNEL_IBT; then
                        objtoolopt="${objtoolopt} --ibt"
                fi
index c8c4d2b..b2c626d 100644 (file)
@@ -31,8 +31,28 @@ static int parse_dump(const struct option *opt, const char *str, int unset)
        return -1;
 }
 
+static int parse_hacks(const struct option *opt, const char *str, int unset)
+{
+       bool found = false;
+
+       /*
+        * Use strstr() as a lazy method of checking for comma-separated
+        * options.
+        *
+        * No string provided == enable all options.
+        */
+
+       if (!str || strstr(str, "jump_label")) {
+               opts.hack_jump_label = true;
+               found = true;
+       }
+
+       return found ? 0 : -1;
+}
+
 const struct option check_options[] = {
        OPT_GROUP("Actions:"),
+       OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label", "patch toolchain bugs/limitations", parse_hacks),
        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"),
@@ -87,14 +107,15 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
 
 static bool opts_valid(void)
 {
-       if (opts.ibt            ||
-           opts.mcount         ||
-           opts.noinstr        ||
-           opts.orc            ||
-           opts.retpoline      ||
-           opts.sls            ||
-           opts.stackval       ||
-           opts.static_call    ||
+       if (opts.hack_jump_label        ||
+           opts.ibt                    ||
+           opts.mcount                 ||
+           opts.noinstr                ||
+           opts.orc                    ||
+           opts.retpoline              ||
+           opts.sls                    ||
+           opts.stackval               ||
+           opts.static_call            ||
            opts.uaccess) {
                if (opts.dump_orc) {
                        fprintf(stderr, "--dump can't be combined with other options\n");
index b9ac351..d157978 100644 (file)
@@ -1592,7 +1592,7 @@ static int handle_jump_alt(struct objtool_file *file,
                return -1;
        }
 
-       if (special_alt->key_addend & 2) {
+       if (opts.hack_jump_label && special_alt->key_addend & 2) {
                struct reloc *reloc = insn_reloc(file, orig_insn);
 
                if (reloc) {
index dc47572..c6acf05 100644 (file)
@@ -12,6 +12,7 @@ extern const struct option check_options[];
 struct opts {
        /* actions: */
        bool dump_orc;
+       bool hack_jump_label;
        bool ibt;
        bool mcount;
        bool noinstr;