]> granicus.if.org Git - yasm/commitdiff
* x86id.re (yasm_x86__parse_insn): Add checking of effective address size.
authorPeter Johnson <peter@tortall.net>
Fri, 3 Sep 2004 23:01:51 +0000 (23:01 -0000)
committerPeter Johnson <peter@tortall.net>
Fri, 3 Sep 2004 23:01:51 +0000 (23:01 -0000)
* x86arch.h (x86_new_insn_data): Add shortmov_op for shortmov post-action.
* x86bc.c (x86_insn): Likewise.
(yasm_x86__bc_create_insn): Copy shortmov_op to instruction.
(x86_bc_insn_resolve): Handle shortmov_op post-action.
* x86id.re (yasm_x86__parse_insn): Set shortmov_op post-action if desired.

* x86id.re (mov_insn): Through reorder and use of new shortmov_op
post-action, change generated code for mov on AMD64.  On AMD64, the short
mov (opcode A0/A1/A2/A3), generated when moving to AL/AX/EAX/RAX from an
absolute address (no registers) has a 64-bit size in 64-bit mode.  While an
address override can reduce it to 32-bits, automatically generating such an
override does not fit well with the model of not doing anything behind the
programmer's back.  Instead, we now generate the 32-bit address size MOD/RM
form unless the address size is specifically set to 64 bits using [qword 0]
notation (this is the equivalent of the GNU AS movabs pseudo-instruction).
The short mov is still generated in 32-bit mode, whether obtained via BITS
setting or an a32 prefix in BITS 64 mode.  (The a32 prefix handling
necessitated the new shortmov post-action.)  Examples (pulled from new
mem64.asm):

    mov ax, [0]                         ; 66 8B 04 25 00 00 00 00
    mov rax, [dword 0]                  ; 48 8B 04 25 00 00 00 00
    mov al, [qword 0xfedcba9876543210]  ; A0 10 32 54 76 98 BA DC FE
    mov al, [0xfedcba9876543210]        ; 8A 04 25 10 32 54 76 (+ warning)
    a32 mov rax, [0]                    ; 67 48 A1 00 00 00 00

* mem64.asm: Update test to match code changes.
* mem64.hex: Likewise.
* mem64.errwarn: Likewise.

Related to: Bugzilla Bug 33
            Reported by: Jeff Lawson <jlawson-yasm@bovine.net>

svn path=/trunk/yasm/; revision=1134

modules/arch/x86/tests/mem64.asm
modules/arch/x86/tests/mem64.errwarn
modules/arch/x86/tests/mem64.hex
modules/arch/x86/x86arch.h
modules/arch/x86/x86bc.c
modules/arch/x86/x86id.re

index a9e1c35c6ecebacc4c5b16d1348978c13f01a8ad..f88d81d16f138b68b4e65966d4782946f76db0e5 100644 (file)
@@ -1,12 +1,15 @@
 [bits 64]
-mov ax, [0]                    ; 66 A1 00 00 00 00 00 00 00 00
+mov ax, [0]                    ; 66 8B 04 25 00 00 00 00
 mov rax, [qword 0]             ; 48 A1 00 00 00 00 00 00 00 00
-mov rax, [dword 0]             ; 67 48 A1 00 00 00 00
-mov al, [0xfedcba9876543210]   ; 48 A0 10 32 54 76 98 BA DC FE
+mov rax, [0]                   ; 48 8B 04 25 00 00 00 00
+mov rax, [dword 0]             ; 48 8B 04 25 00 00 00 00
+mov al, [qword 0xfedcba9876543210]     ; A0 10 32 54 76 98 BA DC FE
+mov al, [0xfedcba9876543210]   ; 8A 04 25 10 32 54 76 (+ warning)
 a32 mov rax, [0]               ; 67 48 A1 00 00 00 00
 a32 mov eax, [0]               ; 67 A1 00 00 00 00
 mov ecx, [0]                   ; 8B 0C 25 00 00 00 00
 mov edx, [dword 0]             ; 8B 14 25 00 00 00 00
