次のコードがどのように機能するか理解できません。これは、再帰関数を使用して数値の階乗を見つける単純なコードです。この場合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」に%eax
1 を掛けます。これは 4 の値を与えますが、これは 4 の階乗では完全に間違っています。ただし、これを実行すると、実際には 24 という正しい出力が得られます。関数が実行されるたびに乗算命令を実行する必要があると考えていました。関数が自分自身の呼び出しを終了した後ではなく、実行されます。
誰かがコードを調べて、コードが実際に24の正しい答えを与えている理由を説明してください。
そして、関数が関数内で呼び出されるたびに、ebp get がスタックにプッシュされ、esp に変更されます。(pushl %ebp Movl %esb, %ebp)。もしそうなら、関数の最後で esp,ebp 値を初期値に戻すにはどうすればよいでしょうか。(私が理解しているように、ポップは end_function で行われ、ebp、return、eax をスタックに数回プッシュした関数を数回呼び出しました)。これは、アセンブリの私のロジックがバラバラになっていることを本当に混乱させています。スタックに何が起こっているのかを定期的に説明し、各ポイントで登録してください。