0

だから私はアセンブラで階乗関数を作成しようとしています

c:

 #include<stdio.h>



int fat (int n) 
{
      if (n==0) return 1;
      else return n*fat(n-1);
}

    int main (void){

    printf("%d\n", fat(4));
       return 0;

    }

アセンブリで:

.text

.global    fat
fat:push    %ebp   
    mov    %esp, %ebp
    movl    $1,%eax
    movl    4(%ebp),%edx

LOOP:cmp    $0,%edx
    je FIM
    sub    $1,%edx
    push    %edx
    call    fat
    imul    %edx,%eax

FIM:mov    %ebp, %esp
    pop    %ebp
    ret

セグメンテーション違反エラーが発生し続けますが、理由がわかりません...誰か助けてもらえますか?

4

2 に答える 2

2

次の行のオフセットはおそらく間違っています。

movl    4(%ebp),%edx

スタックには以前の値%ebpと戻りアドレスが既にあるため、オフセットは 4 より大きくする必要があります。

デバッガーを使用してアセンブリ コードをステップ実行し、すべてのレジスタ値が期待どおりであることを確認することをお勧めします。%edxまた、レジスタの値も保存して復元しない限り、複数の呼び出しでレジスタに問題が発生します。

于 2012-09-29T21:21:20.240 に答える
1
fat:push    %ebp   
    mov    %esp, %ebp
    movl    $1,%eax
    movl    4(%ebp),%edx /* Must be 8(%ebp) because of the return address! */

LOOP:cmp    $0,%edx
    je FIM
    sub    $1,%edx
    push    %edx
    call    fat /* The call to fat() just trashed edx, oops. Gotta save/restore it! */
    imul    %edx,%eax /* The result will be in edx, but you need to return it in eax! */
    /* Why isn't "push %edx" compensated here with "pop" or "addl $4,%esp"??? */
FIM:mov    %ebp, %esp
    pop    %ebp
    ret

C関数をアセンブリ風のスタイルに書き直すと役立つ場合があります。

int fat (int n) 
{
    int eax, edx, savedEdx;

    eax = 1;
    edx = n; /* n = %8(%ebp) */
    if (edx == 0)
      goto done;

    savedEdx = edx; /* can do this with pushl %edx */
    --edx;
    eax = fat(edx); /* pushl %edx; call fat; addl $4, %esp or popl %edx */
    edx = savedEdx; /* popl %edx */

    eax *= edx; /* can do this with imul %edx */

done:
    return eax;
}
于 2012-09-29T21:39:58.327 に答える