用call和ret指令 来解释高级语言是如何执行函数调用的

今天汇编语言学到了 call指令和ret 指令,然后解决了一直以来c/c++(高级语言)是如何执行递归的过程。

首先我们来看一个简单的样例:

C/C++ 程序

#include<iostream>
using namespace std;
void clac(int a,int b)
{
	int ans=a+b;
	cout<<a+b<<endl;
	return;
}
int main() {
   clac(2,3);
   return 0;
}

反汇编程序

Dump of assembler code for function main:
   0x0000000000401595 <+0>:     push   %rbp
   0x0000000000401596 <+1>:     mov    %rsp,%rbp
   0x0000000000401599 <+4>:     sub    $0x20,%rsp
   0x000000000040159d <+8>:     callq  0x401720 <__main>
   0x00000000004015a2 <+13>:    mov    $0x3,%edx
   0x00000000004015a7 <+18>:    mov    $0x2,%ecx
   0x00000000004015ac <+23>:    callq  0x401550 <_Z4clacii>
   0x00000000004015b1 <+28>:    mov    $0x0,%eax
   0x00000000004015b6 <+33>:    add    $0x20,%rsp
   0x00000000004015ba <+37>:    pop    %rbp
   0x00000000004015bb <+38>:    retq
End of assembler dump.

我们把每个语句的对应写下来

 0x000000000040159d <+8>:     callq  0x401720 <__main>  :int main
 
   0x00000000004015a2 <+13>:    mov    $0x3,%edx 
   0x00000000004015a7 <+18>:    mov    $0x2,%ecx
   0x00000000004015ac <+23>:    callq  0x401550 <_Z4clacii> : calc(2,3)
   0x00000000004015b1 <+28>:    mov    $0x0,%eax
   0x00000000004015b6 <+33>:    add    $0x20,%rsp
   0x00000000004015ba <+37>:    pop    %rbp
   0x00000000004015bb <+38>:    retq

我们现在只研究 calc(2,3) 函数的执行过程,首先 传入参数,汇编语言是把0x3,0x2这两个十六进制,存入dx寄存器,cx寄存器,然后callq 0x401550 <_Z4clacii> 这句的功能是 push 下一句的ip(假设x)入栈,jmp到 clac()函数的 ip(假设y) 地址,接下来执行clac()的函数的执行过程, mov $0x0,%eax,add $0x20,%rsp, pop %rbp,retq中间的加法步骤我们不用管,最后 一句retq,这句是修改当前的ip,当前的ip数据从栈中获取,修改后ip=x,此时我们cs:ip地址是clac()函数地址的下一条地址,此时函数调用完成工作。

心得体会:

由上方汇编语言的函数调用过程可以理解cpu的函数调用过程是如何实现的,从而可以理解递归的过程是如何实现的,不过是call 和 ret 的配合下不断的跳转,cs:ip,在跳转的过程中逐渐满足条件,让栈中的数据逐渐清空。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值