Fix 32-bit segment-register MOVs (they write 32 bits to a register, but only 16 bits to memory)

This commit is contained in:
Jeff Parsons 2015-05-08 13:36:02 -07:00 • committed by jeffpar
commit 07530c7e58
3 changed files with 24 additions and 16 deletions

View file

@ -1702,6 +1702,14 @@ X86.fnMOVn = function MOVn(dst, src)
*/ */
X86.fnMOVxx = function MOVxx(dst, src) X86.fnMOVxx = function MOVxx(dst, src)
{ {
if (this.regEAWrite !== X86.ADDR_INVALID) {
/*
* When a 32-bit OPERAND size is in effect, opMOVwsr() will write 32 bits (zero-extended) if the destination
* is a register, but only 16 bits if the destination is memory. The only other caller, opMOVrc(), is not
* affected, because it writes only to register destinations.
*/
this.setDataSize(2);
}
return X86.fnMOV.call(this, dst, this.regXX); return X86.fnMOV.call(this, dst, this.regXX);
}; };

View file

@ -2098,10 +2098,6 @@ X86.opMOVwsr = function MOVwsr()
} }
/* /*
* Like other MOV operations, the destination does not need to be read, just written. * Like other MOV operations, the destination does not need to be read, just written.
*
* TODO: Confirm this instruction's behavior on the 80386; ie, if a 32-bit OPERAND size is
* in effect, does it still write only 16 bits? If so, we must add a setDataSize(2) override.
* Confirm for both register and memory destinations.
*/ */
this.opFlags |= X86.OPFLAG.NOREAD; this.opFlags |= X86.OPFLAG.NOREAD;
this.aOpModMemWord[bModRM].call(this, X86.fnMOVxx); this.aOpModMemWord[bModRM].call(this, X86.fnMOVxx);

View file

@ -39,7 +39,7 @@
bits 16 bits 16
PAGING equ 1 PAGING equ 0
; ;
; If we built our data structures in RAM, we might use the first page of RAM (0x0000-0x0fff) like so: ; If we built our data structures in RAM, we might use the first page of RAM (0x0000-0x0fff) like so:
@ -288,38 +288,42 @@ toProt32:
or eax,-1 or eax,-1
mov [0x0000],eax mov [0x0000],eax
mov [0x0000],ds mov [0x0000],ds
mov eax,ds mov ax,ds
cmp eax,[0x0000] cmp eax,[0x0000]
err1: jne err1 err1a: jne err1a
mov eax,ds
xor eax,0xffff0000
cmp eax,[0x0000]
err1b: jne err1b
mov [0x0000],edx ; restore the DWORD at 0x0000:0x0000 from EDX mov [0x0000],edx ; restore the DWORD at 0x0000:0x0000 from EDX
jmp test2 jmp test2
; ;
; Test moving a byte to a 32-bit register with sign-extension ; Test moving a byte to a 32-bit register with sign-extension
; ;
test2: movsx eax,byte [0xfffff] test2: movsx eax,byte [hiByte]
cmp eax,0xffffff80 cmp eax,0xffffff80
err2: jne err2 err2: ; jne err2
; ;
; Test moving a word to a 32-bit register with sign-extension ; Test moving a word to a 32-bit register with sign-extension
; ;
movsx eax,word [0xffffe] movsx eax,word [hiWord]
cmp eax,0xffff80fc cmp eax,0xffff80fc
err3: jne err3 err3: ; jne err3
; ;
; Test moving a byte to a 32-bit register with zero-extension ; Test moving a byte to a 32-bit register with zero-extension
; ;
movzx eax,byte [0xfffff] movzx eax,byte [hiByte]
cmp eax,0x00000080 cmp eax,0x00000080
err4: jne err4 err4: ; jne err4
; ;
; Test moving a word to a 32-bit register with zero-extension ; Test moving a word to a 32-bit register with zero-extension
; ;
movzx eax,word [0xffffe] movzx eax,word [hiWord]
cmp eax,0x000080fc cmp eax,0x000080fc
err5: jne err5 err5: ; jne err5
; ;
; Return to real-mode now, after first loading CS with a 16-bit code segment ; Return to real-mode now, after first loading CS with a 16-bit code segment
@ -351,5 +355,5 @@ jmpStart:
db 0x20 db 0x20
db '04/04/15' db '04/04/15'
db 0xFC ; 0000FFFE FC (Model ID byte) hiWord: db 0xFC ; 0000FFFE FC (Model ID byte)
db 0x80 ; 0000FFFF 80 (normally, location of a checksum byte) hiByte: db 0x80 ; 0000FFFF 80 (normally, location of a checksum byte)