zoukankan      html  css  js  c++  java
  • 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的函数体为:

    add

    明显第一条指令是长度等于1。

    debug发现:pFunc != add !!,而在pFunc地址处的指令如下:

    jmp

    原来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,正确!

  • 相关阅读:
    SQL注入与防范
    JDCP连接池连接数据库报错:java.lang.AbstractMethodError: com.mysql.jdbc.Connection.isValid(I)Z
    数据库连接池(基于MySQL数据库)
    使用JDBC连接MySQL数据库的一个基本案例
    快速排序的java实现
    在C++的函数中如何指定一个数组,使得这个数组的大小由函数的输入值来决定
    WORD2010如何把全角字母和数字批量转换成半角
    地图安卓
    浅谈java异常[Exception]
    Adapter的getView
  • 原文地址:https://www.cnblogs.com/xylc/p/3503612.html
Copyright © 2011-2022 走看看