博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业
阅读量:6916 次
发布时间:2019-06-27

本文共 1860 字,大约阅读时间需要 6 分钟。

署名信息

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

C源码

这里为了防止重复,修改了部分源码

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

运行 gcc -S -o foo.s -m32 foo.c后,生成的汇编代码为:

g:    pushl   %ebp    movl    %esp, %ebp    movl    8(%ebp), %eax    addl    $99, %eax    popl    %ebp    retf:    pushl   %ebp    movl    %esp, %ebp    pushl   8(%ebp)    call    g    addl    $4, %esp    leave    retmain:    pushl   %ebp    movl    %esp, %ebp    pushl   $22    call    f    addl    $4, %esp    addl    $36, %eax    leave    ret

分析代码运行过程

首先进入main函数:

`pushl   %ebp, movl %esp, %ebp`两行代码,将ebp压入栈,  然后esp的值赋给ebp,这里esp的值先减4,ebp指向与esp相同的位置  以上指令相当于enter,进入了一个新的函数调用栈  将22压入栈(这里其实是定义接下来调用的f的形参int x,并赋值)  调用f,这里先保存eip(PC计数器)的值入栈,esp的值-4,然后将f的地址赋给eip

进入f函数:

执行enter的两条指令,进入新的函数调用栈(同上)  将ebp向前8个字节位置的值(main中压栈的22)压栈,esp-4  这里是定义g的形参并赋值  调用g,eip先压栈,然后eip变为g的地址

进入g函数:

首先执行enter的两条指令,进入新的调用栈(同上)  `movl   8(%ebp), %eax` 首先寻址,将f中压栈的数(也就是g的形参x),赋给eax  `addl   $99, %eax` eax中得值+99,对应C语句 x + 99  `popl   %ebp` 这里因为g中没有开辟新的栈空间(esp的值没有变化),所以这句和leave语句等价  执行完,这一句,ebp恢复到之前的值(f中得状态)  执行ret,其实是执行popl eip,将栈中保存的eip的值,赋给eip  此时ebp、esp和eip均恢复到调用f中得状态退出g,返回值保存在eax中

回到f函数:

`addl    $4, %esp`  esp+4,因为前面进行了pushl开辟新的变量,所以这里需要丢弃栈顶  之后执行leave 和 ret,恢复esp、ebp、eip的值,同上f仅仅返回g的返回值,这里不改动eax,里面保存着g的返回值

回到main函数:

`addl    $4, %esp`丢弃栈顶,原因是上面进行push,定义了新的变量  ` addl    $36, %eax` f(22)的返回值+36,相当于C中得 f(22) + 36main函数leave ret 返回上一层 gcc中应该为__libc_start_main,它可以接收到main的返回值,在eax中

注意点

1.C中的函数,是先定义形参并赋值,然后才进入该函数代码  2.函数调用中占用的栈空间,不仅仅包括局部变量,还包括22这种常量  3.每次函数调用,都执行enter,这条指令的效果相当于开辟了一个新的空栈  4.call调用函数时,eip保存的是call的下一条指令

博客截图

实验环境是在Ubuntu 14.10 32bit,在mac OS X上远程登录

080005124456292.png

对计算机工作流程的认识

图灵机可以执行某些特定操作 通用图灵机可以执行传给它的指令  现在计算机采用冯诺依曼体系结构,将程序和数据均存储在内存中,只需要程序员编写计算机可以识别的代码即可,计算机会将这些代码编译为可执行的指令。

转载于:https://www.cnblogs.com/inevermore/p/4321181.html

你可能感兴趣的文章
Shell 信号发送与捕捉
查看>>
Oracle RAC集群本地时间和远程时间不一致?
查看>>
/var/spool/clientmqueue下生成太多文件处理
查看>>
ASP.NET MVC 5 学习教程:添加控制器
查看>>
lintcode :Invert Binary Tree 翻转二叉树
查看>>
如何解决新浪微博返回结果中的中文编码问题
查看>>
判断URL是否支持断点续传?
查看>>
Visual paradigm软件介绍
查看>>
python 数据类型-字符串-对象和方法
查看>>
WebSocket 教程
查看>>
百度echarts可以做什么
查看>>
UltraEdit取消自动备份(.bak)
查看>>
城中村、小区WiFi覆盖方案
查看>>
QTableWidget控件总结
查看>>
软件项目的开发的时间视乎永远都不够用
查看>>
Vagrant (三) - 网络配置
查看>>
CentOS 7 编译安装 PHP 7
查看>>
分布式熔断降级平台aegis
查看>>
Java™ 教程(为什么要使用泛型?)
查看>>
常用的两个免费可以商用的cc0协议图片网站
查看>>