The following commit has been merged into the objtool/core branch of tip:

Commit-ID:     5ed934e57e712b676ca62e1904ad672a9fa1505a
Gitweb:        
https://git.kernel.org/tip/5ed934e57e712b676ca62e1904ad672a9fa1505a
Author:        Vasily Gorbik <g...@linux.ibm.com>
AuthorDate:    Fri, 13 Nov 2020 17:09:54 +01:00
Committer:     Josh Poimboeuf <jpoim...@redhat.com>
CommitterDate: Wed, 13 Jan 2021 18:13:17 -06:00

x86/insn: Fix vector instruction decoding on big endian cross-compiles

Running instruction decoder posttest on an s390 host with an x86 target
with allyesconfig shows errors. Instructions used in a couple of kernel
objects could not be correctly decoded on big endian system.

  insn_decoder_test: warning: objdump says 6 bytes, but insn_get_length() says 5
  insn_decoder_test: warning: Found an x86 instruction decoder bug, please 
report this.
  insn_decoder_test: warning: ffffffff831eb4e1:    62 d1 fd 48 7f 04 24    
vmovdqa64 %zmm0,(%r12)
  insn_decoder_test: warning: objdump says 7 bytes, but insn_get_length() says 6
  insn_decoder_test: warning: Found an x86 instruction decoder bug, please 
report this.
  insn_decoder_test: warning: ffffffff831eb4e8:    62 51 fd 48 7f 44 24 01      
   vmovdqa64 %zmm8,0x40(%r12)
  insn_decoder_test: warning: objdump says 8 bytes, but insn_get_length() says 6

This is because in a few places instruction field bytes are set directly
with further usage of "value". To address that introduce and use a
insn_set_byte() helper, which correctly updates "value" on big endian
systems.

Signed-off-by: Vasily Gorbik <g...@linux.ibm.com>
Acked-by: Masami Hiramatsu <mhira...@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoim...@redhat.com>
---
 arch/x86/include/asm/insn.h       | 12 ++++++++++++
 arch/x86/lib/insn.c               | 18 +++++++++---------
 tools/arch/x86/include/asm/insn.h | 12 ++++++++++++
 tools/arch/x86/lib/insn.c         | 18 +++++++++---------
 4 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
index 090863c..95a448f 100644
--- a/arch/x86/include/asm/insn.h
+++ b/arch/x86/include/asm/insn.h
@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, 
insn_value_t v,
        p->nbytes = n;
 }
 
+static inline void insn_set_byte(struct insn_field *p, unsigned char n,
+                                insn_byte_t v)
+{
+       p->bytes[n] = v;
+}
+
 #else
 
 struct insn_field {
@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, 
insn_value_t v,
        p->nbytes = n;
 }
 
+static inline void insn_set_byte(struct insn_field *p, unsigned char n,
+                                insn_byte_t v)
+{
+       p->bytes[n] = v;
+       p->value = __le32_to_cpu(p->little);
+}
 #endif
 
 struct insn {
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
index 520b31f..435630a 100644
--- a/arch/x86/lib/insn.c
+++ b/arch/x86/lib/insn.c
@@ -161,9 +161,9 @@ found:
                        b = insn->prefixes.bytes[3];
                        for (i = 0; i < nb; i++)
                                if (prefixes->bytes[i] == lb)
-                                       prefixes->bytes[i] = b;
+                                       insn_set_byte(prefixes, i, b);
                }
-               insn->prefixes.bytes[3] = lb;
+               insn_set_byte(&insn->prefixes, 3, lb);
        }
 
        /* Decode REX prefix */
@@ -194,13 +194,13 @@ found:
                        if (X86_MODRM_MOD(b2) != 3)
                                goto vex_end;
                }
-               insn->vex_prefix.bytes[0] = b;
-               insn->vex_prefix.bytes[1] = b2;
+               insn_set_byte(&insn->vex_prefix, 0, b);
+               insn_set_byte(&insn->vex_prefix, 1, b2);
                if (inat_is_evex_prefix(attr)) {
                        b2 = peek_nbyte_next(insn_byte_t, insn, 2);
-                       insn->vex_prefix.bytes[2] = b2;
+                       insn_set_byte(&insn->vex_prefix, 2, b2);
                        b2 = peek_nbyte_next(insn_byte_t, insn, 3);
-                       insn->vex_prefix.bytes[3] = b2;
+                       insn_set_byte(&insn->vex_prefix, 3, b2);
                        insn->vex_prefix.nbytes = 4;
                        insn->next_byte += 4;
                        if (insn->x86_64 && X86_VEX_W(b2))
@@ -208,7 +208,7 @@ found:
                                insn->opnd_bytes = 8;
                } else if (inat_is_vex3_prefix(attr)) {
                        b2 = peek_nbyte_next(insn_byte_t, insn, 2);
-                       insn->vex_prefix.bytes[2] = b2;
+                       insn_set_byte(&insn->vex_prefix, 2, b2);
                        insn->vex_prefix.nbytes = 3;
                        insn->next_byte += 3;
                        if (insn->x86_64 && X86_VEX_W(b2))
@@ -220,7 +220,7 @@ found:
                         * Makes it easier to decode vex.W, vex.vvvv,
                         * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
                         */
-                       insn->vex_prefix.bytes[2] = b2 & 0x7f;
+                       insn_set_byte(&insn->vex_prefix, 2, b2 & 0x7f);
                        insn->vex_prefix.nbytes = 2;
                        insn->next_byte += 2;
                }
