我正在尝试编写一个程序,该程序将两个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
;**********************************************************
我对程序集了解不多,但是我正在使用DOSBOX,MASM 5.10和链接程序来构建我的代码。
我似乎遇到的问题是,当我尝试构建代码时,它说未定义EAX
和EBX
。它还为我对Illegal size for operand
或MOV
的每个SUM
调用都说DIFF
。
有人可以告诉我我做错了什么,或者更简单的方法吗?我已经尝试了好几个小时,但进展甚微。
谢谢!
您可以使用.386
指令访问16位程序中的32位寄存器。但是它仍然是一个16位程序!
对32位寄存器的访问是通过在机器代码中向指令编码添加显式前缀(66h-“操作数大小前缀”)来完成的。但是,不使用.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
to
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
to
MOV AX,DSEG ;Initialize DS
MOV DS,AX
您通常不能在同一指令中使用不同的操作数大小(16位和32位)。
更改
XCHG EAX,BX ; Swap values of EAX and EBX
to
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
不会做您期望的事情。在比较[[signed之后,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
to
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