C程序汇编运行模式简析

SJTUBEAR 原创作品转载请注明出处 /《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

1. 汇编

在修习LINUX内核这门课的初始阶段,首先需要掌握的就是汇编以及汇编程序对于堆栈的操作。

下面我们就来分析一下一个简单地C程序是如何被汇编程序所表达的!

2. 得到汇编代码

首先,我们写一个简单地C程序,命名为exp1.c:

 1 #include <stdio.h>
 2
 3 int g(int x)
 4 {
 5     return x+3;
 6 }
 7
 8 int f(x)
 9 {
10     return g(x);
11 }
12
13 int main()
14 {
15     return f(8)+1;
16 }

程序非常的简单,我们此时再通过编译指令将其编译为汇编程序:

1 gcc –S –o main.s main.c -m32

这样我们就得到了这个简单C程序的汇编代码:

 1     .file    "exp1.c"
 2     .text
 3     .globl    g
 4     .type    g, @function
 5 g:
 6 .LFB0:
 7     .cfi_startproc
 8     pushl    %ebp
 9     .cfi_def_cfa_offset 8
10     .cfi_offset 5, -8
11     movl    %esp, %ebp
12     .cfi_def_cfa_register 5
13     movl    8(%ebp), %eax
14     addl    $3, %eax
15     popl    %ebp
16     .cfi_def_cfa 4, 4
17     .cfi_restore 5
18     ret
19     .cfi_endproc
20 .LFE0:
21     .size    g, .-g
22     .globl    f
23     .type    f, @function
24 f:
25 .LFB1:
26     .cfi_startproc
27     pushl    %ebp
28     .cfi_def_cfa_offset 8
29     .cfi_offset 5, -8
30     movl    %esp, %ebp
31     .cfi_def_cfa_register 5
32     subl    $4, %esp
33     movl    8(%ebp), %eax
34     movl    %eax, (%esp)
35     call    g
36     leave
37     .cfi_restore 5
38     .cfi_def_cfa 4, 4
39     ret
40     .cfi_endproc
41 .LFE1:
42     .size    f, .-f
43     .globl    main
44     .type    main, @function
45 main:
46 .LFB2:
47     .cfi_startproc
48     pushl    %ebp
49     .cfi_def_cfa_offset 8
50     .cfi_offset 5, -8
51     movl    %esp, %ebp
52     .cfi_def_cfa_register 5
53     subl    $4, %esp
54     movl    $8, (%esp)
55     call    f
56     addl    $1, %eax
57     leave
58     .cfi_restore 5
59     .cfi_def_cfa 4, 4
60     ret
61     .cfi_endproc
62 .LFE2:
63     .size    main, .-main
64     .ident    "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
65     .section    .note.GNU-stack,"",@progbits

3.汇编代码分析

汇编出的代码,多了很多辅助信息,为了能够更好地看清主干,我们删减一下:

 1 g:
 2     pushl    %ebp            //保存现场,将父函数的栈底寄存器存入当前程序栈中
 3     movl    %esp, %ebp      //构建当前函数堆栈
 4     movl    8(%ebp), %eax   //从父函数堆栈中取得参数,存入ax寄存器
 5     addl    $3, %eax        //完成+3操作
 6     popl    %ebp            //恢复原父函数堆栈
 7     ret                     //pop出原EIP地址,恢复执行
 8 f:
 9     pushl    %ebp            //保存现场,将父函数的栈底寄存器存入当前程序栈中
10     movl    %esp, %ebp      //构建当前函数堆栈
11     subl    $4, %esp        //栈顶加一,用以储存变量传递给g函数
12     movl    8(%ebp), %eax   //取得参数
13     movl    %eax, (%esp)    //将参数传入变量位置
14     call    g               //调用g
15     leave                   //清楚局部变量空间
16     ret                     //返回
17 main:
18     pushl    %ebp
19     movl    %esp, %ebp
20     subl    $4, %esp        //空出局部变量空间
21     movl    $8, (%esp)      //为变量赋值
22     call    f               //调用f
23     addl    $1, %eax        //完成+1操作
24     leave                   //清理局部变量
25     ret                     //返回

我们对f函数进行详细的分析:

1. 首先进行enter指令:

此时,ebp当前所指向的位置存入栈顶,并且将ebp重定向指向esp:

2.栈顶加一并存入变量值:

3.调用g

4.从g返回后,返回值储存在AX寄存器中,不用操作,调用leave,清理变量

5.最后ret,同时EIP被读出恢复到原位置继续执行,返回值在AX中传递给调用函数

3.个人的一点感悟:

程序的调用就是这样嵌套的执行下去,每个函数都有自己的堆栈用以储存当前变量以及环境值,并通过将父函数的EBP放入栈底用以恢复环境。

同时EIP存入父栈栈顶,便于恢复到原节点处继续执行。

这样,就可以有规律的一直嵌套下去。

如果使用递归函数,就是一个码堆栈的过程,知道最顶部的堆栈返回,函数就像多米诺骨牌一样收回所有的堆栈。

这也是递归函数占用空间比较多的原因之一。如果没有很好地退出机制,有可能内存溢出。