@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn)
 
        /* Get first opcode */
        op = get_next(insn_byte_t, insn);
-       opcode->bytes[0] = op;
+       insn_set_byte(opcode, 0, op);
        opcode->nbytes = 1;
 
        /* Check if there is VEX prefix or not */
diff --git a/tools/arch/x86/include/asm/insn.h 
b/tools/arch/x86/include/asm/insn.h
index c1fab7a..cc777c1 100644
--- a/tools/arch/x86/include/asm/insn.h
+++ b/tools/arch/x86/include/asm/insn.h
@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, 
insn_value_t v,
        p->nbytes = n;
 }
 
+static inline void insn_set_byte(struct insn_field *p, unsigned char n,
+                                insn_byte_t v)
+{
+       p->bytes[n] = v;
+}
+
 #else
 
 struct insn_field {
@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, 
insn_value_t v,
        p->nbytes = n;
 }
 
+static inline void insn_set_byte(struct insn_field *p, unsigned char n,
+                                insn_byte_t v)
+{
+       p->bytes[n] = v;
+       p->value = __le32_to_cpu(p->little);
+}
 #endif
 
 struct insn {
diff --git a/tools/arch/x86/lib/insn.c b/tools/arch/x86/lib/insn.c
index 77e92aa..3d9355e 100644
--- a/tools/arch/x86/lib/insn.c
+++ b/tools/arch/x86/lib/insn.c
@@ -161,9 +161,9 @@ found:
                        b = insn->prefixes.bytes[3];
                        for (i = 0; i < nb; i++)
                                if (prefixes->bytes[i] == lb)
-                                       prefixes->bytes[i] = b;
+                                       insn_set_byte(prefixes, i, b);
                }
-               insn->prefixes.bytes[3] = lb;
+               insn_set_byte(&insn->prefixes, 3, lb);
        }
 
        /* Decode REX prefix */
@@ -194,13 +194,13 @@ found:
                        if (X86_MODRM_MOD(b2) != 3)
                                goto vex_end;
                }
-               insn->vex_prefix.bytes[0] = b;
-               insn->vex_prefix.bytes[1] = b2;
+               insn_set_byte(&insn->vex_prefix, 0, b);
+               insn_set_byte(&insn->vex_prefix, 1, b2);
                if (inat_is_evex_prefix(attr)) {
                        b2 = peek_nbyte_next(insn_byte_t, insn, 2);
-                       insn->vex_prefix.bytes[2] = b2;
+                       insn_set_byte(&insn->vex_prefix, 2, b2);
                        b2 = peek_nbyte_next(insn_byte_t, insn, 3);
-                       insn->vex_prefix.bytes[3] = b2;
+                       insn_set_byte(&insn->vex_prefix, 3, b2);
                        insn->vex_prefix.nbytes = 4;
                        insn->next_byte += 4;
                        if (insn->x86_64 && X86_VEX_W(b2))
@@ -208,7 +208,7 @@ found:
                                insn->opnd_bytes = 8;
                } else if (inat_is_vex3_prefix(attr)) {
                        b2 = peek_nbyte_next(insn_byte_t, insn, 2);
-                       insn->vex_prefix.bytes[2] = b2;
+                       insn_set_byte(&insn->vex_prefix, 2, b2);
                        insn->vex_prefix.nbytes = 3;
                        insn->next_byte += 3;
                        if (insn->x86_64 && X86_VEX_W(b2))
@@ -220,7 +220,7 @@ found:
                         * Makes it easier to decode vex.W, vex.vvvv,
                         * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
                         */
-                       insn->vex_prefix.bytes[2] = b2 & 0x7f;
+                       insn_set_byte(&insn->vex_prefix, 2, b2 & 0x7f);
                        insn->vex_prefix.nbytes = 2;
                        insn->next_byte += 2;
                }
@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn)
 
        /* Get first opcode */
        op = get_next(insn_byte_t, insn);
-       opcode->bytes[0] = op;
+       insn_set_byte(opcode, 0, op);
        opcode->nbytes = 1;
 
        /* Check if there is VEX prefix or not */

Reply via email to