assembly - 这个程序中的堆栈指针是如何通过 call 和 ret 改变的

标签 assembly x86 calling-convention

我的问题与上下文改变时似乎发生的行为有关,尤其是关于 RSPRBP .

鉴于这个非常简单的程序:

Reading symbols from ./function_call...done.
(gdb) disass main
Dump of assembler code for function main:
   0x00000000004004d6 <+0>: push   rbp
   0x00000000004004d7 <+1>: mov    rbp,rsp
   0x00000000004004da <+4>: mov    esi,0x2
   0x00000000004004df <+9>: mov    edi,0x1
   0x00000000004004e4 <+14>:    call   0x4004b6 <add_and_7>
   0x00000000004004e9 <+19>:    mov    eax,0x0
   0x00000000004004ee <+24>:    pop    rbp
   0x00000000004004ef <+25>:    ret    
End of assembler dump.
(gdb) disass add_and_7
Dump of assembler code for function add_and_7:
   0x00000000004004b6 <+0>: push   rbp
   0x00000000004004b7 <+1>: mov    rbp,rsp
   0x00000000004004ba <+4>: mov    DWORD PTR [rbp-0x14],edi
   0x00000000004004bd <+7>: mov    DWORD PTR [rbp-0x18],esi
   0x00000000004004c0 <+10>:    mov    DWORD PTR [rbp-0x4],0x7
   0x00000000004004c7 <+17>:    mov    edx,DWORD PTR [rbp-0x14]
   0x00000000004004ca <+20>:    mov    eax,DWORD PTR [rbp-0x18]
   0x00000000004004cd <+23>:    add    edx,eax
   0x00000000004004cf <+25>:    mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004004d2 <+28>:    add    eax,edx
   0x00000000004004d4 <+30>:    pop    rbp
   0x00000000004004d5 <+31>:    ret    
End of assembler dump.
(gdb) list
1   int add_and_7( int num1, int num2 ) {
2       int seven = 7;
3       return num1 + num2 + seven;
4   }
5   
6   int main() {
7       add_and_7( 1, 2 );
8       return 0;
9   }

所有功能都以 push rbp 开始据我所知,它将父上下文保留到堆栈中。父函数如何知道如何重建自己? call中是否内置了必要的步骤?和 ret ?

然后是rsp总是移到 rbp .正如我所读到的,这将新的堆栈基础设置在当前函数的上下文中。我似乎无法弄清楚的是,堆栈指针最初是何时或如何设置到该点的。我最好的猜测是汇编函数调用会这样做,这是怎么回事?

最后,当一个方法返回时,它看起来像 eax是用于父函数以利用其子函数的返回的寄存器。是 eax明确用于此目的还是这只是我的编译器和体系结构的约定?

最佳答案

How does the parent function know how to rebuild itself ? Are the necessary steps built into call and ret?



在调用函数之前,寄存器的当前状态以及返回地址被保存。 call指令跳转到被调用函数开始的特定地址。返回地址被压入堆栈。当被调用函数返回时,ret指令弹出先前推送的返回地址并转到该位置。

Then the rsp is always moved to rbp



rbp 之前被压入堆栈,以便能够从调用者的函数中恢复 rbp 的值。然后,将 rsp 移至 rbp 为被调用函数创建新的堆栈帧。新的基指针已经建立。所以目前, rbp 和 rsp 指向相同的地址。如果还有其他push说明,esp是自动调整的。功能完成后,pop ebp指令恢复先前压入的堆栈基指针地址。

关于assembly - 这个程序中的堆栈指针是如何通过 call 和 ret 改变的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25470101/

相关文章:

assembly - MASM/NASM 差异

x86 - 如何使用 SSE 计算某个范围内的字节数?

c++ - GCC 是否优化调用约定

c - 在 C 语言中,调用者是否曾经特别对待可变参数?

assembly - MIPS 语言避免管道停顿

具有非内联汇编的 Qt C++ 项目

c++ - MSVC : Reading a specific 64 or 32 bit register (e. g。 R10) 64 位代码?

c - 在编译/链接时如何使用地址进行计算?

x86 - 使用 SIMD 提取位

c++ - 为什么 x86-64 使用 IA-64 C++ ABI?