1

我创建了这个简单且毫无意义的汇编 (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)
4

2 回答 2

2

据我所知,你一切都好。

我可以提出的一个小问题是,将地址写在这些地址的值之上可能更直观。那是:

0x2E |-------|
     | 0x13  |
0x32 |-------|

原因是覆盖值 ( 0x2E, 0x2F, 0x30, 0x31) 的地址范围朝向下一个地址0x32

当然,您可能希望在考试时使用老师期望的符号。

于 2009-06-21T05:14:22.230 回答
0

你答对了。

您正在做的是使用标准的调用者-被调用者约定执行函数调用,为被调用者创建一个框架。然后,您在返回给调用者之前执行一个简单的寄存器推送和弹出操作。这是完全正确的,您的理解是正确的(有关详细信息,请参阅http://y86tutoring.wordpress.com/2012/10/31/functioning-stacks/

一切看起来都很好。唯一的建议是您不需要在堆栈上定义 0x0000 字。只需定义 Stack 标签就可以了。

于 2012-11-08T03:18:32.523 回答