如何通过call和ret在该程序中更改堆栈指针
我的问题涉及在情况发生变化时似乎发生的行为,特别是有关RSP
和RBP
。
鉴于这个非常简单的程序:
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 }
所有的功能开始推rbp
,据我所知,它是保存父上下文到堆栈上。 父功能如何知道如何重建自己? call
和ret
内置了必要的步骤吗?
然后rsp
总是移动到rbp
。 正如我所读到的,这将新的堆栈基础设置为当前函数的上下文。 我似乎无法弄清楚什么时候或如何将堆栈指针设置为该位置。 我最好的猜测是汇编函数调用这是否是最新发生的?
最后,当一个方法返回时,它看起来像eax
是用于父函数来利用其eax
返回的寄存器。 eax
是否明确用于此目的,或者这只是我的编译器和体系结构的约定?
父功能如何知道如何重建自己? Call和Ret内置了必要的步骤吗?
在调用函数之前,寄存器的当前状态以及返回地址被保存。 call
指令跳转到被调用函数开始的特定地址。 返回地址被压入堆栈。 当被调用的函数返回时, ret
指令会先弹出返回地址并前往该位置。
然后rsp总是移动到rbp
rbp先前被压入堆栈以便能够从调用者的函数恢复rbp的值。 然后,rsp被移动到rbp为被调用函数创建一个新的栈帧。 新的基址指针已经建立。 所以目前,rbp和rsp指向相同的地址。 如果有其他push
说明,esp会自动调整。 当函数完成时, pop ebp
指令恢复先前推入的堆栈基址指针地址。
按下并弹出修改堆栈指针 - SP
。
呼叫按下FLAGS - 状态寄存器以及RA - 返回地址。 Ret弹出FLAGS弹出窗口并跳转到返回地址。
正如rkhb所说,保留某些寄存器的必要性来自调用约定。
链接地址: http://www.djcxy.com/p/80379.html上一篇: How is the stack pointer changed in this program with call and ret