递归函数的汇编表示

2024-06-13 02:08
文章标签 汇编 表示 递归函数

本文主要是介绍递归函数的汇编表示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写入程序test.c:

# include <stdio.h>
int fun(int n)
{
if (n==0)
return 0;
if(n==1)
return 1;
else
return n+fun(n-1);
}
int main()
{
fun(4);
return 0;
}

使用gcc –g test.c产生调试信息,使用gdb调试程序,反汇编后得到汇编代码(fun函数):

(gdb) disas fun
Dump of assembler code for function fun:0x004016b0 <+0>:     push   %ebp0x004016b1 <+1>:     mov    %esp,%ebp0x004016b3 <+3>:     sub    $0x18,%esp0x004016b6 <+6>:     cmpl   $0x0,0x8(%ebp)0x004016ba <+10>:    jne    0x4016c3 <fun+19>0x004016bc <+12>:    mov    $0x0,%eax0x004016c1 <+17>:    jmp    0x4016e3 <fun+51>0x004016c3 <+19>:    cmpl   $0x1,0x8(%ebp)0x004016c7 <+23>:    jne    0x4016d0 <fun+32>0x004016c9 <+25>:    mov    $0x1,%eax0x004016ce <+30>:    jmp    0x4016e3 <fun+51>0x004016d0 <+32>:    mov    0x8(%ebp),%eax0x004016d3 <+35>:    sub    $0x1,%eax0x004016d6 <+38>:    mov    %eax,(%esp)0x004016d9 <+41>:    call   0x4016b0 <fun>    //递归调用函数fun()0x004016de <+46>:    mov    0x8(%ebp),%edx0x004016e1 <+49>:    add    %edx,%eax0x004016e3 <+51>:    leave                    //函数调用结束0x004016e4 <+52>:    ret
End of assembler dump.

上面的汇编语句中,<+35>和<+38>行分别使得n减一和使得n-1入栈,然后继续递归调用函数fun(),直到遇到递归的终止条件,使用leave和ret语句返回。

递归调用的过程是:


设置断点,单步执行后,查看栈帧后可得

(gdb) bt

#0 fun (n=1) at test.c:6

#1 0x004016de in fun (n=2) at test.c:9

#2 0x004016de in fun (n=3) at test.c:9

#3 0x004016de in fun (n=4) at test.c:9

#4 0x004016ff in main () at test.c:13

 可见,fun函数每次递归调用,都会申请新的堆栈,如果递归调用的次数变多,执行的效率会降低很多。

继续单步执行,查看堆栈信息

#0  infun (n=2) at test.c:10

#1 0x004016de in fun (n=3) at test.c:9

#2 0x004016de in fun (n=4) at test.c:9

#3 0x004016ff in main () at test.c:13

f(1)的堆栈已经被释放

再次单步执行,堆栈信息为

#0  infun (n=3) at test.c:10

#2 0x004016de in fun (n=4) at test.c:9

#3 0x004016ff in main () at test.c:13

此时f(2)的堆栈已经被释放

再次单步执行,查看堆栈信息

#0  infun (n=4) at test.c:10

#3 0x004016ff in main () at test.c:13

f(3)的堆栈被释放

单步执行,堆栈信息为:

#0  mainat test.c:14

此时递归函数的调用已经结束


这篇关于递归函数的汇编表示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1055994

相关文章

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext),和uboot一样,都是从汇编阶段开始的,因为对于kernel而言,还没进行栈的维护,所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。         内核起始部分代码被解压代码调用,前面关于uboot的文章中有提到过(eg:zImage)。uboot启动是无条件的,只要代码的位置对,上电就工作,kern

汇编:嵌入式软件架构学习资源

成为嵌入式软件架构设计师需要掌握多方面的知识,包括嵌入式系统、实时操作系统、硬件接口、软件设计模式等。 以下是一些推荐的博客和网站,可以帮助你深入学习嵌入式软件架构设计: ### 1. **Embedded.com**    - **网址**: [Embedded.com](https://www.embedded.com/)    - **简介**: 这是一个专注于嵌入式系统设计的专业网

从计组中从重温C中浮点数表示及C程序翻译过程

目录 移码​编辑  传统浮点表示格式 浮点数的存储(ieee 754)->修炼内功 例子:   ​编辑 浮点数取的过程   C程序翻译过程 移码  传统浮点表示格式 浮点数的存储(ieee 754)->修炼内功 根据国际标准IEEE(电⽓和电⼦⼯程协会)  32位 例子:    64位    IEEE754对有效数字M和

GDB 查看汇编

查看汇编 x disassemble

C语言-程序环境 #预处理 #编译 #汇编 #链接 #执行环境

文章目录 前言 一、程序的环境翻译和执行环境 二、翻译环境 (一)、整体把握 (一)、编译 1、预处理(预编译) 2、编译 a、词法分析 b、语法分析 c、语义分析 d、符号汇总 3、汇编 (二)、链接 三、运行环境 总结​​​​​​​ 前言 路漫漫其修远兮,吾将上下而求索; PS:本文参考了《程序员的自我修养》,致敬大佬们! 一、程序的

C语言程序设计(算法的概念及其表示)

一、算法的概念 一个程序应包括两个方面的内容: 对数据的描述:数据结构 对操作的描述:算法 著名计算机科学家沃思提出一个公式: 数据结构 +算法 =程序 完整的程序设计应该是: 数据结构+算法+程序设计方法+语言工具 广义地说,为解决一个问题而采取的方法和步骤,就称为“算法”。 对同一个问题,可有不同的解题方法和步骤。为了有效地进行解题,不仅需要保证算法正确,还要考虑算

Linux 技巧汇编

10个重要的Linux ps命令实战 显示所有当前进程 根据用户过滤进程 通过cpu和内存使用来过滤进程 通过进程名和PID过滤 根据线程来过滤进程 树形显示进程 显示安全信息 格式化输出root用户(真实的或有效的UID)创建的进程 使用PS实时监控进程状态 https://linux.cn/article-4743-1.html Python 云服务器应用 | Http

正点原子阿尔法ARM开发板-IMX6ULL(二)——介绍情况以及汇编

文章目录 一、裸机开发(21个)二、嵌入式Linux驱动例程三、汇编3.1 处理器内部数据传输指令3.2 存储器访问指令3.3 压栈和出栈指令3.4 跳转指令3.5 算术运算指令3.6 逻辑运算指令 一、裸机开发(21个) 二、嵌入式Linux驱动例程 三、汇编 我们在进行嵌入式 Linux 开发的时候是绝对要掌握基本的 ARM 汇编,因为 Cortex-A 芯片一

javascript数组的字符串表示

var names=["aa","bb","hh"]; var namestr=names.join(); console.log(namestr); //后台运行的结果为      aa,bb,hh namestr=names.toString(); console.log(namestr); //后台运行的结果为      aa,bb,hh console.log(nam