New opcode for 32->64 bit sign-extended immediate with warning
authorH. Peter Anvin <hpa@zytor.com>
Tue, 7 Oct 2008 17:05:10 +0000 (10:05 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 7 Oct 2008 17:05:10 +0000 (10:05 -0700)
Add a new opcode for 32->64 bit sign-extended immediate, with warning
on the number not matching.

This unfortunately calls for an audit of all the \4[0123] opcodes, if
they should be replaced by \25[4567].  This only replaces one
instruction (MOV reg64,imm32); other instructions need to be
considered.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
assemble.c
disasm.c
insns.dat
insns.pl
test/immwarn.asm

index 1ed78bb..f8b782c 100644 (file)
@@ -56,6 +56,7 @@
  * \250..\253    - same as \150..\153, except warn if the 64-bit operand
  *                 is not equal to the truncated and sign-extended 32-bit
  *                 operand; used for 32-bit immediates in 64-bit mode.
+ * \254..\257    - a signed 32-bit operand to be extended to 64 bits.
  * \260..\263    - this instruction uses VEX rather than REX, with the
  *                V field taken from operand 0..3.
  * \270                 - this instruction uses VEX rather than REX, with the
@@ -953,6 +954,12 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
         case 0253:
             length += is_sbyte32(opx) ? 1 : 4;
             break;
+        case 0254:
+        case 0255:
+        case 0256:
+        case 0257:
+           length += 4;
+           break;
        case 0260:
        case 0261:
        case 0262:
@@ -1592,6 +1599,21 @@ static void gencode(int32_t segment, int64_t offset, int bits,
             }
             break;
 
+       case 0254:
+       case 0255:
+       case 0256:
+       case 0257:
+            data = opx->offset;
+           if (opx->wrt == NO_SEG && opx->segment == NO_SEG &&
+               (int32_t)data != (int64_t)data) {
+               errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
+                       "signed dword immediate exceeds bounds");
+           }
+           out(offset, segment, &data, OUT_ADDRESS, 4,
+               opx->segment, opx->wrt);
+           offset += 4;
+            break;
+
        case 0260:
        case 0261:
        case 0262:
index 46e3cf2..0ff40fc 100644 (file)
--- a/disasm.c
+++ b/disasm.c
@@ -513,6 +513,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
            break;
 
        case4(040):
+       case4(0254):
             opx->offset = getu32(data);
            data += 4;
            break;
index 8da82ed..1b28d63 100644 (file)
--- a/insns.dat
+++ b/insns.dat
@@ -768,7 +768,7 @@ MOV         reg8,imm                        \10\xB0\21                                      8086,SM
 MOV            reg16,imm                       \320\10\xB8\31                                  8086,SM
 MOV            reg32,imm                       \321\10\xB8\41                                  386,SM
 MOV            reg64,imm                       \324\10\xB8\55                                  X64,SM
-MOV            reg64,imm32                     \324\1\xC7\200\41                               X64
+MOV            reg64,imm32                     \324\1\xC7\200\255                              X64
 MOV            rm8,imm                         \1\xC6\200\21                                   8086,SM
 MOV            rm16,imm                        \320\1\xC7\200\31                               8086,SM
 MOV            rm32,imm                        \321\1\xC7\200\41                               386,SM
index cb45496..1f723dd 100755 (executable)
--- a/insns.pl
+++ b/insns.pl
@@ -658,7 +658,7 @@ sub byte_code_compile($) {
            # This allows us to match the AMD documentation and still
            # do the right thing.
            unshift(@codes, 0160+$oppos{'d'}+($oc0 ? 4 : 0));
-       } elsif ($op =~ /^(ib\,s|ib|ib\,w|iw|iwd|id|iwdq|rel|rel8|rel16|rel32|iq|seg|ibw|ibd|ibd,s)$/) {
+       } elsif ($op =~ /^(ib\,s|ib|ibx|ib\,w|iw|iwd|id|idx|iwdq|rel|rel8|rel16|rel32|iq|seg|ibw|ibd|ibd,s)$/) {
            if (!defined($oppos{'i'})) {
                die "$fname: $line: $op without 'i' operand\n";
            }
@@ -676,6 +676,8 @@ sub byte_code_compile($) {
                push(@codes, 034+$oppos{'i'});
            } elsif ($op eq 'id') { # imm32
                push(@codes, 040+$oppos{'i'});
+           } elsif ($op eq 'idx') { # imm32 extended to 64 bits
+               push(@codes, 0254+$oppos{'i'});
            } elsif ($op eq 'iwdq') { # imm16/32/64, depending on opsize
                push(@codes, 044+$oppos{'i'});
            } elsif ($op eq 'rel8') {
index 90084fb..8bffbfa 100644 (file)
@@ -72,7 +72,7 @@
        mov rax,7fffffffh
        mov rax,80000000h
 %if WARN
-       mov rax,dword 80000000h ; XXX - missing
+       mov rax,dword 80000000h
 %endif
        add rcx,0FFFFh
 %if WARN