Skip to content

Commit 5ed934e

Browse files
Vasily Gorbikjpoimboe
authored andcommitted
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 <gor@linux.ibm.com> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
1 parent 7786032 commit 5ed934e

File tree

4 files changed

+42
-18
lines changed

4 files changed

+42
-18
lines changed

arch/x86/include/asm/insn.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
3030
p->nbytes = n;
3131
}
3232

33+
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
34+
insn_byte_t v)
35+
{
36+
p->bytes[n] = v;
37+
}
38+
3339
#else
3440

3541
struct insn_field {
@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
5157
p->nbytes = n;
5258
}
5359

60+
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
61+
insn_byte_t v)
62+
{
63+
p->bytes[n] = v;
64+
p->value = __le32_to_cpu(p->little);
65+
}
5466
#endif
5567

5668
struct insn {

arch/x86/lib/insn.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ void insn_get_prefixes(struct insn *insn)
161161
b = insn->prefixes.bytes[3];
162162
for (i = 0; i < nb; i++)
163163
if (prefixes->bytes[i] == lb)
164-
prefixes->bytes[i] = b;
164+
insn_set_byte(prefixes, i, b);
165165
}
166-
insn->prefixes.bytes[3] = lb;
166+
insn_set_byte(&insn->prefixes, 3, lb);
167167
}
168168

169169
/* Decode REX prefix */
@@ -194,21 +194,21 @@ void insn_get_prefixes(struct insn *insn)
194194
if (X86_MODRM_MOD(b2) != 3)
195195
goto vex_end;
196196
}
197-
insn->vex_prefix.bytes[0] = b;
198-
insn->vex_prefix.bytes[1] = b2;
197+
insn_set_byte(&insn->vex_prefix, 0, b);
198+
insn_set_byte(&insn->vex_prefix, 1, b2);
199199
if (inat_is_evex_prefix(attr)) {
200200
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
201-
insn->vex_prefix.bytes[2] = b2;
201+
insn_set_byte(&insn->vex_prefix, 2, b2);
202202
b2 = peek_nbyte_next(insn_byte_t, insn, 3);
203-
insn->vex_prefix.bytes[3] = b2;
203+
insn_set_byte(&insn->vex_prefix, 3, b2);
204204
insn->vex_prefix.nbytes = 4;
205205
insn->next_byte += 4;
206206
if (insn->x86_64 && X86_VEX_W(b2))
207207
/* VEX.W overrides opnd_size */
208208
insn->opnd_bytes = 8;
209209
} else if (inat_is_vex3_prefix(attr)) {
210210
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
211-
insn->vex_prefix.bytes[2] = b2;
211+
insn_set_byte(&insn->vex_prefix, 2, b2);
212212
insn->vex_prefix.nbytes = 3;
213213
insn->next_byte += 3;
214214
if (insn->x86_64 && X86_VEX_W(b2))
@@ -220,7 +220,7 @@ void insn_get_prefixes(struct insn *insn)
220220
* Makes it easier to decode vex.W, vex.vvvv,
221221
* vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
222222
*/
223-
insn->vex_prefix.bytes[2] = b2 & 0x7f;
223+
insn_set_byte(&insn->vex_prefix, 2, b2 & 0x7f);
224224
insn->vex_prefix.nbytes = 2;
225225
insn->next_byte += 2;
226226
}
@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn)
256256

257257
/* Get first opcode */
258258
op = get_next(insn_byte_t, insn);
259-
opcode->bytes[0] = op;
259+
insn_set_byte(opcode, 0, op);
260260
opcode->nbytes = 1;
261261

262262
/* Check if there is VEX prefix or not */

tools/arch/x86/include/asm/insn.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
3030
p->nbytes = n;
3131
}
3232

33+
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
34+
insn_byte_t v)
35+
{
36+
p->bytes[n] = v;
37+
}
38+
3339
#else
3440

3541
struct insn_field {
@@ -51,6 +57,12 @@ static inline void insn_field_set(struct insn_field *p, insn_value_t v,
5157
p->nbytes = n;
5258
}
5359

60+
static inline void insn_set_byte(struct insn_field *p, unsigned char n,
61+
insn_byte_t v)
62+
{
63+
p->bytes[n] = v;
64+
p->value = __le32_to_cpu(p->little);
65+
}
5466
#endif
5567

5668
struct insn {

tools/arch/x86/lib/insn.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ void insn_get_prefixes(struct insn *insn)
161161
b = insn->prefixes.bytes[3];
162162
for (i = 0; i < nb; i++)
163163
if (prefixes->bytes[i] == lb)
164-
prefixes->bytes[i] = b;
164+
insn_set_byte(prefixes, i, b);
165165
}
166-
insn->prefixes.bytes[3] = lb;
166+
insn_set_byte(&insn->prefixes, 3, lb);
167167
}
168168

169169
/* Decode REX prefix */
@@ -194,21 +194,21 @@ void insn_get_prefixes(struct insn *insn)
194194
if (X86_MODRM_MOD(b2) != 3)
195195
goto vex_end;
196196
}
197-
insn->vex_prefix.bytes[0] = b;
198-
insn->vex_prefix.bytes[1] = b2;
197+
insn_set_byte(&insn->vex_prefix, 0, b);
198+
insn_set_byte(&insn->vex_prefix, 1, b2);
199199
if (inat_is_evex_prefix(attr)) {
200200
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
201-
insn->vex_prefix.bytes[2] = b2;
201+
insn_set_byte(&insn->vex_prefix, 2, b2);
202202
b2 = peek_nbyte_next(insn_byte_t, insn, 3);
203-
insn->vex_prefix.bytes[3] = b2;
203+
insn_set_byte(&insn->vex_prefix, 3, b2);
204204
insn->vex_prefix.nbytes = 4;
205205
insn->next_byte += 4;
206206
if (insn->x86_64 && X86_VEX_W(b2))
207207
/* VEX.W overrides opnd_size */
208208
insn->opnd_bytes = 8;
209209
} else if (inat_is_vex3_prefix(attr)) {
210210
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
211-
insn->vex_prefix.bytes[2] = b2;
211+
insn_set_byte(&insn->vex_prefix, 2, b2);
212212
insn->vex_prefix.nbytes = 3;
213213
insn->next_byte += 3;
214214
if (insn->x86_64 && X86_VEX_W(b2))
@@ -220,7 +220,7 @@ void insn_get_prefixes(struct insn *insn)
220220
* Makes it easier to decode vex.W, vex.vvvv,
221221
* vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
222222
*/
223-
insn->vex_prefix.bytes[2] = b2 & 0x7f;
223+
insn_set_byte(&insn->vex_prefix, 2, b2 & 0x7f);
224224
insn->vex_prefix.nbytes = 2;
225225
insn->next_byte += 2;
226226
}
@@ -256,7 +256,7 @@ void insn_get_opcode(struct insn *insn)
256256

257257
/* Get first opcode */
258258
op = get_next(insn_byte_t, insn);
259-
opcode->bytes[0] = op;
259+
insn_set_byte(opcode, 0, op);
260260
opcode->nbytes = 1;
261261

262262
/* Check if there is VEX prefix or not */

0 commit comments

Comments
 (0)