Re: 全局变量用导入函数初始化的问题!
Windows内核调试
全局变量用导入函数初始化的问题!
zyq8709
2011-06-15, 21:36 下午
代码:
typedef void (*F)();
extern void f();
F d=f;
void main()
{
F l=f;
}
其中void f()为一个普通dll导出的函数。
1、请问d的值在编译时如何计算并确定,即在该程序载入之前的静态值是如何计算出来的?
2、l的值经过我的观察并非初始化为导入表中的相对应的地址,而是赋给了0x00000001类似的值,并在载入时进行修改。这是怎么的一个过程?是重定位吗?但是又不对应PE文件中重定位表中表项的定义?请问这到底是怎样的一个过程?
Re: 全局变量用导入函数初始化的问题!
wrong
2011-06-16, 09:46 上午
这个问题比较复杂。分解来看,
1. 全局变量初始化的问题,你可以参考 http://user.qzone.qq.com/31731705/blog/1302767807
2. 导入函数的问题,f的值不是编译时确定的,是在link时,最终的值应该是PE在load时,你可以参考 http://user.qzone.qq.com/31731705/blog/1306146001
Re: 全局变量用导入函数初始化的问题!
zyq8709
2011-06-16, 10:57 上午
你给出的答案我都知道,比较简略。
详细的说一下我的疑问,牵扯到编译连接和载入的详细过程。
关于全局变量初始化的问题:
已初始化的全局变量是放在.data段中的,以汇编的方式就是 变量 dd 数值,那么一般的如果类似于int a=0;
那么就是 a dd 0h,那么关键这是一个导入函数,准确说f的值是本PE文件导入段中的一个函数指针,汇编的形式就是一个存储空间类似于[XXXXXXXX],那么编译器在编译时如何处理呢,根据汇编的规则是不可能出现这样的形式的:d dd [XXXXXXXX],因为dd就是起到将数值直接放入二进制文件中的,不可能放入一个地址,那么问题就是dd后的数值应该是多少呢,编译时是如何确定的呢,因为真正的值是在载入时才确定的,那么编译时静态确定下来的只是如何计算的?我看了输出的汇编是
d dd f,那这个f到底是多少?
关于局部变量的赋值:
按理说它的汇编应是:
mov eax,[f导入表对应地址]
mov l,eax
那为何我看到的汇编代码却是:
mov l,00000000h
而这个00000000h在载入时被修改为真实地址,这个过程是怎样进行的呢?
它又不符合PE文件的重定位过程呀?
Re: 全局变量用导入函数初始化的问题!
wrong
2011-06-17, 10:37 上午
你可以贴出代码包括汇编来看看。
你还可以再仔细看看我给的链接,关于全局变量,
1. C和C++的初始化过程是不同的。
2. void f();和__declspec(dllimport) void f();也是不一样的。
Re: 全局变量用导入函数初始化的问题!
zyq8709
2011-06-17, 11:32 上午
我又研究了一下解决了,关键就是用了extern而不是_declspec(dllimport),用extern是连接的是exe中的存根函数,而非直接引用导入表。而那个0x00000000只是vc给出的汇编列表,但在我看pe文件的二进制时发现其实编译的结果就是存根函数地址,这个地址在重定位时可改变。而用_declspec(dllimport)时,全局变量的初始化时实际上是在启动函数调用了一个类似与构造函数来初始化的,这个函数由编译器自动生成。