我已经创建了这个简单且毫无意义的汇编(Y86)代码,以便在使用指令调用,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)
答案 0 :(得分:2)
据我所知,你做得很好。
我可以做的一个小问题是,在这些地址上写入高于该值的地址可能更直观。那就是:
0x2E |-------|
| 0x13 |
0x32 |-------|
原因是覆盖值(0x2E
,0x2F
,0x30
,0x31
)的地址范围会转到下一个地址0x32
。< / p>
当然,您可能希望在参加考试时使用教师期望的符号。
答案 1 :(得分:0)
你做对了。
您正在做的是使用标准的caller-callee约定来执行函数调用,为被调用者创建一个框架。然后在返回调用者之前执行简单的按钮和弹出。这是完全正确的,您的理解是正确的(详见http://y86tutoring.wordpress.com/2012/10/31/functioning-stacks/)
一切看起来都不错。唯一的建议是您不需要在堆栈上定义0x0000字。只需定义Stack标签即可。