この単純で無意味なアセンブリ(Y86)コードを作成して、命令の呼び出し時にスタック内で起こっていることをすべて理解しているかどうかを確認しました。このY86アセンブリコードでスタックが正しく理解できますか?
私が言ったように、このコードは無意味です、それは単なるテスト/学習の目的です。しかし、すべてのメモリアドレスが正しく(有望な)計算され、ランダムではありません。
アセンブリコードは以下の通りです:
| .pos 0
0x00 | irmovl Stack, %esp
0x06 | rrmovl %esp, %ebp
0x08 | irmovl $5, %eax
0x0E | call func
0x13 | halt
0x14 | func:
0x14 | pushl %ebp
0x16 | rrmovl %esp, %ebp
0x18 | pushl %eax
0x1A | popl %eax
0x1C | popl %ebp
0x1E | ret
| .pos 50
0x32 | Stack: .long 0
次のスタックを描き、各ステップ(命令)がスタックに何をするかを説明するために私の最善の方法です。 %espと%ebpを参照するのにSPとBPを使用していたことに注意してください。なぜなら、それらは多く使われて読みやすくなります。
私が知りたいのは、上記のすべてが上にあるか、私が何かを逃した場合です。自由にコピー/ペーストして、あなたの答えにいくつかのステップを修正してください。
また、私の理解は非常に重要なので、私は準備が必要な月曜日の試験があります。私はあなたに私が与えることができる最高の答えがほしいと思います。あなたの答えに応じて、コメント欄で気をつけなければならないいくつかの関連する質問があるかもしれません。
- INSTRUCTION: irmovl Stack, %esp
- INSTRUCTION: rrmovl %esp, %ebp
1) Point %esp (SP) and %ebp (BP) to Stack
| ... |
0x2E |-------|
| |
0x32 |-------| <--- SP & BP
- INSTRUCTION: irmovl $5, %eax
1) Sets %eax = 5
- INSTRUCTION: call func
1) Decrements SP by 4 (0x32 -> 0x2E)
2) Saves return address (0x13) in memory location pointed by SP (0x2E)
3) Jumps to "func" memory address (0x14)
| ... |
0x2A |-------|
| 0x13 |
0x2E |-------| <--- SP
| |
0x32 |-------| <--- BP
- INSTRUCTION: pushl %ebp
1) Decrements SP by 4 (0x2E -> 0x2A)
2) Saves BP value (0x32) in memory location pointed by SP (0x2A)
| ... |
0x26 |-------|
| 0x32 |
0x2A |-------| <--- SP
| 0x13 |
0x2E |-------|
| |
0x32 |-------| <--- BP
- INSTRUCTION: rrmovl %esp, %ebp
1) Sets BP = SP (0x32 -> 0x2A)
| ... |
0x26 |-------|
| 0x32 |
0x2A |-------| <--- SP & BP
| 0x13 |
0x2E |-------|
| |
0x32 |-------|
- INSTRUCTION: pushl %eax
1) Decrements SP by 4 (0x2A -> 0x26)
2) Saves %eax value (5) in memory location pointed by SP (0x26)
| ... |
0x22 |-------|
| 5 |
0x26 |-------| <--- SP
| 0x32 |
0x2A |-------| <--- BP
| 0x13 |
0x2E |-------|
| |
0x32 |-------|
- INSTRUCTION: popl %eax
1) Saves value (5) in memory location pointed by SP (0x26) in %eax
2) Increments SP by 4 (0x26 -> 0x2A)
| ... |
0x22 |-------|
| 5 |
0x26 |-------|
| 0x32 |
0x2A |-------| <--- SP & BP
| 0x13 |
0x2E |-------|
| |
0x32 |-------|
- INSTRUCTION: popl %ebp
1) Saves value (0x32) in memory location pointed by SP (0x2A) in %ebp
2) Increments SP by 4 (0x2A -> 0x2E)
| ... |
0x22 |-------|
| 5 |
0x26 |-------|
| 0x32 |
0x2A |-------|
| 0x13 |
0x2E |-------| <--- SP
| |
0x32 |-------| <--- BP
- INSTRUCTION: ret
1) Jumps to memory address (0x13) in memory location pointed by SP (0x2E)
2) Increments SP by 4 (0x2E -> 0x32)
実際に私は使用される "表記法"を知らない:/その例では、私は常に0x13が[0x2E、0x2D、0x2C、0x2B]に保存されるだろうが、それはちょうど私にとって意味がある。誰かが私に「あなたは大丈夫だ」と答えると、これは別の質問につながります。なぜ[0x32、0x31、0x30、0x2F]に空白のブロックを残しますか? –
これはあなたがそのように説明した理由を説明しますが、スタックは/ grow/downwards(つまり、新しい要素が最後より下にある)のみであり、要素自体も後方に格納されているわけではありません。 xの(4バイト)要素は、常にx、x + 1、x + 2、x + 3に格納されます。スタックのためにこれを逆にすることは、スタックからのアドレスを "普通"のコードで簡単に使用できないことを意味します。スタックの一番下にある空のブロックについては、これはpushl vが%espではなく%esp-4にvを格納しているという結果です。もちろん、多くの場合、%espの初期値を変更することでこれを避けることができます。 – mweerden