0

2 つの 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また、 orへの呼び出しIllegal size for operandごとにも表示されます。MOVSUMDIFF

私が間違っていること、またはこれを行うためのより簡単な方法を誰かに教えてもらえますか? 私は数時間それを理解しようとしてきましたが、ほとんど進歩していません。

ありがとう!

4

1 に答える 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') は、スタックから 2 つの 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 は間違ったものになります。ところで、2 番目JLは決してジャンプしJNLません。符号なし比較もCMP実行します。したがって、 (jump if below)との符号なし比較の後にジャンプできます。次の命令をスキップする可能性のある条件付きジャンプ (JNB - 以下でない場合はジャンプ) を 1 つだけ使用するだけで十分です。JB

変化する

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 に答える