このY86アセンブリコードでスタックを正しく理解していますか?
質問
この単純で無意味なアセンブリ(Y86)コードを作成して、命令call、pushl、popl、retを使用したときにスタック内で発生しているすべてを理解できるかどうかを確認しました。
私が言ったように、このコードは無意味で、テスト/学習の目的のためだけのものです。ただし、すべてのメモリアドレスは正しく(希望的に)計算され、ランダムではありません。
アセンブリコードは次のとおりです。
| .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
以下は、スタックを描画し、各ステップ(命令)がスタックで何を行うかを説明するための最善の方法です。 SPとBPを使用してそれぞれ%espと%ebpを参照しているため、これらは頻繁に使用され、読みやすくなっていることに注意してください。
私が知りたいのは、上記のすべてが正しいかどうか、または何かを見逃したかどうかです。自由にコピー/貼り付けを行って、回答のステップを修正してください。
また、これについての私の理解は非常に重要であることに注意してください。月曜日に準備する必要がある試験があります。あなたの答えに応じて、コメントセクションで注意する関連する質問がある場合(またはない場合)があります。
- 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)
解決
あなたがそれを大丈夫だと言える限りでは。
私ができるマイナーな点の1つは、それらのアドレスの値の上にアドレスを書き込む方がおそらくより直感的だということです。つまり:
0x2E |-------|
| 0x13 |
0x32 |-------|
値をカバーするアドレス範囲( 0x2E
、 0x2F
、 0x30
、 0x31
)次のアドレス 0x32
に進みます。
もちろん、試験の実施時に教師が期待する表記法を使用することもできます。
他のヒント
正解です。
やっているのは、標準の呼び出し元と呼び出し先の規則を使用して関数呼び出しを実行し、呼び出し先のフレームを作成することです。次に、呼び出し元に戻る前に、レジスタの単純なプッシュとポップを実行します。これは完全に正しく、あなたの理解は正しいです( http://y86tutoring.wordpressを参照してください.com / 2012/10/31 / functioning-stacks / をご覧ください)
すべてがよさそうだ。唯一の提案は、スタックで0x0000ワードを定義する必要がないことです。 Stackラベルを定義するだけで済みます。