3

学生が組み合わせの計算を練習できるように、アセンブリ言語(MASM)でプログラムを作成しました。プログラムは階乗を再帰的に計算します。nとrを受け取り、(n = r)!、n !、およびr!を取得するcombinationsという手順を使用します。階乗と呼ばれるプロシージャを呼び出すことによって。階乗は再帰的です。

.data
n       DWORD   ?
r       DWORD   ?
result  DWORD   ?
answer            DWORD ?
divisor DWORD   ?

.code
MAIN    PROC

(いくつかの予備手順の呼び出し)

push OFFSET divisor     ;ebp+20
push n              ;ebp+16
push r              ;ebp+12
push OFFSET result      ;ebp+8
call    combinations

;*************************************************
; combinations calls factorial (3 times) to calculate n!, r!, and (n-r)!.
; combinations calculates n!/(r!(n-r)!) , and stores the value in result.
; receives:  accepts n and r by value and result by address.
; returns: none
; preconditions: none
; registers changed:  eax, ebx, edx
;*************************************************
combinations    PROC
push        ebp
mov     ebp,esp

mov     eax, [ebp+16]   ;find (n-r)!
sub     eax, [ebp+12]
mov     ebx, eax
push        ebx
call        factorial
pop     ebx
mov     edx,[ebp+20]    ;move (n-r)! into result
mov     [edx],eax

mov     ebx, [ebp+12]        ;find r!
push        ebx
call        factorial
pop     ebx

mov     edx,[ebp+20]
mov     ebx, [edx]
mul     ebx         ;r!*(n-r)!, store product in eax
mov     ebx, [ebp+20]
mov     [ebx], eax          ;store product in divisor variable

mov     ebx, [ebp+16]   ;find n!
push        ebx
call        factorial
pop     ebx
mov     edx,[ebp+20]            
mov     ebx,[edx]           ;move value of divisor into ebx

mov     edx, 0
div     ebx         ;divide n! by divisor (r!*(n-r)!)
mov     ebx, [ebp+8]
mov     [ebx],eax                 ;move quotient into result

pop     ebp
ret     16
combinations    ENDP

;*************************************************
; calculates factorial recursively
; receives: 
; returns: factorial solution in eax
; preconditions: none
; registers changed: eax
;*************************************************
factorial   PROC
mov eax,dword ptr [esp+4]
cmp eax,1
jle endRecursive
dec eax
push eax
call factorial
mov esi,dword ptr [esp+4]
mul esi
endRecursive:
    ret 4
factorial   ENDP

すべてが期待どおりに進み、必要な値を取得しています。ただし、すべての計算が完了し、プログラムが組み合わせ手順の最後に「ret 16」というステートメントに到達すると、次の例外が発生します。

Project.exeの0x76f915deで未処理の例外:0xC0000005:アクセス違反。

デバッガーで実行し、計算を間違えた場合にreturnステートメントを変更しようとしましたが、これまで試したことは何も機能しませんでした。じっと見つめすぎたのかもしれませんが、どんなアイデアでもよろしくお願いします。前もって感謝します。

更新: デバッガーでebpとespを追跡するだけです。プログラムが最後の階乗呼び出しから出たとき、espはebpの+12であるため、階乗の呼び出しごとに+4が追加されます。その結果、プログラムがpop ebpにヒットすると、ebpは本来あるべき場所ではなくrを指しています。これを修正する方法について何か提案はありますか?

4

1 に答える 1

3

pop ebxへの3つのトップレベル呼び出しの後に表示される3つの命令を削除する必要がありますfactorialfactorialすでに(を使用して)引数をスタックからポップしているので、スタックポインタを台無しにしret 4て、引数を再度削除しようとします。pop ebx

于 2012-12-01T07:55:08.100 に答える