0

フィボナッチ数列を計算して出力するプログラムをNASMで書いています。2 つのシード値と反復回数のユーザー入力を受け取り、それらをスタックに格納してから、「fib」サブルーチンを呼び出して計算と出力を行います。入力/印刷の読み取りなどを行うために、ここからライブラリを使用しています。

ここに私のasm_mainがあります:

asm_main:
        enter   0,0                 ; setup routine
        pusha

    mov eax, prompt1        ; access first prompt
    call    print_string        ; print prompt
    call    read_int        ; read input and stores in eax
    push    eax         ; store input on stack

    mov eax, prompt2        ; access second prompt
    call    print_string        ; print prompt
    call    read_int        ; read input and stores in eax
    push    eax         ; store input on stack

    mov eax, prompt3        ; access third prompt
    call    print_string        ; print prompt
    call    read_int        ; read input and stores in eax
    push    eax         ; store input on stack

    call    fib         ; call fib subroutine to calculate sequence
    call    print_nl        ; end with a newline

fib サブルーチンは次のとおりです。

fib:
    pop ecx         ; retrieve number of iterations from stack
    pop ebx         ; retrieve second seed value from stack
    pop eax         ; retrieve first seed value from stack

    _looper:            ; section to be looped
        mov edx, eax
        add edx, ebx    ; sum = a + b
        call    print_int
        call    print_nl
        mov eax, ebx    ; a = b
        mov ebx, edx    ; b = sum
        loop _looper
    ret

ただし、このプッシュとポップは正しく機能しておらず、その理由がわかりません。最初のシード値として「3」、2 番目のシード値として「5」、反復回数として「7」を入力すると、fib 内で呼び出されたレジスタ ダンプの結果が次のようになります。

Register Dump # 1
EAX = 00000005 EBX = 00000007 ECX = 080484D4 EDX = BF97A1B4
ESI = 00000000 EDI = 00000000 EBP = BF97A168 ESP = BF97A144
EIP = 08048480 FLAGS = 200282       SF 

ここで何か不足していますか?私の理解では、スタックは後入れ/先出しである必要があり、何が問題なのかわかりません。ありがとう

4

1 に答える 1

1

call fib次に、最初にfibスタックからポップするのはリターンアドレスです。引数をポップオフした後にそれを押し戻すことを確認する限り、それをオフにしても問題retありません。そうしないと、最後の命令が意図しない場所に送信されます。

たとえば、次のようにすることができます

fib:
    pop edx         ; pop return address
    pop ecx         ; retrieve number of iterations from stack
    pop ebx         ; retrieve second seed value from stack
    pop eax         ; retrieve first seed value from stack
    push edx        ; put return address back on stack
    ...

しかし、より伝統的なアプローチは、スタックフレームをセットアップすることです

    push ebp
    mov ebp, esp

次に、引数にアクセスします

    mov ecx, [ebp+8]
    mov ebx, [ebp+12]

等々

そして、最後にスタック フレームと引数を取り出します。

    mov esp, ebp
    pop ebp
    ret 12

この後者のアプローチにより、ルーチンへのエントリ時だけでなく、必要なときに引数にアクセスできます。

于 2013-05-04T20:44:48.973 に答える