简单c语言汇编后代码解释(1)
来源:互联网 发布:mac引导修复工具 编辑:程序博客网 时间:2024/05/29 11:21
今天我们来以一个简单的案例来解释c语言对应汇编语言的关系
#include "stdio.h"long add(long a, long b){ long x = a, y = b; return (x + y);}int main(int argc, char* argv[]){ long a = 1, b = 2; printf("%d\n", add(a, b)); return 0;}
编译之后反汇编的代码如下 我们来逐一分析,需要注意我们这里是直接跳过了编译器附加的启动函数 来到了我们自己写的main函数
CPU DisasmAddress Hex dump Command Comments004010A0 /$ 55 PUSH EBP ; INT StackFrame.main(argc,argv)004010A1 |. 8BEC MOV EBP,ESP004010A3 |. 83EC 08 SUB ESP,8004010A6 |. C745 F8 01000 MOV DWORD PTR SS:[LOCAL.2],1004010AD |. C745 FC 02000 MOV DWORD PTR SS:[LOCAL.1],2004010B4 |. 8B45 FC MOV EAX,DWORD PTR SS:[LOCAL.1]004010B7 |. 50 PUSH EAX ; /b => 2004010B8 |. 8B4D F8 MOV ECX,DWORD PTR SS:[LOCAL.2] ; |004010BB |. 51 PUSH ECX ; |a => 1004010BC |. E8 BFFFFFFF CALL add ; \add004010C1 |. 83C4 08 ADD ESP,8004010C4 |. 50 PUSH EAX004010C5 |. 68 48644100 PUSH OFFSET 00416448 ; /_Format = "%d"004010CA |. E8 71FFFFFF CALL printf ; \printf004010CF |. 83C4 08 ADD ESP,8004010D2 |. 33C0 XOR EAX,EAX004010D4 |. 8BE5 MOV ESP,EBP004010D6 |. 5D POP EBP004010D7 \. C3 RETN
首先是前三句以及最后的三句 ,这六句在每次进入一个函数时都会出现
PUSH EBPMOV EBP,ESPSUB ESP,8***********省略********MOV ESP,EBPPOP EBPRETN
push ebp pop ebp这一对是因为该函数中需要用到ebp寄存器,所以需要先把他原来的值压栈保护起来,等到该函数执行完毕时再返回
除了ebp之外,如果函数内还有用到其他寄存器比如eax ebx 也会出现类似的
开头先push eax 最后 pop eax 弹出eax
那么既然函数里需要用到ebp,那么ebp到底有什么用呢?
ebp其实是一个局部变量的基地址
我们可以看到
push ebp之后执行了一句mov ebp,esp
而esp是栈指针,所以此时ebp也指向了栈指针,而整个函数的局部变量,也是全部保存在栈中的,所以ebp其实是为了方便指向局部变量的一个寄存器
因为ebp的值在整个函数中都不会改变,所以此时引用栈中的局部变量就十分轻松。
接下来 sub esp,8是为了给局部变量留出空间
即ebp和esp之间存放局部变量
接下来
004010A6 |. C745 F8 01000 MOV DWORD PTR SS:[LOCAL.2],1004010AD |. C745 FC 02000 MOV DWORD PTR SS:[LOCAL.1],2
就对应c语言中的 long a = 1, b = 2;
local.2 local.1即为ebp-8 ebp-4
然后紧跟的 下面四句
004010B4 |. 8B45 FC MOV EAX,DWORD PTR SS:[LOCAL.1]004010B7 |. 50 PUSH EAX ; /b => 2004010B8 |. 8B4D F8 MOV ECX,DWORD PTR SS:[LOCAL.2] ; |004010BB |. 51 PUSH ECX ; |a => 1
这四句 即为传递参数给函数 首先先把两个局部变量分别放到eax ecx,然后再Push到栈中,为什么不能直接push到栈中而用寄存器中转呢,很简单,因为x86cpu只支持这样的指令
接下来就是调用add方法了 然后我们进入add方法内部看一看
004010BC |. E8 BFFFFFFF CALL add ; \add
我们可以注意到 之前所说的那6句又重复出现了 这种调用可以无限嵌套下去直到爆栈
CPU DisasmAddress Hex dump Command Comments00401080 /$ 55 PUSH EBP ; INT StackFrame.add(a,b)00401081 |. 8BEC MOV EBP,ESP00401083 |. 83EC 08 SUB ESP,800401086 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]00401089 |. 8945 FC MOV DWORD PTR SS:[LOCAL.1],EAX0040108C |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2]0040108F |. 894D F8 MOV DWORD PTR SS:[LOCAL.2],ECX00401092 |. 8B45 FC MOV EAX,DWORD PTR SS:[LOCAL.1]00401095 |. 0345 F8 ADD EAX,DWORD PTR SS:[LOCAL.2]00401098 |. 8BE5 MOV ESP,EBP0040109A |. 5D POP EBP0040109B \. C3 RETN
add方法没什么好解释的,和上面一样 下面四句对应c语言中的 long x = a, y = b; 即把形参分别赋值给局部变量 形参是之前已经压栈进来的 所以去栈对应的位置取就行
00401086 |. 8B45 08 MOV EAX,DWORD PTR SS:[ARG.1]00401089 |. 8945 FC MOV DWORD PTR SS:[LOCAL.1],EAX0040108C |. 8B4D 0C MOV ECX,DWORD PTR SS:[ARG.2]0040108F |. 894D F8 MOV DWORD PTR SS:[LOCAL.2],ECX
下面两句完成了实际的加法功能,首先把局部变量放入寄存器中,然后再用寄存器做加法,为什么不能直接对两个内存单元做加法呢?和上面一样,不支持这种指令,
加法只能是先取内存单元到寄存器中,再对寄存器做加法
0401092 |. 8B45 FC MOV EAX,DWORD PTR SS:[LOCAL.1]00401095 |. 0345 F8 ADD EAX,DWORD PTR SS:[LOCAL.2]
接下来三句之前解释过了,不过这里注意一个细节,就是加法完成后结果值保存在了eax中,这是一个默认的返回值寄存器,即调用方法后结果值默认保存在eax中
不过对于有多返回值的语言比如lua,就不太清楚会怎么样了
接下来返回到主函数中 然后紧跟着执行了一句
004010C1 |. 83C4 08 ADD ESP,8
这是什么意思呢?其实这是一种调用约定,因为我们之前调用函数时压入了两个参数,而函数调用完成后栈指针应该恢复到原来位置,而这种是一种调用者恢复栈指针的做法,也可以在函数里面恢复栈指针
接下来四句 还是同样 先进行压栈 然后call 返回之后进行清栈 printf函数内部我们就不深究了
004010C4 |. 50 PUSH EAX004010C5 |. 68 48644100 PUSH OFFSET 00416448 004010CA |. E8 71FFFFFF CALL printf 004010CF |. 83C4 08 ADD ESP,8
最后一句值得注意的就是这个了,前面说过 eax是默认存放返回值的一个寄存器,而我们的main函数其实是由别的启动函数调用的 所以我们要返回值给他
return 0就表示程序正常结束
004010D2 |. 33C0 XOR EAX,EAX
然后就是还原esp 返回到启动函数了
- 简单c语言汇编后代码解释(1)
- 最简单的C语言工程,汇编代码
- 简单到引导扇区汇编代码解释
- .bss段 .data段 C语言后汇编汇编查看代码
- c语言反汇编代码
- 识别c语言汇编代码
- 简单C语言程序的汇编分析1
- 用自己的语言解释一段简单的汇编
- 汇编-代码解释集合
- C语言的反汇编代码
- Keil中C语言汇编代码比较
- C语言中嵌入汇编代码
- C语言的反汇编代码
- 简单c程序汇编代码分析
- 汇编并分析一段简单C代码
- 反汇编一个简单的C程序,分析汇编代码
- C语言--简单小代码1
- c语言编写简单shell解释器
- strus中jsp:forward失效,404错误
- 实现一个简单的网页(缩略词表、文献来源链接、快速访问键列表)
- Filter(1)-过滤器的"Helloworld"
- LA4382&&hdu2973
- 什么是存储过程,存储过程的作用及好处
- 简单c语言汇编后代码解释(1)
- 顺序表的实现以及简单的 插入,删除,查找,输出操作
- 关于spring boot整合mybatis使用oracle数据库出现could not load:oracle.jdbc.driver.OracleDriver问题的终极解决方案
- python 获取文件下所有文件或目录os.walk()
- 虚拟机 VM tcsetattr fd1: input/output error解决方法
- poj1330 lca倍增算法模板
- myeclips安装svn插件的方法
- 经典排序算法--冒泡排序
- putty上执行后台运行命令失效