+mov rbx, [0]                   ; 48 8B 1C 25 00 00 00 00
 a32 mov rbx, [0]               ; 67 48 8B 1C 25 00 00 00 00
 mov ebx, [rcx]                 ; 8B 19
 mov r8, [r9]                   ; 4D 8B 01
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0b47ad9b6e9d773616d5a52f7ad112feaf863fe5 100644 (file)
@@ -0,0 +1 @@
+-:7: warning: value does not fit in 32 bit field
index ae433679c818dc864d2edfb52cbc3d4f4bd39516..eeb726b8e0d8925027511d3b61c7d81d0b3e65a9 100644 (file)
@@ -1,26 +1,33 @@
 66 
-a1 
+8b 
+04 
+25 
 00 
 00 
 00 
 00 
+48 
+a1 
 00 
 00 
 00 
 00 
-48 
-a1 
 00 
 00 
 00 
 00 
+48 
+8b 
+04 
+25 
 00 
 00 
 00 
 00 
-67 
 48 
-a1 
+8b 
+04 
+25 
 00 
 00 
 00 
@@ -34,6 +41,13 @@ a0
 ba 
 dc 
 fe 
+8a 
+04 
+25 
+10 
+32 
+54 
+76 
 67 
 48 
 a1 
@@ -61,6 +75,14 @@ a1
 00 
 00 
 00 
+48 
+8b 
+1c 
+25 
+00 
+00 
+00 
+00 
 67 
 48 
 8b 
index 397d7907eca4b2ff8008d2e3e50c0bc23464ed82..6bff6d1f05d5a1838ae5334773e49bf55ea78cb8 100644 (file)
@@ -167,6 +167,7 @@ typedef struct x86_new_insn_data {
     unsigned char im_sign;
     unsigned char shift_op;
     unsigned char signext_imm8_op;
+    unsigned char shortmov_op;
 } x86_new_insn_data;
 
 yasm_bytecode *yasm_x86__bc_create_insn(yasm_arch *arch, x86_new_insn_data *d);
index 4267d6107c676ec8dbb173f320fe7f505ad09ed9..778c04584c4667009655ec1247444e27988e9497 100644 (file)
@@ -29,6 +29,7 @@
 
 #define YASM_LIB_INTERNAL
 #define YASM_BC_INTERNAL
+#define YASM_EXPR_INTERNAL
 #include <libyasm.h>
 
 #include "x86arch.h"
@@ -103,6 +104,13 @@ typedef struct x86_insn {
      */
     unsigned char signext_imm8_op;
 
+    /* HACK, similar to those above, for optimizing long (modrm+sib) mov
+     * instructions in amd64 into short mov instructions if a 32-bit address
+     * override is applied in 64-bit mode to an EA of just an offset (no
+     * registers) and the target register is al/ax/eax/rax.
+     */
+    unsigned char shortmov_op;
+
     unsigned char mode_bits;
 } x86_insn;
 
@@ -238,6 +246,7 @@ yasm_x86__bc_create_insn(yasm_arch *arch, x86_new_insn_data *d)
     insn->rex = d->rex;
     insn->shift_op = d->shift_op;
     insn->signext_imm8_op = d->signext_imm8_op;
+    insn->shortmov_op = d->shortmov_op;
 
     insn->mode_bits = arch_x86->mode_bits;
 
