我正在尝试编写一个程序,它可以添加和减去两个32位数字,并存储内存中的总和和差异。我没有任何输出,只是通过调试器获得结果。
这是我的代码。
;---------------------------------------------------------;
;**********************************************************
STACK SEGMENT PARA STACK 'STACK'
DB 64 DUP('STACK')
STACK ENDS
;**********************************************************
DSEG SEGMENT PARA PUBLIC 'DATA'
X1 DD 4967290
X2 DD 4967295
SUM DD ?
DIFF DD ?
DSEG ENDS
;**********************************************************
;---------------------------------------------------------
CSEG SEGMENT PARA PUBLIC 'CODE'
OUR_PROG PROC FAR
ASSUME CS:CSEG, DS:DSEG, SS:STACK
; Set up the stack to contain the proper values
; so this program can return to debug.
;
PUSH DS ; Put return seg. addr on stack
MOV EAX,0 ; Clear a register EAX
PUSH EAX ; Put zero return address on stack
; Initialize the data segment address
MOV EAX,DSEG ;Initialize DS
MOV DS,AX
; -------------------------------------------------------------
; Perform the addition
;
MOV EAX,X1 ; Load 32 bit variable in X1 to reg AX
MOV EBX,X2 ; Load 32 bit variable in X2 to reg BX
ADD EAX,EBX ; Add data in registers AX and BX, store in AX
; Store the sum in memory
;
MOV SUM,EAX ; Store the result at mem loc SUM
; -------------------------------------------------------------
; Perform the subtraction
MOV EAX,X1 ; Reload first word to reg EAX
CMP EAX,EBX ; Compare values of X1 and X2 stored in registers EAX and EBX
JL .SWAPSUB ; If EBX is greater than EAX, jump to SWAPSUB
JL .NOSWAP ; If '' , jump past other sub section
.SWAPSUB: ;Jump point to swap values
XCHG EAX,BX ; Swap values of EAX and EBX
.NOSWAP:
SUB EAX,EBX ; Subtract EBX from EAX
MOV DIFF,EBX ; Store the result at mem loc DIFF
RET ; Retrurn to DEBUG
OUR_PROG ENDP
CSEG ENDS
END OUR_PROG
;**********************************************************
我不太了解Assembly,但我正在使用DOSBOX,MASM 5.10和链接器程序来构建我的代码。
我似乎遇到的问题是,当我尝试构建代码时,它表示EAX
和EBX
未定义。对于Illegal size for operand
或MOV
的{{1}}次来电,它还会SUM
说。
任何人都可以告诉我我做错了什么或更简单的方法吗?我一直试图弄清楚几个小时,但收效甚微。
谢谢!
答案 0 :(得分:1)
您可以使用.386
指令在16位程序中访问32位寄存器。但是它仍然是一个16位程序!
在机器代码中,通过在指令编码中添加显式前缀(66h-“操作数大小前缀”)来访问32位寄存器。但是,未使用.386
伪指令的.MODEL
强制MASM假定32位程序正在运行,而不是每次都切换到32位。在这种情况下,您必须明确告诉汇编器使用16位段,因此它将假定代码将以16位模式执行:
STACK SEGMENT PARA STACK 'STACK' USE16
...
DSEG SEGMENT PARA PUBLIC 'DATA' USE16
...
CSEG SEGMENT PARA PUBLIC 'CODE' USE16
...
继续通过组合16位段部分和16位偏移量部分来形成存储器地址。 “ RETF”(“ PROC FAR”)从堆栈中获取两个16位值,然后跳到那里。
更改
PUSH DS ; Put return seg. addr on stack
MOV EAX,0 ; Clear a register EAX
PUSH EAX ; Put zero return address on stack
到
PUSH DS ; Put PSP seg. addr on stack
MOV AX,0 ; Clear a register AX
PUSH AX ; Put zero return address on stack
段地址保持16位。因此,32位EAX具有不同的操作数大小。
更改
MOV EAX,DSEG ;Initialize DS
MOV DS,AX
到
MOV AX,DSEG ;Initialize DS
MOV DS,AX
通常,同一条指令中不能使用不同的操作数大小(16位和32位)。
更改
XCHG EAX,BX ; Swap values of EAX and EBX
到
XCHG EAX,EBX ; Swap values of EAX and EBX
在16位操作(MS-DOS)期间可以短时间切换到完整的32位操作(保护模式),但这非常复杂并且容易出错,因此不建议使用。
JL .SWAPSUB ; If EBX is greater than EAX, jump to SWAPSUB
JL .NOSWAP ; If '' , jump past other sub section
不会执行您期望的操作。在进行了签名比较后,JL
(如果不多,则跳转)跳转。因此,0xDEADBEEF(负)将小于0x1FEDBEEF(正)。在这种情况下,EAX和EBX交换错误,SUB将导致负数,而DIFF将错误。顺便说一句,第二个JL
将永远不会跳转,您的意思是JNL
(如果不小于,则跳转)。 CMP
也会执行 unsigned 比较。因此,您可以在与JB
进行无符号比较之后进行跳转(如果低于,则跳转)。仅使用一个条件跳转就足够了(JNB-如果不低于此条件,则跳转),这可能会跳过下一条指令。
更改
JL .SWAPSUB ; If EBX is greater than EAX, jump to SWAPSUB
JL .NOSWAP ; If '' , jump past other sub section
到
JNB .NOSWAP ; If EAX not below EBX, skip over .SWAPSUB
在SUB EAX,EBX
之后,区别在于EAX
,而不是EBX
。
利用MASM 5.1和更高版本的可能性的示例:
.MODEL SMALL, C ; 'C' also enables local labels and variables in MASM 5.1
.386 ; Enable features of the i386 processor
.STACK 1000h ; Reserve space for stack and initialize stack pointer
.DATA
X1 DD 1FEDBEEFh ; 535674607
X2 DD 0DEADBEEFh ; 3735928559
SUM DD ?
DIFF DD ?
SUM_STR DB 16 DUP ('$')
DIFF_STR DB 16 DUP ('$')
S DB "SUM: $"
D DB "DIFF: $"
CrLf DB 13, 10, '$'
.CODE
OUR_PROG PROC
; -------------------------------------------------------------
; Initialize the data segment address
MOV AX, @DATA ; Initialize DS
MOV DS, AX
; -------------------------------------------------------------
; Perform the addition
;
MOV EAX, X1 ; Load 32 bit variable in X1 to reg EAX
MOV EBX, X2 ; Load 32 bit variable in X2 to reg EBX
ADD EAX, EBX ; Add data in registers AX and BX, store in EAX
MOV SUM, EAX ; Store the result at mem loc SUM
; -------------------------------------------------------------
; Perform the subtraction
MOV EAX, X1 ; Reload first word to reg EAX
CMP EAX, EBX ; Compare values of X1 and X2 stored in registers EAX and EBX
JNB SHORT @F
XCHG EAX, EBX ; Swap values of EAX and EBX
@@:
SUB EAX, EBX ; Subtract EBX from EAX
MOV DIFF, EAX ; Store the result at mem loc DIFF
; -------------------------------------------------------------
; Display the stuff
MOV EAX, SUM ; "SUM: 4271603166"
LEA DI, SUM_STR
CALL eax2dec
LEA DX, S
MOV AH, 9 ; http://www.ctyme.com/intr/rb-2562.htm
INT 21h
LEA DX, SUM_STR
INT 21h
LEA DX, CrLf
Int 21h
MOV EAX, DIFF ; "DIFF: 3200253952"
LEA DI, DIFF_STR
CALL eax2dec
LEA DX, D
MOV AH, 9 ; http://www.ctyme.com/intr/rb-2562.htm
INT 21h
LEA DX, DIFF_STR
INT 21h
LEA DX, CrLf
Int 21h
; -------------------------------------------------------------
; Exit the program
MOV AX, 4C00h ; Exit with code 0
INT 21h ; Call MSDOS
OUR_PROG ENDP
; -------------------------------------------------------------
; Convert an integer in EAX to a decimal ASCII string
eax2dec PROC ; ARG EAX DWORD, DI: offset of string
LOCAL Regs[4]:DWORD
IF (@Version EQ 510) ; Bug in MASM 5.1: Wrong offset with `Regs`
mov [bp-16], eax ; Preserve some registers
mov [bp-12], ebx
mov [bp-8], ecx
mov [bp-4], edx
ELSE
mov [Regs+0], eax
mov [Regs+4], ebx
mov [Regs+8], ecx
mov [Regs+12], edx
ENDIF
xor cl, cl ; Counter
mov ebx, 10 ; Base 10
@@:
xor edx,edx ; Clear EDX for division
div ebx ; EAX/10 remainder EDX (eff. DL)
push dx ; Onto the stack to get it later LIFO
inc cl ; Increment counter
test eax, eax ; Anything more to divide?
jnz @B ; Yes - jump to the @@ before
@@:
pop ax ; Get back the remainders LIFO
or al, 30h ; Convert to ASCII
mov [di], al ; Store it
inc di ; Pointer to ASCII string
dec cl ; Decrement pointer
jnz @B ; If remainders left, jump to the @ before
mov BYTE PTR [di], '$' ; Terminator for INT 21h/09h
IF (@Version EQ 510) ; Bug in MASM 5.1: Wrong offset with `Regs`
mov eax, [bp-16] ; Restore some registers
mov ebx, [bp-12]
mov ecx, [bp-8]
mov edx, [bp-4]
ELSE
mov eax, [Regs+0]
mov ebx, [Regs+4]
mov ecx, [Regs+8]
mov edx, [Regs+12]
ENDIF
ret ; RET: DI points to the terminating '$'
eax2dec ENDP
;**********************************************************
END OUR_PROG ; END of source & entry point