函数调用与返回的相关指令

简介: 理解函数调用与返回的相关汇编指令及递归函数

如有以下code demo:

include

int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
int c = max(3,4);
return 0;
}
函数调用和返回会分别用到call和ret两个汇编指令。

8: int c = max(3,4);
00401088 push 4
0040108A push 3
0040108C call @ILT+0(max) (00401005)
00401091 add esp,8
00401094 mov dword ptr [ebp-4],eax
……………………………………………………………………………………
@ILT+0(?max@@YAHHH@Z):
00401005 jmp max (00401020)
……………………………………………………………………………………
2: int max(int a,int b)
3: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
4: return a>b?a:b;
00401038 mov eax,dword ptr [ebp+8]
0040103B cmp eax,dword ptr [ebp+0Ch]
0040103E jle max+28h (00401048)
00401040 mov ecx,dword ptr [ebp+8]
00401043 mov dword ptr [ebp-4],ecx
00401046 jmp max+2Eh (0040104e)
00401048 mov edx,dword ptr [ebp+0Ch]
0040104B mov dword ptr [ebp-4],edx
0040104E mov eax,dword ptr [ebp-4]
5: }
00401051 pop edi
00401052 pop esi
00401053 pop ebx
00401054 mov esp,ebp
00401056 pop ebp
00401057 ret
1 call addr
Switches active frame to callee function. Equivalent to:

push %eip // eip保存指令目标地址

mov addr, %eip
//代码效果参考:http://www.zidongmutanji.com/bxxx/27882.html

2 ret
Restores active frame to caller function. Equivalent to:

pop %eip

(每执行一个指令,都会更新%eip的值。)

3 push S
Pushes a copy of S onto the top of the stack. Equivalent to:

sub $4, %esp

mov S, (%esp)

4 pop D
Pops the top element off the stack and places it in location D. Equivalent to:

mov (%esp), D

add $4, %esp

(push、pop、call、ret都会更新%esp的值,也就是栈指针偏移。)

5 递归函数
先看一个while循环:

int sumDown(int n) { // iterative version
int total = 0;
int i = n;
while (i > 0) {
total += i;
i--;
}
return total;
}
两个汇编跳转指令构成一个while循环:

6: while (i > 0) { // iterative version
00401045 cmp dword ptr [ebp-8],0
00401049 jle sumDown+3Fh (0040105f) // 条件跳转至return前
7: total += i;
0040104B mov ecx,dword ptr [ebp-4]
0040104E add ecx,dword ptr [ebp-8]
00401051 mov dword ptr [ebp-4],ecx
8: i--;
00401054 mov edx,dword ptr [ebp-8]
00401057 sub edx,1
0040105A mov dword ptr [ebp-8],edx
9: }
0040105D jmp sumDown+25h (00401045) // 无跳转跳转回while语句:
10: return total;
0040105F mov eax,dword ptr [ebp-4]
11: }
将while改写为goto版本:

int sumIf(int n){ // goto version
int total = 0;
int i = n;
restart:
if(i<=0)
goto end;
total +=i;
i--;
goto restart;
end:
return total;
}
对应的汇编同样由几个跳转汇编指令构成:

6: restart:
7: if(i<=0)
00401095 cmp dword ptr [ebp-8],0
00401099 jg restart+8 (0040109d)
8: goto end;
0040109B jmp end+5 (004010b6)
9: total +=i;
0040109D mov ecx,dword ptr [ebp-4]
004010A0 add ecx,dword ptr [ebp-8]
004010A3 mov dword ptr [ebp-4],ecx
10: i--;
004010A6 mov edx,dword ptr [ebp-8]
004010A9 sub edx,1
004010AC mov dword ptr [ebp-8],edx
11: goto restart;
004010AF jmp restart (00401095)
12: end:
13: return total;
004010B1 mov eax,dword ptr [ebp-4]
004010B4 jmp end+7 (004010b8)
14: }
004010B6 jmp end (004010b1)
004010B8 pop edi
递归版本:

int sumr(int n) {
if (n <= 0) {
return 0;
}
return n + sumr(n-1);
}
对应的汇编:

