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

本文涉及的产品
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
公网NAT网关,每月750个小时 15CU
简介: 理解函数调用与返回的相关汇编指令及递归函数

如有以下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应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
高可用应用架构
欢迎来到“高可用应用架构”课程,本课程是“弹性计算Clouder系列认证“中的阶段四课程。本课程重点向您阐述了云服务器ECS的高可用部署方案,包含了弹性公网IP和负载均衡的概念及操作,通过本课程的学习您将了解在平时工作中,如何利用负载均衡和多台云服务器组建高可用应用架构,并通过弹性公网IP的方式对外提供稳定的互联网接入,使得您的网站更加稳定的同时可以接受更多人访问,掌握在阿里云上构建企业级大流量网站场景的方法。 学习完本课程后,您将能够: 理解高可用架构的含义并掌握基本实现方法 理解弹性公网IP的概念、功能以及应用场景 理解负载均衡的概念、功能以及应用场景 掌握网站高并发时如何处理的基本思路 完成多台Web服务器的负载均衡,从而实现高可用、高并发流量架构
相关文章
|
1月前
|
C语言
C语言函数返回值详解
本文详细解析了C语言中函数返回值的概念与应用。从函数的基本定义入手,深入探讨了不同类型返回值的作用及意义,并提供了实用的编程示例,帮助读者更好地理解和使用函数返回值。通过本文,你将掌握如何有效利用返回值优化代码结构与功能实现。
|
1月前
|
Java 程序员 C++
【Python】链式、嵌套调用、递归、函数栈帧、参数默认值和关键字参数
【Python】链式、嵌套调用、递归、函数栈帧、参数默认值和关键字参数
22 0
【Python】链式、嵌套调用、递归、函数栈帧、参数默认值和关键字参数
|
3月前
|
存储 Java Spring
@Around 可以获取程序执行后的返回值吗
【8月更文挑战第13天】@Around 可以获取程序执行后的返回值吗
121 2
|
3月前
|
存储
hyengine 寄存器问题之传递参数和接收返回值如何解决
hyengine 寄存器问题之传递参数和接收返回值如何解决
|
6月前
理解汇编中的CALL指令和参数传递
理解汇编中的CALL指令和参数传递
299 1
|
6月前
|
存储 Python 容器
python函数的返回值、嵌套方式以及函数中的变量(一)
python函数的返回值、嵌套方式以及函数中的变量(一)
239 2
|
6月前
|
Python
python函数的返回值、嵌套方式以及函数中的变量(二)
python函数的返回值、嵌套方式以及函数中的变量(二)
243 1
|
6月前
|
存储 Serverless Python
函数调用的形式
在编程中,函数调用是一种基本且重要的操作,它允许我们执行预定义的代码块,并可能返回结果。函数调用有多种形式,每种形式都有其特定的用途和优势。本文将探讨函数调用的一些常见形式,并附上相应的代码示例。
64 1
|
6月前
|
存储 C语言
C语言函数的返回值
C语言函数的返回值
60 0