0

我正在尝试编写一个程序,将两个 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没有定义。它还说明了我对orIllegal size for operand的每个MOV调用。SUMDIFF

谁能告诉我我做错了什么或更简单的方法?我一直试图弄清楚几个小时,但进展甚微。

谢谢!

4

1 回答 1

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(jump if less) 在有符号比较后跳转。因此,0xDEADBEEF(负)将小于 0x1FEDBEEF(正)。在这种情况下,EAX 和 EBX 将交换错误,SUB 将导致负数,DIFF 将错误。顺便说一句,第二个JL永远不会跳,你的意思是JNL(如果不是更少就跳)。CMP也执行无符号比较。因此,您可以在与JB(jump if below) 进行无符号比较后进行跳转。只使用一个条件跳转就足够了(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
于 2020-02-07T17:02:34.310 回答