Browse Source

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.
Michael Matz 3 years ago
parent
commit
5692716770
5 changed files with 15 additions and 3 deletions
  1. 5 1
      i386-asm.c
  2. 1 1
      i386-asm.h
  3. 1 0
      i386-tok.h
  4. 7 0
      tests/asmtest.S
  5. 1 1
      x86_64-asm.h

+ 5 - 1
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];
         }

+ 1 - 1
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)

+ 1 - 0
i386-tok.h

@@ -185,6 +185,7 @@
  DEF_WLX(btr)
  DEF_WLX(btc)
 
+ DEF_WLX(lar)
  DEF_WLX(lsl)
 
  /* generic FP ops */

+ 7 - 0
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

+ 1 - 1
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)