时间: 2024-10-10 17:37:00

C程序汇编运行模式简析的相关文章

Hadoop-MR[会用]MR程序的运行模式

1.简介 现在很少用到使用MR计算框架来实现功能,通常的做法是使用hive等工具辅助完成.但是对于其底层MR的原理还是有必要做一些了解. 2.MR客户端程序实现套路 这一小节总结归纳编写mr客户端程序的一般流程和套路.将以wordcount为例子进行理解. 运行一个mr程序有三种模式,分别为:本地模式,本地集群模式,命令行集群模式 3.代码实现 import java.io.IOException; import org.apache.hadoop.conf.Configuration; imp

RAP开发入门-运行过程简析(三)

今天通过标准的RAP程序来简单分析下RAP的启动过程 1.新建一个标准的rap plugin-in 项目: 得到的项目结构大概如下: run confi..->..add bundle(配置好bundle 运行结果如下): 全屏控制代码: /** * Configures the initial size and appearance of a workbench window. * 配置初始大小和显示workbench的窗口样式 * -看来以后的主题应该在这里设置了 */ public cla

项目管理中PMC管理模式简析

一.了解PMC管理要点,充分发挥PMC的优势 PMC属于一种委托管理模式,在项目建设工作中应重点考虑如何发挥PMC管理的优势,为了能够在项目建设管理当中充分发挥PMC管理的优势: 1.技术优势 2.管理优势 3.人才优势 二.优化PMC管理内容,发挥项目管理团队在各阶段的管理优势,合理管理项目,确保PMC管理与业主管理实现有效衔接.互补,实现项目建设目标 天行健咨询认为采用合理的措施确保PMC管理与业主管理实现有效衔接.互补是工程建设管理的重要任务,应用PMC模式管理项目建设工作时,需要统筹执行

MR程序Debug调式或者运行模式

问题描述:在开发MR程序中会遇一些问题需要通过Debug调式,那么本文将介绍描述配置eclipse如何在Windows或者Linux下启动Debug调式. MR程序的Debug调式换言之就是MR程序的运行模式,MR程序有三种运行模式:本地模式(local).集群模式(cluster) Linux环境下: 1.本地模式:直接通过eclipse右键进行Debug即可 2.集群模式: 2.1.将hadoop的配置文件:core-site.xml/hdfs-site.xml/mapreduce-site

在vs 2015环境下,c语言和汇编混编操作简析(更新中......)

在VS 2015环境下如何混编. 在新建工程里也会发现了很多问题, 应用程序类型分为:windows应用程序,控制台应用程序,DLL,静态库 静态库: 静态库是指在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为"库"文件:在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中的这种库. 程序编译一般需经预处理.编译.汇编和链接几个步骤.静态库特点是可执行文件中包含了库代码的一份完整拷贝:缺点就是被多次使用就会有多份冗余拷贝. 静态库和动态库是两种共享程序

怎样判定应用程序自身运行在“兼容模式”下?

P.S.话说有很多天很多天没有写东东了啊,因为实在太忙了,还是恢复至少一个月两篇的状态吧. 我们的程序有时候需要精确的判定当前运行在哪个系统下面,也就是说程序的某个功能可能需要知道当前运行在哪个真正的操作系统下,而操作系统提供了一个兼容模式功能,就是用户可以设置某个程序运行在某个模拟的更低的版本的操作系统下面,这是有好处的,因为某些程序在某些更高版本的操作系统下面可能发生兼容性问题而无法运行.在设置兼容模式运行后,程序里面调用ring3层的GetVersionEx得到的将是模拟的的操作系统版本,

3 weekend110的job提交的逻辑及YARN框架的技术机制 + MR程序的几种提交运行模式

途径1: 途径2: 途径3: 成功! 由此,可以好好比较下,途径1和途径2 和途径3 的区别. 现在,来玩玩weekend110的joba提交的逻辑之源码跟踪 原来如此,weekend110的job提交的逻辑源码,停在这了 hello world hello tom helllo jim jim is a bad boy hello jack hello baby baby is my nvshen hello world hello tom helllo jim jim is a bad bo

最简单的基于FFMPEG的转码程序分析 +ffmpga代码简析(转 +总结)

模块:  libavcodec    - 编码解码器         libavdevice   - 输入输出设备的支持         libavfilter   - 视音频滤镜支持         libavformat   - 视音频等格式的解析         libavutil     - 工具库         libpostproc   - 后期效果处理         libswscale    - 图像颜色.尺寸转换 1. ffmpga代码简析 1.1 av_log() av_

MapReduce程序运行模式

本地运行模式: mapreduce程序是被提交给LocalJobRunner在本地以单进程的形式运行 而处理的数据及输出结果可以在本地文件系统,也可以在hdfs上 怎样实现本地运行?写一个程序,不要带集群的配置文件 本质是程序的conf中是否有mapreduce.framework.name=local以及yarn.resourcemanager.hostname参数 本地模式非常便于进行业务逻辑的debug,只要在eclipse中打断点即可 集群运行模式: 将mapreduce程序提交给yar