13: int c = sumr(36);
0040D4C8 push 24h
0040D4CA call @ILT+35(sumr) (00401028) // call启动
………………………………………………………………………………
4: if (n <= 0) {
00401088 cmp dword ptr [ebp+8],0
0040108C jg sumr+22h (00401092)
5: return 0;
0040108E xor eax,eax
00401090 jmp sumr+36h (004010a6) // call 结束,ret 开始
6: }
7: return n + sumr(n-1); // 按条件call,且参数构成迭代:n = n-1
00401092 mov eax,dword ptr [ebp+8]
00401095 sub eax,1
00401098 push eax
00401099 call @ILT+30(sumDownIf) (00401023)
0040109E add esp,4
004010A1 mov ecx,dword ptr [ebp+8]
004010A4 add eax,ecx
8: }
004010A6 pop edi
004010A7 pop esi
004010A8 pop ebx
004010A9 add esp,40h
004010AC cmp ebp,esp
004010AE call __chkesp (004010c0)
004010B3 mov esp,ebp
004010B5 pop ebp
004010B6 ret // ret
迭代版本同goto版本一样,通过条件判断不断构成跳转,形成循环:

call……call……call…………ret……ret……ret…………

在不断的call中,参数可以构成迭代:n = n-1

在不断的ret中,返回结果存储在%eax寄存器(在非递归版本中使用临时变量total保存)。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
JavaScript
Element el-radio 单选框详解
本文目录 1. 用途 2. 单选框 3. 单选框样式 4. 单选框组 4. 单选框组样式 5. 尺寸调节 6. 绑定值变化事件 7. 小结
2198 0
Element el-radio 单选框详解
|
数据安全/隐私保护
BUUCTF 萌萌哒的八戒 1
BUUCTF 萌萌哒的八戒 1
510 0
|
4月前
|
传感器 监控 安全
RFID为战略物资提供安全保障
RFID技术通过全生命周期闭环管理,实现战略物资在生产、仓储、运输、分发各环节的防伪溯源、实时监控与权限管控,支持快速盘点、自动报警与数据加密,提升战备效率与安全保障,广泛应用于军事、能源等关键领域。
|
5月前
|
运维 监控 安全
为什么禁止使用 Executors 创建线程池?
Java并发中,`Executors`快捷方法易导致OOM或系统雪崩,因隐藏关键配置。阿里手册禁止其在生产使用。应显式创建`ThreadPoolExecutor`,设定核心参数与有界队列,结合Guava命名线程,提升系统稳定性与可维护性。
|
5月前
|
传感器 人工智能 算法
餐饮配送机器人核心技术解析与选型
餐饮行业面临“三高一低”困境,送餐机器人凭借高效配送、智能交互与数据能力,成为降本增效刚需。融合SLAM导航、预测避障、大模型交互与车规级底盘,实现厘米级定位、主动揽客与无感取餐。猎户星空、擎朗、普渡等品牌各具优势,推动餐厅数字化升级。
484 0
|
6月前
|
传感器 运维 算法
C语言实现酒店KTV声控DMX512灯光系统的节目选择
C语言实现酒店KTV声控DMX512灯光系统的节目选择
|
监控 关系型数据库 PostgreSQL
两阶段提交(2PC, Two-Phase Commit)
【8月更文挑战第24天】
1056 9
|
Java
如何将OffsetDateTime转换为字符串格式的日期
【10月更文挑战第30天】如何将OffsetDateTime转换为字符串格式的日期
524 0
|
数据采集 Prometheus Cloud Native
架构革新:揭示卓越性能与高可扩展的共赢秘诀
为了构建现代化的可观测数据采集器LoongCollector,iLogtail启动架构通用化升级,旨在提供高可靠、高可扩展和高性能的实时数据采集和计算服务。然而,通用化的过程总会伴随性能劣化,本文重点介绍LoongCollector的性能优化之路,并对通用化和高性能之间的平衡给出见解。
架构革新:揭示卓越性能与高可扩展的共赢秘诀
|
算法 程序员 开发工具
C语言编程规范
C 语言编程规范有助于提升代码的可读性、可维护性和可移植性。主要包括:命名规范(如 `my_variable`、`MAX_SIZE`)、代码缩进与空格、注释(解释逻辑但不过度)、函数设计(短小精悍、参数不超过三个)、错误处理、避免魔法数字、选择合适数据结构、使用标准库、保持代码格式一致及版本控制。遵循这些规范能显著提高团队开发效率和代码质量。
1901 2

热门文章

最新文章