MASM x86组件中的32位加减法

问题描述 投票:0回答:1

我正在尝试编写一个程序,该程序将两个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和链接程序来构建我的代码。

我似乎遇到的问题是,当我尝试构建代码时,它说未定义EAXEBX。它还为我对Illegal size for operandMOV的每个SUM调用都说DIFF

有人可以告诉我我做错了什么,或者更简单的方法吗?我已经尝试了好几个小时,但进展甚微。

谢谢!

assembly x86 masm x86-16
1个回答
1
投票

您可以使用.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

© www.soinside.com 2019 - 2024. All rights reserved.