MASM中的奇怪行为:“dec”指令导致减法2

时间:2013-08-21 15:08:58

标签: assembly x86 masm irvine32

我正在编写一个程序来显示当前时间和日期10秒。我被指示我可能只使用smallwin.inc。我编写了一个使用Irvine32.inc工作的程序,但是当我切换到只有smallwin时,我需要编写一些输出数字的程序。当我添加这些时,一个非常奇怪的行为开始发生!我使用调用“dec repTime”,它将减少2而不是1!我尝试过“sub repTime,1”,它仍然是一样的!我甚至将repTime移到eax,然后减去1,然后将eax移回repTime,它仍然减去2!

我写的程序应该运行10秒钟。由于减法2问题,它运行4秒而不是!有什么问题?!?

这是我的代码:

; this code demonstrates the usage of Windows API functions to display
; current date and time. It provides a running digital clock that updates
; itself for 10 seconds. The output is displayed starting with cursor position
; (5,5) and uses yellow foreground and blue background.

INCLUDE smallwin.inc

.data
buffer DB 256 DUP(?)
prompt    BYTE "Today is: "                  ; strings used to format the output
slash     BYTE '/'
colon     BYTE ':'
space     BYTE "     Time: "
newLine   WORD 0D0Ah                         
repTime   DWORD 10                           ; display time for 10 seconds   
cursPos   COORD <5,5>                        ; cursor coordinates

.data?
outHandle DWORD ?                            ; storage for console output handle
sysTimeNow   SYSTEMTIME <>                      ; storage for system time structure
sysTimeFuture SYSTEMTIME <>

.code

WriteChar PROC

pushfd
pushad
mov  buffer,al
INVOKE WriteConsole, outHandle, OFFSET buffer, 1, 0, 0

popad
popfd
ret
WriteChar ENDP

outInt PROC USES eax ebx ecx edx,
number: SDWORD               ; method parameter
mov ebx, 10                ; divisor for the radix system
xor ecx, ecx               ; digits counter
cmp number, 0              ; is number >= 0?
jge go                      ; yes - proceed
neg number                 ; negate the number
mov al, '-'
INVOKE WriteChar

go:
mov eax, number   
puDigit:
xor edx, edx
div ebx                    ; get one digit
push edx                   ; save it for further processing
inc ecx                    ; update the digits counter
cmp eax, 0                 ; end of processing
jne puDigit

printIT:
pop eax                     ; get a digit from stack
or al, 30h                 ; ASCII conversion
INVOKE WriteChar           ; print it
loop printIT

ret
outInt ENDP

format2 PROC 
LOCAL zero:BYTE

mov zero, '0'
cmp ax, 10                              ; number < 10 ?
jge L 
push eax                                ; YES - output preceeding 0
INVOKE WriteConsole, outHandle, ADDR zero, 1, 0, 0
pop eax
L:   INVOKE outInt, eax                          ; output the number itself

ret
format2 ENDP


main PROC
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov outHandle, eax                      ; get console handle for output

INVOKE SetConsoleTextAttribute, outHandle, 30 ; setup colors
INVOKE GetLocalTime, ADDR sysTimeFuture

;set Future Time to Dec 25, 2013
mov sysTimeFuture.wDay, 25
mov sysTimeFuture.wMonth, 12
mov sysTimeFuture.wYear, 2013
mov sysTimeFuture.wHour, 0
mov sysTimeFuture.wMinute, 0
mov sysTimeFuture.wSecond, 0


startLabel:
INVOKE SetConsoleCursorPosition, outHandle, cursPos

INVOKE GetLocalTime, ADDR sysTimeNow       ; retrieve current date/time

INVOKE WriteConsole, outHandle, ADDR prompt,
SIZEOF prompt, 0, 0                  ; output prompt

mov eax, 0
mov ax, sysTimeNow.wDay                    ; day of the month
call format2
INVOKE WriteConsole, outHandle, ADDR slash, 1, 0, 0 ; output '/'

mov ax, sysTimeNow.wMonth                  ; month number
call format2
INVOKE WriteConsole, outHandle, ADDR slash, 1, 0, 0 ; output '/'

mov ax, sysTimeNow.wYear                   ; print out the year
INVOKE outInt, ax
INVOKE WriteConsole, outHandle, ADDR space, SIZEOF space, 0, 0 

mov ax, sysTimeNow.wHour                   ; output hours
call format2
INVOKE WriteConsole, outHandle, ADDR colon, 1, 0, 0 ; output ':'

mov ax, sysTimeNow.wMinute                 ; output minutes
call format2
INVOKE WriteConsole, outHandle, ADDR colon, 1, 0, 0 ; output ':'

mov ax, sysTimeNow.wSecond                 ; output seconds
call format2

INVOKE Sleep, 1000                      ; wait for 1 second
dec repTime                             ; update the stop watch counter
jnz startLabel

INVOKE SetConsoleTextAttribute, outHandle, 15 ; reset the colors 
INVOKE WriteConsole, outHandle, ADDR newLine, 2, 0, 0 ; start new line
INVOKE ExitProcess, 0 
main ENDP

END main

1 个答案:

答案 0 :(得分:0)

查看outint的原型:

outInt PROTO number:SDWORD

预期的参数是 S 签名 DWORD - SDWORD或者它可能是DWORD,无所谓,看看你传递的是什么作为参数:

mov     ax, sysTimeNow.wYear                   ; print out the year
INVOKE  outInt, ax

您正在传递一个WORD大小的注册表作为参数,并在程序中使用eax

将以上两行更改为:

movzx   eax, sysTimeNow.wYear                   ; print out the year
INVOKE  outInt, eax

或:

xor     eax, eax
mov     ax, sysTimeNow.wYear                   ; print out the year
INVOKE  outInt, eax

eax的上半部分“清零”并使其正常工作。或者,您可以做的是使该过程期望WORD大小的参数,因为这是您传递的内容,并在proc中使用ax而不是eax

相关问题