C语言汇编--Hello word

转载代码:https://blog.csdn.net/tangyanzhi1111/article/details/8931611

参考链接:VC++6.0反汇编代码

今天写一个最初带我进入C语言的一个代码吧–Hello World代码。

#include "stdafx.h"

int main(int argc, char* argv[])
{
	printf("Hello World!\n");

	return 0;
}

如上,这个程序很简单,但是对于他其中蕴含的汇编代码却很少被关注到了。接下来让我们一起去看一下这个程序的反汇编吧!

//几个寄存器的含义
ebp:基址指针 esp:堆栈指针
eax:累加器 ebx:基址寄存器
ecx:计数寄存器 edx:数据寄存器
esi:源变址寄存器 edi:目的变址寄存器
eip:指令指针

_chkesp:用于检测堆栈平衡的函数,如果esp不等于函数调用前保存的值,就会转到错误处理代码。
int3:留给调试工具使用的中断,调试工具运行后会替换int3的向量。

参见:绕过 __chkesp()函数

首先,先来解释几个简单的语句吧。

push ebp
mov ebp, esp

push:把一个32位操作数压入栈中,执行完后,栈顶指针esp减4,ebp用来保存push执行后esp的值,执行完毕后,用ebp回复esp。同时,调用此函数上层函数也用ebp做同样的事情,先push入栈,返回之前弹出,避免ebp被我们改动。

xor eax, eax
ret

xor eax,eax常用来代替mov eax,0。清零操作。在windows中,函数返回值都是放在eax中然后返回,外部从eax中得到返回值。这就代表return 0操作。

lea edi, [ebp-40h]

lea取得第二个参数代表的地址放入第一个参数代表的寄存器中。

mov ecx, 10h
mov eax, 0CCCCCCCh
rep stos dword ptr es:[edi]

stos是串存储指令,它的功能是将eax中的数据放入 [edi] 所指的地址中,同时 [edi] 会增加4个字节。Rep使指令重复执行ecx中填写的次数。

由于CPU的寄存器有限,而且操作寄存器会影响标志值,push作用是压栈,pop是退栈。即保存寄存器标志的值和寄存器本身的值,以便在函数调用完毕后恢复原有的标志值。这也是为什么我们见到在调用某个函数或者运行一个程序时,入口总是push一堆寄存器的东东,返回函数再 pop 一堆寄存器,也就是这个原因。

如下,反汇编。

6:    int main(int argc, char* argv[])
7:    {
0040D6F0 55                   push        ebp
>>保存esp,返回之前弹出,避免ebp被我们改动,push操作使esp减小,esb不变
0040D6F1 8B EC                mov         ebp,esp
>>用来保存函数执行前的esp的值,执行完毕后,用ebp恢复esp,原ebp值已经被压栈(位于栈顶),而新的ebp又恰恰指向栈顶。此时ebp寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原ebp入栈后的栈顶),从该地址为基准,向上(栈底方向)能获取返回地址、参数值(假如main中有参数,“获取参数值“会比较容易理解);向下(栈顶方向)能获取函数局部变量值,而该地址又存储着上一层函数调用时ebp的值
0040D6F3 83 EC 40             sub         esp,40h
>>把esp向上移动一个范围,等于在栈中开辟一片空间存储main函数的局部变量;由于冯诺依曼机是小端模式,所以sub操作可以理解为将esp栈顶减去,实际上是为栈增加空间
0040D6F6 53                   push        ebx
0040D6F7 56                   push        esi
0040D6F8 57                   push        edi
>>保存三个寄存器的值,待main结束恢复,原来的值被破坏有可能引起系统崩溃
0040D6F9 8D 7D C0             lea         edi,[ebp-40h]
>>把ebp-040h加载到edi中,目的是保存局部变量的区域
0040D6FC B9 10 00 00 00       mov         ecx,10h
0040D701 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
0040D706 F3 AB                rep stos    dword ptr [edi]
>>从ebp-040h开始的局部变量空间区域加载初始化全部变成0CCCCCCCCh(也就是int 3中断指令的机器码);局部变量不可能被执行,执行了就会出错,这样发生意外时执行堆栈里面的内容会引发调试中断提示开发者return 0

8:        printf("Hello World!\n");
0040D708 68 1C 20 42 00       push        offset string "%d" (0042201c)
0040D70D E8 4E 39 FF FF       call        printf (00401060)
0040D712 83 C4 04             add         esp,4
9:
10:       return 0;
0040D715 33 C0                xor         eax,eax
>>返回值将放在eax返回(因为eax是可以更改的,所以这就是很多如阿健给藐视报批的原因)
11:   }
0040D717 5F                   pop         edi
0040D718 5E                   pop         esi
0040D719 5B                   pop         ebx
>>恢复原来寄存器的值,怎么push进去的,倒序pop出来
0040D71A 83 C4 40             add         esp,40h
>>将esp回到程序开始执行mov ebp, esp时的状态,相当于销毁函数最开始分配的用于保存局部变量的栈空间
0040D71D 3B EC                cmp         ebp,esp
>>比较ebp和esp的值,确定是否相等
0040D71F E8 BC 39 FF FF       call        __chkesp (004010e0)
>>调用__chkesp()函数,检查esp与函数之前实现开始时状态是否一致
0040D724 8B E5                mov         esp,ebp
>>由于调用__chkesp()函数后,esp的值发生了变化,因此需要mov恢复esp栈顶指针
0040D726 5D                   pop         ebp
>>恢复ebp,也就是恢复调用函数之前各个寄存器的状态
0040D727 C3                   ret
>>将返回地址存入eip,退出主函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值