@@ -644,6 +653,18 @@ x86_bc_insn_resolve(yasm_bytecode *bc, int save,
            temp = yasm_expr_copy(ea->disp);
            assert(temp != NULL);
 
+           /* Handle shortmov special-casing */
+           if (insn->shortmov_op && insn->mode_bits == 64 &&
+               insn->addrsize == 32 &&
+               !yasm_expr__contains(temp, YASM_EXPR_REG)) {
+               yasm_x86__ea_set_disponly((yasm_effaddr *)&eat);
+
+               if (save) {
+                   /* Make the short form permanent. */
+                   insn->opcode[0] = insn->opcode[1];
+               }
+           }
+
            /* Check validity of effective address and calc R/M bits of
             * Mod/RM byte and SIB byte.  We won't know the Mod field
             * of the Mod/RM byte until we know more about the
index fdfdb2b8852eba3a1787c04065d444d9a215e49d..9384840bdcf198db66561b645a4685f468ff7eff 100644 (file)
@@ -105,6 +105,9 @@ RCSID("$IdPath$");
  *            2 = SHORT
  *            3 = FAR
  *            4 = TO
+ *  - 1 bit = effective address size
+ *            0 = any address size allowed except for 64-bit
+ *            1 = only 64-bit address size allowed
  *
  * MSBs than the above are actions: what to do with the operand if the
  * instruction matches.  Essentially describes what part of the output bytecode
@@ -128,11 +131,12 @@ RCSID("$IdPath$");
  * additional data (stored in the second byte of the opcode with a one-byte
  * opcode) is passed to later stages of the assembler with flags set to
  * indicate postponed actions.
- *  - 2 bits = postponed action:
+ *  - 3 bits = postponed action:
  *             0 = none
  *             1 = shift operation with a ,1 short form (instead of imm8).
  *             2 = large imm16/32 that can become a sign-extended imm8.
  *             3 = can be far jump
+ *             4 = could become a short opcode mov with bits=64 and a32 prefix
  */
 #define OPT_Imm                0x0
 #define OPT_Reg                0x1
@@ -171,30 +175,35 @@ RCSID("$IdPath$");
 #define OPS_Relaxed    (1UL<<8)
 #define OPS_RMASK      (1UL<<8)
 
-#define OPTM_None      (0UL<<9)
-#define OPTM_Near      (1UL<<9)
-#define OPTM_Short     (2UL<<9)
-#define OPTM_Far       (3UL<<9)
-#define OPTM_To                (4UL<<9)
-#define OPTM_MASK      (7UL<<9)
-
-#define OPA_None       (0UL<<12)
-#define OPA_EA         (1UL<<12)
-#define OPA_Imm                (2UL<<12)
-#define OPA_SImm       (3UL<<12)
-#define OPA_Spare      (4UL<<12)
-#define OPA_Op0Add     (5UL<<12)
-#define OPA_Op1Add     (6UL<<12)
-#define OPA_SpareEA    (7UL<<12)
-#define OPA_JmpRel     (8UL<<12)
-#define OPA_AdSizeR    (9UL<<12)
-#define OPA_MASK       (0xFUL<<12)
-
-#define OPAP_None      (0UL<<16)
-#define OPAP_ShiftOp   (1UL<<16)
-#define OPAP_SImm8Avail        (2UL<<16)
-#define OPAP_JmpFar    (3UL<<16)
-#define OPAP_MASK      (3UL<<16)
+#define OPEAS_Not64    (0UL<<9)
+#define OPEAS_64       (1UL<<9)
+#define OPEAS_MASK     (1UL<<9)
+
+#define OPTM_None      (0UL<<10)
+#define OPTM_Near      (1UL<<10)
+#define OPTM_Short     (2UL<<10)
+#define OPTM_Far       (3UL<<10)
+#define OPTM_To                (4UL<<10)
+#define OPTM_MASK      (7UL<<10)
+
+#define OPA_None       (0UL<<13)
+#define OPA_EA         (1UL<<13)
+#define OPA_Imm                (2UL<<13)
+#define OPA_SImm       (3UL<<13)
+#define OPA_Spare      (4UL<<13)
+#define OPA_Op0Add     (5UL<<13)
+#define OPA_Op1Add     (6UL<<13)
+#define OPA_SpareEA    (7UL<<13)
+#define OPA_JmpRel     (8UL<<13)
+#define OPA_AdSizeR    (9UL<<13)
+#define OPA_MASK       (0xFUL<<13)
+
+#define OPAP_None      (0UL<<17)
+#define OPAP_ShiftOp   (1UL<<17)
+#define OPAP_SImm8Avail        (2UL<<17)
+#define OPAP_JmpFar    (3UL<<17)
+#define OPAP_ShortMov  (4UL<<17)
+#define OPAP_MASK      (7UL<<17)
 
 typedef struct x86_insn_info {
     /* The CPU feature flags needed to execute this instruction.  This is OR'ed
@@ -303,24 +312,63 @@ static const x86_insn_info twobytemem_insn[] = {
 
 /* Move instructions */
 static const x86_insn_info mov_insn[] = {
-    { CPU_Any, 0, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2,
+    /* Absolute forms for non-64-bit mode */
+    { CPU_Not64, 0, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2,
       {OPT_Areg|OPS_8|OPA_None, OPT_MemOffs|OPS_8|OPS_Relaxed|OPA_EA, 0} },
-    { CPU_Any, 0, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
+    { CPU_Not64, 0, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
       {OPT_Areg|OPS_16|OPA_None, OPT_MemOffs|OPS_16|OPS_Relaxed|OPA_EA, 0} },
-    { CPU_386, 0, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
+    { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
       {OPT_Areg|OPS_32|OPA_None, OPT_MemOffs|OPS_32|OPS_Relaxed|OPA_EA, 0} },
-    { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
-      {OPT_Areg|OPS_64|OPA_None, OPT_MemOffs|OPS_64|OPS_Relaxed|OPA_EA, 0} },
 
-    { CPU_Any, 0, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2,
+    { CPU_Not64, 0, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2,
       {OPT_MemOffs|OPS_8|OPS_Relaxed|OPA_EA, OPT_Areg|OPS_8|OPA_None, 0} },
-    { CPU_Any, 0, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2,
+    { CPU_Not64, 0, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2,
       {OPT_MemOffs|OPS_16|OPS_Relaxed|OPA_EA, OPT_Areg|OPS_16|OPA_None, 0} },
-    { CPU_386, 0, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2,
+    { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2,
       {OPT_MemOffs|OPS_32|OPS_Relaxed|OPA_EA, OPT_Areg|OPS_32|OPA_None, 0} },
+
+    /* 64-bit absolute forms for 64-bit mode */
+    { CPU_Hammer|CPU_64, 0, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2,
+      {OPT_Areg|OPS_8|OPA_None,
+       OPT_MemOffs|OPS_8|OPS_Relaxed|OPEAS_64|OPA_EA, 0} },
+    { CPU_Hammer|CPU_64, 0, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
+      {OPT_Areg|OPS_16|OPA_None,
+       OPT_MemOffs|OPS_16|OPS_Relaxed|OPEAS_64|OPA_EA, 0} },
+    { CPU_Hammer|CPU_64, 0, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
+      {OPT_Areg|OPS_32|OPA_None,
+       OPT_MemOffs|OPS_32|OPS_Relaxed|OPEAS_64|OPA_EA, 0} },
+    { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0xA1, 0, 0}, 0, 2,
+      {OPT_Areg|OPS_64|OPA_None,
+       OPT_MemOffs|OPS_64|OPS_Relaxed|OPEAS_64|OPA_EA, 0} },
+
+    { CPU_Hammer|CPU_64, 0, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2,
+      {OPT_MemOffs|OPS_8|OPS_Relaxed|OPEAS_64|OPA_EA,
+       OPT_Areg|OPS_8|OPA_None, 0} },
+    { CPU_Hammer|CPU_64, 0, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2,
+      {OPT_MemOffs|OPS_16|OPS_Relaxed|OPEAS_64|OPA_EA,
+       OPT_Areg|OPS_16|OPA_None, 0} },
+    { CPU_Hammer|CPU_64, 0, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2,
+      {OPT_MemOffs|OPS_32|OPS_Relaxed|OPEAS_64|OPA_EA,
+       OPT_Areg|OPS_32|OPA_None, 0} },
     { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0xA3, 0, 0}, 0, 2,
-      {OPT_MemOffs|OPS_64|OPS_Relaxed|OPA_EA, OPT_Areg|OPS_64|OPA_None, 0} },
+      {OPT_MemOffs|OPS_64|OPS_Relaxed|OPEAS_64|OPA_EA,
+       OPT_Areg|OPS_64|OPA_None, 0} },
 
+    /* General 32-bit forms using Areg / short absolute option */
+    { CPU_Any, 0, 0, 0, 0, 1, {0x88, 0xA2, 0}, 0, 2,
+      {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA|OPAP_ShortMov, OPT_Areg|OPS_8|OPA_Spare,
+       0} },
+    { CPU_Any, 0, 16, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2,
+      {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA|OPAP_ShortMov,
+       OPT_Areg|OPS_16|OPA_Spare, 0} },
+    { CPU_386, 0, 32, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2,
+      {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA|OPAP_ShortMov,
+       OPT_Areg|OPS_32|OPA_Spare, 0} },
+    { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2,
+      {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA|OPAP_ShortMov,
+       OPT_Areg|OPS_64|OPA_Spare, 0} },
+
+    /* General 32-bit forms */
     { CPU_Any, 0, 0, 0, 0, 1, {0x88, 0, 0}, 0, 2,
       {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_8|OPA_Spare, 0} },
     { CPU_Any, 0, 16, 0, 0, 1, {0x89, 0, 0}, 0, 2,
@@ -330,6 +378,21 @@ static const x86_insn_info mov_insn[] = {
     { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0x89, 0, 0}, 0, 2,
       {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} },
 
+    /* General 32-bit forms using Areg / short absolute option */
+    { CPU_Any, 0, 0, 0, 0, 1, {0x8A, 0xA0, 0}, 0, 2,
+      {OPT_Areg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA|OPAP_ShortMov,
+       0} },
+    { CPU_Any, 0, 16, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2,
+      {OPT_Areg|OPS_16|OPA_Spare,
+       OPT_RM|OPS_16|OPS_Relaxed|OPA_EA|OPAP_ShortMov, 0} },
+    { CPU_386, 0, 32, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2,
+      {OPT_Areg|OPS_32|OPA_Spare,
+       OPT_RM|OPS_32|OPS_Relaxed|OPA_EA|OPAP_ShortMov, 0} },
+    { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2,
+      {OPT_Areg|OPS_64|OPA_Spare,
+       OPT_RM|OPS_64|OPS_Relaxed|OPA_EA|OPAP_ShortMov, 0} },
+
+    /* General 32-bit forms */
     { CPU_Any, 0, 0, 0, 0, 1, {0x8A, 0, 0}, 0, 2,
       {OPT_Reg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0} },
     { CPU_Any, 0, 16, 0, 0, 1, {0x8B, 0, 0}, 0, 2,
@@ -339,6 +402,7 @@ static const x86_insn_info mov_insn[] = {
     { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0x8B, 0, 0}, 0, 2,
       {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} },
 
+    /* Segment register forms */
     { CPU_Any, 0, 0, 0, 0, 1, {0x8C, 0, 0}, 0, 2,
       {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA,
        OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, 0} },
@@ -357,6 +421,7 @@ static const x86_insn_info mov_insn[] = {
     { CPU_Hammer|CPU_64, 0, 0, 0, 0, 1, {0x8E, 0, 0}, 0, 2,
       {OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, OPT_Reg|OPS_64|OPA_EA, 0} },
 
+    /* Immediate forms */
     { CPU_Any, 0, 0, 0, 0, 1, {0xB0, 0, 0}, 0, 2,
       {OPT_Reg|OPS_8|OPA_Op0Add, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
     { CPU_Any, 0, 16, 0, 0, 1, {0xB8, 0, 0}, 0, 2,
@@ -383,6 +448,7 @@ static const x86_insn_info mov_insn[] = {
     { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0xC7, 0, 0}, 0, 2,
       {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} },
 
+    /* CR/DR forms */
     { CPU_586|CPU_Priv|CPU_Not64, 0, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, 2,
       {OPT_CR4|OPS_32|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, 0} },
     { CPU_386|CPU_Priv|CPU_Not64, 0, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, 2,
@@ -1983,6 +2049,18 @@ yasm_x86__parse_insn(yasm_arch *arch, const unsigned long data[4],
                }
            }
 
+           if (mismatch)
+               break;
+
+           /* Check for 64-bit effective address size */
+           if (op->type == YASM_INSN__OPERAND_MEMORY) {
+               if ((info->operands[i] & OPEAS_MASK) == OPEAS_64) {
+                   if (op->data.ea->len != 8)
+                       mismatch = 1;
+               } else if (op->data.ea->len == 8)
+                   mismatch = 1;
+           }
+
            if (mismatch)
                break;
 
@@ -2076,6 +2154,7 @@ yasm_x86__parse_insn(yasm_arch *arch, const unsigned long data[4],
     d.im_sign = 0;
     d.shift_op = 0;
     d.signext_imm8_op = 0;
+    d.shortmov_op = 0;
     d.rex = 0;
 
     /* Apply modifiers */
@@ -2255,6 +2334,9 @@ yasm_x86__parse_insn(yasm_arch *arch, const unsigned long data[4],
                case OPAP_SImm8Avail:
                    d.signext_imm8_op = 1;
                    break;
+               case OPAP_ShortMov:
+                   d.shortmov_op = 1;
+                   break;
                default:
                    yasm_internal_error(
                        N_("unknown operand postponed action"));