VC++ 得到的函数地址与实际函数地址不一致的原因。
我想试验一个计算汇编指令长度的代码是否正确,因而写了如下code进行验证,但结果非常奇怪
#include <stdio.h>
#include <Windows.h> int add(int a,int b)
{
return a+b;
} extern ULONG GetOpCodeSize(PVOID Start); int main(int argc,char* argv[])
{
int c = add(1,2);
PVOID pFunc = (void*)add;
ULONG ulResult = GetOpCodeSize(pFunc);
return 0;
}
发现,返回的汇编指令长度等于5,然而,反汇编看到add的函数体为:
明显第一条指令是长度等于1。
debug发现:pFunc != add !!,而在pFunc地址处的指令如下:
原来VC++ debug模式下在调用函数之前需要通过一个中转,原因在于VC++的Incremental Link :
什么是Incremental Link Table呢?
假如一个程序有连续两个foo和bar (所谓连续,就是他们编译连接之后函数体连续存放), foo入口位置在0x0400,长度为0x200个字节,那么bar入口就应该在0x0600 = 0x0400+0x0200。程序员在开发的时候总是频繁的修改code然后build,假如程序员在foo里面增加了一些内容,现在foo函数体占 0x300个字节了,bar的入口也就只好往后移0x100变成了0x0700,这样就有一个问题,如果foo在程序中被调用了n次,那么linker不得不修改这n个函数调用点,虽然linker不嫌累,但是link时间长了,程序员会觉得不爽。所以MSVC在Debug版的build,不会让各个函数体之间这么紧凑,每个函数体后都有padding(全是汇编代码int 3,作用是引发中断,这样因为古怪原因运行到不该运行的padding部分,会发生异常),有了这些padding,就可以一定程度上缓解上面提到的问题,不过当函数增加内容太多超过padding,还是有问题,怎么办呢?MSVC在Debug build中用上了Incremental Link Table, ILT其实就是一串jmp语句,每个jmp语句对应一个函数,jmp的目的地就是函数的入口点,和没有ILT的区别是,现在对函数的调用不是直接call 到函数入口点了,而是call到ILT中对应的位置,而这个位置上什么也不做,直接jmp到函数中去。这样的好处是,当一个函数入口地址改变时,只要修改 ILT中对应值就搞定了,用不着修改每一个调用位置,用一个冗余的ITL把时间复杂度从O(n)将为O(1),值得,当然Debug版的二进制文件会稍大稍慢,Release版不会用上ILT。
最后disable Incremental Link 之后,结果是1,正确!
最新文章
- 软件工程线上课程(C语言实践篇)学习心得总结
- PHP基于websocket实时通信的实现—GoEasy
- Redis-cluster集群【第二篇】:redis持久化
- php 二维数组(没啥技术含量)
- 反射认识_02_反射成员变量Field
- php大力力 [002节]mac php环境安装,mamp安装 ,phpMyAdmin启动
- SQL SERVER 2008 R2 SP3 发布
- hdoj 5301 Buildings
- 20141109--SQL 练习题-1
- ORA-19809: 超出了恢复文件数的限制
- TDirectory.Delete 创建删除目录简单示例
- RSA加密算法正确性证明
- 【spoj LCS2】 Longest Common Substring II
- 同步文件的利器-rsync
- 标准IO:常用函数集合
- 修改CUSTOM.PLL文件调用客户化FORM&;修改标准FORM
- yii批量插入的方法
- 深入理解Fabric环境搭建的详细过程
- bootstrap 失效的原因
- MooFest POJ - 1990 (树状数组)
热门文章
- 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:3.安装Oracle RAC-3.2.安装 cvuqdisk 软件包
- fedora25安装和docker-ce_清华源
- Jenkins+Maven+Gitlab+Nexus持续集成环境搭建
- Redis使用记录
- __block 和__weak 区别及使用
- python--web项目
- vb调试dll
- 转:C#中Monitor对象与Lock关键字的区别分析
- 使用CSS3实现响应式标题全屏居中和站点前端性能
- atitit.跨语言实现备份mysql数据库&#160;为sql文件特性&#160;api&#160;兼容性java&#160;c#.net&#160;php&#160;js