首先给出完整的C代码:

int g(int x)
{
return x+;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f()+;
}

使用命令:gcc –S –o hw001.s hw001.c -m32

对应生成的IA32汇编代码如图所示:

暂不分析以“.”开头的行,得到程序如下:

g:
pushl %ebp
movl %esp ,%ebp
movl (%ebp) ,%eax
addl $ ,%eax
popl %ebp
ret
f:
pushl %ebp
movl %esp ,%ebp
subl $ ,%esp
movl (%ebp) ,%eax
movl %eax ,(%esp)
call g
leave
ret
main:
pushl %ebp
movl %esp ,%ebp
subl $ ,%esp
movl $ ,(%esp)
call f
addl $ ,%eax
leave
ret

接下来逐行分析汇编代码,主要分析堆栈指针的变化情况:

1明确代码中用到的寄存器的默认功能
eax:储存函数返回值。
ebp:帧指针,储存堆栈的栈底位置
esp:栈指针,储存堆栈的栈顶位置
2假设main函数被调用之前,堆栈的栈底对应内存地址为100,栈顶对应内存地址为96,分别存放在ebp和esp内,并假设栈生长方向为内存的低字节方向。
3从main函数的入口“main:”开始,
  • pushl %ebp
等价于  subl  $4    ,%esp
             movl %ebp , %esp
将esp指向下一个空位置,并将当前栈底位置入栈 ,根据假设有,ebp值为100,esp = 92,
  • movl %esp ,%ebp
此时ebp = esp = 92
这两行代码会在每一个函数的起始部分出现,功能是将之前函数的堆栈压入栈底,在其上重新开辟一个新的堆栈,新栈的栈底在92。
  • subl $4 ,%esp
  • movl $8 ,(%esp)
这两行代码将8入栈,相当于pushl $8。此时esp为88。
  • call f
这行代码相当于
pushl %eip
movl  f,%eip   @此处的f应该为label f 的地址,即 函数f的入口地址
esp为84,接下来程序跳转到f:之后开始执行。
  • pushl %ebp
  • movl %esp ,%ebp
同上,此时有ebp = esp = 80。
  • subl $4 ,%esp
  • movl 8(%ebp) ,%eax
  • movl %eax ,(%esp)
这三行代码将内存地址88处的值8写入eax中。再把esp指向位置76的值写为8。
  • call g
这行代码相当于
pushl %eip
movl g,%eip   @此处的g应该为label g 的地址,即 函数f的入口地址。
esp为72,接下来程序跳转到g:之后开始执行。
  • pushl %ebp
  • movl %esp ,%ebp
同上,此时有ebp = esp = 68。
  • movl 8(%ebp) ,%eax
  • addl $11 ,%eax
将76位置的值写入eax,再把eax值加11,eax值为19
  • popl %ebp
把当前栈顶值出栈,写入ebp中。即把原ebp值80写回ebp,将esp+4,此时,ebp=80,esp=72。
  • ret
代码相当于popl %eip,即
movl (%esp)  ,%eip
addl  $4,         %esp
有esp = 76。
  • leave
返回到f中执行代码leave。leave相当于
movl %ebp,%esp
popl %ebp
此时ebp = 92,esp =84。
  • ret
代码相当于popl %eip,即
movl (%esp)  ,%eip
addl  $4,         %esp
此时ebp = 92,esp = 88。
  • addl $1 ,%eax
返回到main中继续执行,此时eax值为20
  • leave
相当于
movl %ebp,%esp
popl %ebp
此时ebp = 100,esp =96。
  • ret
代码相当于popl %eip,即
movl (%esp)  ,%eip
addl  $4,         %esp
程序返回到调用main的函数中继续执行。
堆栈内容如下表所示:

by昆仑雪狐

原创作品转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

