Unlike the jump_label bits, static_cpu_has is implemented with
alternatives. We use the new type field to distinguish them from any
other alternatives

Like jump_labels, make static_cpu_has set static_jump_dest on the
instructions after the static branch such that we can assert on it.

Cc: Thomas Gleixner <t...@linutronix.de>
Cc: Borislav Petkov <b...@alien8.de>
Cc: Josh Poimboeuf <jpoim...@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org>
---
 tools/objtool/check.c   |   21 +++++++++++++++++++++
 tools/objtool/special.c |   26 +++++++++++++++-----------
 tools/objtool/special.h |    1 +
 3 files changed, 37 insertions(+), 11 deletions(-)

--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -636,6 +636,12 @@ static int handle_group_alt(struct objto
        fake_jump->ignore = true;
 
        if (!special_alt->new_len) {
+               /*
+                * The NOP case for _static_cpu_has()
+                */
+               if (special_alt->static_cpu_has)
+                       fake_jump->jump_dest->static_jump_dest = true;
+
                *new_insn = fake_jump;
                return 0;
        }
@@ -664,6 +670,21 @@ static int handle_group_alt(struct objto
                                  insn->sec, insn->offset);
                        return -1;
                }
+
+               if (special_alt->static_cpu_has) {
+                       if (insn->type != INSN_JUMP_UNCONDITIONAL) {
+                               WARN_FUNC("not an unconditional jump in 
_static_cpu_has()",
+                                         insn->sec, insn->offset);
+                       }
+                       if (insn->jump_dest == fake_jump) {
+                               WARN_FUNC("jump inside alternative for 
_static_cpu_has()",
+                                         insn->sec, insn->offset);
+                       }
+                       /*
+                        * The JMP+disp case for _static_cpu_has()
+                        */
+                       insn->jump_dest->static_jump_dest = true;
+               }
        }
 
        if (!last_new_insn) {
--- a/tools/objtool/special.c
+++ b/tools/objtool/special.c
@@ -40,6 +40,10 @@
 #define ALT_FEATURE_OFFSET     8
 #define ALT_ORIG_LEN_OFFSET    10
 #define ALT_NEW_LEN_OFFSET     11
+#define ALT_TYPE_OFFSET                13
+
+#define ALT_TYPE_DEFAULT       0
+#define ALT_TYPE_STATIC_CPU_HAS        1
 
 #define X86_FEATURE_POPCNT (4*32+23)
 
@@ -48,7 +52,6 @@ struct special_entry {
        bool group, jump_or_nop;
        unsigned char size, orig, new;
        unsigned char orig_len, new_len; /* group only */
-       unsigned char feature; /* ALTERNATIVE macro CPU feature */
 };
 
 struct special_entry entries[] = {
@@ -60,7 +63,6 @@ struct special_entry entries[] = {
                .orig_len = ALT_ORIG_LEN_OFFSET,
                .new = ALT_NEW_OFFSET,
                .new_len = ALT_NEW_LEN_OFFSET,
-               .feature = ALT_FEATURE_OFFSET,
        },
        {
                .sec = "__jump_table",
@@ -84,24 +86,23 @@ static int get_alt_entry(struct elf *elf
 {
        struct rela *orig_rela, *new_rela;
        unsigned long offset;
+       void *data;
 
        offset = idx * entry->size;
+       data = sec->data->d_buf + offset;
 
        alt->group = entry->group;
        alt->jump_or_nop = entry->jump_or_nop;
 
        if (alt->group) {
-               alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset +
-                                                  entry->orig_len);
-               alt->new_len = *(unsigned char *)(sec->data->d_buf + offset +
-                                                 entry->new_len);
-       }
-
-       if (entry->feature) {
                unsigned short feature;
+               unsigned char type;
 
-               feature = *(unsigned short *)(sec->data->d_buf + offset +
-                                             entry->feature);
+               alt->orig_len = *(unsigned char *)(data + entry->orig_len);
+               alt->new_len = *(unsigned char *)(data + entry->new_len);
+
+               feature = *(unsigned short *)(data + ALT_FEATURE_OFFSET);
+               type = *(unsigned char *)(data + ALT_TYPE_OFFSET);
 
                /*
                 * It has been requested that we don't validate the !POPCNT
@@ -110,6 +111,9 @@ static int get_alt_entry(struct elf *elf
                 */
                if (feature == X86_FEATURE_POPCNT)
                        alt->skip_orig = true;
+
+               if (type == ALT_TYPE_STATIC_CPU_HAS)
+                       alt->static_cpu_has = true;
        }
 
        orig_rela = find_rela_by_dest(sec, offset + entry->orig);
--- a/tools/objtool/special.h
+++ b/tools/objtool/special.h
@@ -27,6 +27,7 @@ struct special_alt {
        bool group;
        bool skip_orig;
        bool jump_or_nop;
+       bool static_cpu_has;
 
        struct section *orig_sec;
        unsigned long orig_off;


Reply via email to