aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-07-11 21:41:15 +0200
committerMichael Matz <matz@suse.de>2016-12-15 17:47:08 +0100
commit5692716770e9e2e733d0e7ab6ce0bd70cb830aba (patch)
tree7b3b856046c5052a9e416389758f5ada4a6ba52f
parente3f2a683113bb28bc1e9820dfe18d3bd8e0156d2 (diff)
downloadtinycc-5692716770e9e2e733d0e7ab6ce0bd70cb830aba.tar.gz
tinycc-5692716770e9e2e733d0e7ab6ce0bd70cb830aba.tar.bz2
x86-asm: Fix lar opcode operands
lar can accept multiple sizes as well (wlx), like lsl. When using autosize it's important to look at the destination operand first; when it's a register that one determines the size, not the input operand.
-rw-r--r--i386-asm.c6
-rw-r--r--i386-asm.h2
-rw-r--r--i386-tok.h1
-rw-r--r--tests/asmtest.S7
-rw-r--r--x86_64-asm.h2
5 files changed, 15 insertions, 3 deletions
diff --git a/i386-asm.c b/i386-asm.c
index 136fe60..71c451a 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -733,7 +733,11 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
autosize = NBWLX-2;
#endif
if (s == autosize) {
- for(i = 0; s == autosize && i < nb_ops; i++) {
+ /* Check for register operands providing hints about the size.
+ Start from the end, i.e. destination operands. This matters
+ only for opcodes accepting different sized registers, lar and lsl
+ are such opcodes. */
+ for(i = nb_ops - 1; s == autosize && i >= 0; i--) {
if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX)))
s = reg_to_size[ops[i].type & OP_REG];
}
diff --git a/i386-asm.h b/i386-asm.h
index 7a8fb0d..65d5179 100644
--- a/i386-asm.h
+++ b/i386-asm.h
@@ -341,7 +341,7 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
/* segments */
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
- DEF_ASM_OP2(lar, 0x0f02, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG32)
+ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG)
diff --git a/i386-tok.h b/i386-tok.h
index c54e0e7..cf65897 100644
--- a/i386-tok.h
+++ b/i386-tok.h
@@ -185,6 +185,7 @@
DEF_WLX(btr)
DEF_WLX(btc)
+ DEF_WLX(lar)
DEF_WLX(lsl)
/* generic FP ops */
diff --git a/tests/asmtest.S b/tests/asmtest.S
index ebc17fc..0bbd764 100644
--- a/tests/asmtest.S
+++ b/tests/asmtest.S
@@ -625,8 +625,15 @@ int $0x10
clflush 0x1000(%rax,%rcx)
fxsaveq (%rdx)
fxrstorq (%rcx)
+
#endif
+ lar %ax,%dx
+ lar %eax,%dx
+ lar %ax,%edx
+ lar %eax,%edx
+ lar %ax,%rdx
+ lar %eax,%rdx
emms
movd %edx, %mm3
movd 0x1000, %mm2
diff --git a/x86_64-asm.h b/x86_64-asm.h
index 73a9f57..5855d2a 100644
--- a/x86_64-asm.h
+++ b/x86_64-asm.h
@@ -359,7 +359,7 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
/* segments */
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
- DEF_ASM_OP2(lar, 0x0f02, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG32)
+ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lgdtq, 0x0f01, 2, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)