简单C程序生成的汇编代码分析的更多相关文章

  1. 一个简单C程序的汇编代码分析

    几个重要的寄存器 eip - 用于存放当前所执行的指令地址 esp - 栈(顶)指针寄存器 ebp - 基址(栈底)指针寄存器 简单的C程序 int g(int x) { ; } int f(int ...

  2. 《Linux内核分析》week1作业-分析一个简单c语言的汇编代码

    1.C语言源码 #include <stdio.h> int g(int x){ ; } int f(int x){ return g(x); } int main(){ )+; } 2. ...

  3. start_kernel之前的汇编代码分析

    start_kernel之前的汇编代码分析 Boot中执行下面两句话之后,进入uclinux内核. theKernel = (void (*)(int, int, unsigned int))((ui ...

  4. STM32F103 ucLinux开发之二(内核启动汇编代码分析)

    start_kernel之前的汇编代码分析 Boot中执行下面两句话之后,进入uclinux内核. theKernel = (void (*)(int, int, unsigned int))((ui ...

  5. 分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业

    署名信息 郭春阳 原创作品转载请注明出处 :<Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 C源码 这 ...

  6. STM8S汇编代码分析

    转载:http://blog.csdn.net/u010093140/article/details/50021897使用STVD建立完汇编工程项目之后(具本建立方法可以看我的另一篇博文http:// ...

  7. 关于rt-thread调度器实现的底层代码分析

      本文使用了rt-thread自带的钩子函数和显示函数进行了实验,从rt-thread自带的延时函数rt_thread_delay()函数入手,对rt-thread系统的调度器进行分析.主要参考资料 ...

  8. 通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

    秦鼎涛  <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验一 通过汇编一个简单的C程序,分析汇编代码 ...

  9. 第一周:通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

    姓名:吕松鸿 学号:20135229 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

随机推荐

  1. Scala学习 —— 元组&映射

    再说集合之前,我们先来回顾一下映射&元祖 映射是键/值对偶的集合,Scala有一个通用的叫法--元组,也就是n个对象的聚集,并不一定要相同类型的.对偶不过是一个n=2的元祖.元祖对于那种需要将 ...

  2. Hibernate与MyBatis

    一. Hibernate与MyBatis Hibernate 是当前最流行的O/R mapping框架,它出身于sf.net,现在已经成为Jboss的一部分. Mybatis 是另外一种优秀的O/R ...

  3. ArcGIS Add-in插件开发从0到1及实际案例分享

    同学做毕设,要求我帮着写个ArcGIS插件,实现功能为:遍历所有图斑,提取相邻图斑的公共边长及其他属性(包括相邻图斑的ID),链接到属性表中.搞定后在这里做个记录.本文分两大部分: ArcGIS插件开 ...

  4. DW安装步骤

    Adobe Dreamweaver CC 2015破解步骤 Adobe Dreamweaver CC 2015的安装包和破解补丁可以在这里下载.链接: http://pan.baidu.com/s/1 ...

  5. 10.6 CCPC northeast

    1001 Minimum's Revenge 点的编号从 1 到 n ,u  v 的边权是 LCM(u,v) ,求这个图的最下生成树 搞成一颗以 1 为 根 的菊花树 ---------------- ...

  6. 在为ListView设置adapter时出错

    为listView设置adapter,代码如下: SimpleAdapter simpleAdapter = new SimpleAdapter(this, listItems, R.layout.m ...

  7. Sql Server xml 类型字段的增删改查

    1.定义表结构 在MSSM中新建数据库表CommunicateItem,定义其中一个字段ItemContentXml 为xml类型 2.编辑表数据,新增一行,发现xml类型不能通过设计器录入数据. 需 ...

  8. hadoop运行原理之Job运行(五) 任务调度

    接着上篇来说.hadoop首先调度辅助型task(job-cleanup task.task-cleanup task和job-setup task),这是由JobTracker来完成的:但对于计算型 ...

  9. 【PHP】分页条函数封装

    这两天在学习PHP 想做一个前端后台都包含的网站 看了一些视频发现大牛们都是将封装起来实现代码的重用性 本人技拙也写了个分页条函数的封装 分页条在用PHP网站开发中十分常用 通过封装代码来提高网站开发 ...

  10. 关于DMA和它的仇家

    [基础知识]什么叫做DMA?DMA=Direct Memory Access.这是一种通过硬件实现的数据传输机制.简单的说,就是不在CPU的参与下完成数据的传输.[/基础知识]不太明白?我举个简单的例 ...