【问题标题】:What happens to arguments pushed on the stack when a function call returns?当函数调用返回时,压入堆栈的参数会发生什么?
【发布时间】:2020-04-19 12:50:50
【问题描述】:

假设这个 C 代码:

int add(int a, int b){
 int c = a+b;
 return c;
}

int main(){
  int c = add(3,4);
  printf("%d", c);
  return 0;
}

当调用add 时会发生以下情况:

Push 4 on the stack
Push 3 on the stack
Push the address of `printf` on the stack (return address)
call `add`
// do stuff under add
pop the stack and and goto `printf`

add 下的值 4 和 3 仍在堆栈-0x18(%rbp) 上。他们不应该被清除吗?

00000000000005fa <add>:
 5fa:   55                      push   %rbp
 5fb:   48 89 e5                mov    %rsp,%rbp
 5fe:   89 7d ec                mov    %edi,-0x14(%rbp)
 601:   89 75 e8                mov    %esi,-0x18(%rbp)
 604:   8b 55 ec                mov    -0x14(%rbp),%edx
 607:   8b 45 e8                mov    -0x18(%rbp),%eax
 60a:   01 d0                   add    %edx,%eax
 60c:   89 45 fc                mov    %eax,-0x4(%rbp)
 60f:   8b 45 fc                mov    -0x4(%rbp),%eax
 612:   5d                      pop    %rbp
 613:   c3                      retq   

0000000000000614 <main>:
 614:   55                      push   %rbp
 615:   48 89 e5                mov    %rsp,%rbp
 618:   be 04 00 00 00          mov    $0x4,%esi
 61d:   bf 03 00 00 00          mov    $0x3,%edi
 622:   e8 d3 ff ff ff          callq  5fa <add>
 627:   5d                      pop    %rbp
 628:   c3                      retq  

【问题讨论】:

  • 4 和 3 被放入寄存器 ESI 和 EDI,而不是堆栈。
  • 查看
  • 你认为他们为什么会被清除?没有标准甚至惯例要求这样做。一个实现当然可以做到这一点,但大多数都做不到,因为那会很昂贵。
  • 我无法想象“添加”出来,SP 在哪里降低到局部变量之下?
  • @Jasen,编译器正在利用“红色区域”。 en.m.wikipedia.org/wiki/Red_zone_(computing)

标签: c assembly stack


【解决方案1】:

但 add 下的值 4 和 3 仍在堆栈中

并非如此,因为堆栈不再覆盖存储43 的内存。它们位于堆栈指针之外的内存中。尽管这些值仍然在内存中曾经是堆栈的一部分的位置,但它们现在是未初始化垃圾的一部分。在堆栈移动后访问它们,例如通过存储他们的地址,将是未定义的行为。

他们不应该被清除吗?

不,清除这些值是不必要的,并且可能会影响程序的运行时效率。

【讨论】:

  • 啊,我明白了,所以由于 ESP 甚至没有增加,属于 3 和 4 的内存区域只是一次使用,下次使用堆栈时将被覆盖。
  • 我想添加一个附带问题,“pop rbp”是否会增加堆栈指针?
  • @Josh 对,这正是下一次需要堆栈空间时会发生的事情。
  • @Josh 是的,pop 操作将堆栈指针向与 push 相反的方向移动。实际方向取决于架构:在某些系统上推送是增量,而在其他系统上是减量。
【解决方案2】:

当您调用pop 指令时,堆栈顶部的值存储在指定的寄存器中,并且 SP(堆栈指针)寄存器递增(在 x86 上堆栈向下增长)。它不会修改之前位于堆栈顶部的内存位置,因为没有必要这样做。

堆栈顶部的任何值都将保留在那里,直到将新值压入其顶部。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 2021-03-08
    • 2017-05-29
    • 1970-01-01
    • 2013-10-12
    相关资源
    最近更新 更多