4

次のコードがどのように機能するか理解できません。これは、再帰関数を使用して数値の階乗を見つける単純なコードです。この場合4*3*2*1 = 24

.section .data
.section .text
.globl _start
._start:

 pushl $4
 call factorial
 addl $4, %esp

 movl %eax, %ebx
 movl $1, %eax
 int $0x80

 .type factorial, @function
 factorial:
 pushl %ebp
 movl %esp, %ebp
 movl 8(%ebp), %eax

 cmpl $1, %eax
 je end_factorial
 decl %eax
 pushl %eax
 call factorial
 movl 8(%ebp), %ebx
 imull %ebx, %eax

 end_factorial:
 movl %ebp, %esp
 popl %ebp
 ret

このセクションが実行される理由がわかりません (行 25/26) を除いて、コードに関するすべてを理解しています。

movl 8(%ebp), %ebx
imull %ebx, %eax

私の理解 (これは明らかに間違っています) は、関数は の値が 1 になるまで自分自身を呼び出し続けるということです%eax。その時点で、「4」に%eax1 を掛けます。これは 4 の値を与えますが、これは 4 の階乗では完全に間違っています。ただし、これを実行すると、実際には 24 という正しい出力が得られます。関数が実行されるたびに乗算命令を実行する必要があると考えていました。関数が自分自身の呼び出しを終了した後ではなく、実行されます。

誰かがコードを調べて、コードが実際に24の正しい答えを与えている理由を説明してください。

そして、関数が関数内で呼び出されるたびに、ebp get がスタックにプッシュされ、esp に変更されます。(pushl %ebp Movl %esb, %ebp)。もしそうなら、関数の最後で esp,ebp 値を初期値に戻すにはどうすればよいでしょうか。(私が理解しているように、ポップは end_function で行われ、ebp、return、eax をスタックに数回プッシュした関数を数回呼び出しました)。これは、アセンブリの私のロジックがバラバラになっていることを本当に混乱させています。スタックに何が起こっているのかを定期的に説明し、各ポイントで登録してください。

4

1 に答える 1

3

関数の戻り値は常に%eax

アセンブリ関数が経由して factorial を呼び出し、%eax毎回 1 ずつ減分してスタックにプッシュします。1つに%eaxなると、ようやく戻ってきます。これによりcall factorial、再帰呼び出しで%eaxwas 2 に戻ります。これは に格納されてい8(%ebp)ます (プッシュされたことを思い出してください)。これで、 2*1=2= ができ%eaxました。factorialこれで終了して再び戻り、最初に呼び出した関数に戻るまでプロセスが繰り返されます。

于 2012-11-06T02:18:27.687 に答える