利用反汇编手段解析C语言函数

592 篇文章 8 订阅 ¥99.90 ¥299.90
165 篇文章 18 订阅
本文通过Visual C++6.0反汇编32位C程序,详细阐述函数调用过程,包括参数传递、地址跳转、局部变量分配、函数体执行和返回值处理。局部变量在EBP寄存器为基础的堆栈中分配,函数结束时通过堆栈平衡恢复状态。未初始化的局部变量可能会显示为特定的字符序列,有助于调试。
摘要由CSDN通过智能技术生成

利用反汇编手段解析C语言函数

 

通过在 Visual C++6.0 下反汇编一个 32 位 C语言程序的部分代码来解析解释函数调用的具体过程。

函数调用过程
函数调用过程主要由参数传递、地址跳转、局部变量分配和赋初值、执行函数体,结果返回等几个步骤组成。

参数传递及函数跳转
参数由实参传递给形参。在底层实现上,即是实参按照函数调用规定压入堆栈。参数传递完成后就通过CALL指令由当前程序跳转到子程序处。

局部变量分配并赋值
函 数的“{”被认为是分配局部变量空间的时机。在汇编层面局部变量分配体现为堆栈中以 EBP 寄存器为基址向低地址端分配的一个连续区域,通过 EBP 寄存器的相对寻址方式来寻址函数内的局部变量。由于堆栈增长的方向是高地址端到低地址端,因此函数中先定义的局部变量地址较大,后定义的变量地址逐渐变小,相邻定义的变量其地址一定相邻。由于全局数据和局部数据定义在不用的数据区而并不与局部变量相邻,根据程序局部性原理,相邻的数据会被缓存,因此对相同的运算,局部变量作为操作数的运算效率就可能高于有全局变量参与的运算。同时,局部变量分配和回收只需要移动堆栈指针ESP,因此效率最高。

寻址函数的参数
参数存放在以 EBP 为基址的高地址端。对参数的访问同样是通过EBP 寄存器相对寻址操作来实现。

执行函数体内的语句
函数内和具体功能相关的语句被转化成一系列汇编语句。

返回值
return 语句将返回值返回到主调函数。在底层,参数是通过 EAX 寄存器或 EDX 寄存器传递给主调函数。

返回主调函数
函数的“}”被解释为函数体已经执行完。遇到“}”时,会将堆栈中的局部变量、程序中压入堆栈的寄存器的值全部弹出,将之前 CALL指令执行时压入堆栈的函数返回地址弹到指令指针寄存器 EIP,从而返回到主调函数。

堆栈平衡
堆栈平衡指的是将函数调用前压入堆栈的参数弹出堆栈,使堆栈恢复到其调用前的状态。由于函数调用完成后,参数就是无用的数据了,因此需要将其移出堆栈。
在 C语言中不需要进行堆栈平衡。而在汇编层面上却根据调用约定来确定由主调函数或是被调函数完成堆栈平衡。

 

栈帧

参数由主调函数压入堆栈,CALL 指令将函数返回地址入栈。进入子函数后,需要保存 EBP 原值、分配局部变量空间、保存寄存器初始值。函数内通过“EBP-位移量”方式访问局部变量,通过“EBP+位移量”方式访问参数。

每发生一次函数调用,就会在堆栈中建立一个栈帧,栈帧在函数调用后释放。但是系统的堆栈资源有限,因此如果函数调用(如递归调用)层数过多,则可能发生堆栈溢出错误。

 

反汇编

从 Call 指令可见 fuction函数编译后加了“_”修饰符。

在函数内,遇到“{”时分配局部空间,并用值“0xCCH”进行初始化。未在定义时初始化的局部变量其初值就与“0xCCH”相关。因此 int 类型变量由于占四个字节,其初值为 - 858993460(0xCCCCC-CCCH);两个连续的 0xCCH 对应汉字“烫”字,因此当
以字符形式显示函数内未初始化的变量时会显示为“烫烫…”;指针类型变量就指向了地址为 0xCCCC-CCH 的内存。由此在调试模式下能很容易发现未初始化的变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值