谈谈全局变量、静态变量的初始化问题

时间:2021-09-13 19:37:57

经常性的在面试和笔记题目中会看到全局变量、静态全局变量、静态变量的存储位置和初始化时间的问题,

一般都能答出来他们存储位置,但可能有很多人不清楚这些变量是什么时候初始化的,下面我们从代码角度来看看,这些变量是什么时候初始化的,

如果在main函数之前初始化,那么又是如何做的。

samplecode定义如下:

MyClass g_A;
int g_nTest2 = 1;
int main()
{
return 0;
}

1.类对象初始化 先来看下那个g_A在什么时候初始化和调用构造函数 

在main之前还有另外一个函数:(w)mainCRTStartup需要调用(crt的main入口),代码如下:

int mainCRTStartup(void)
{
/*
* The /GS security cookie must be initialized before any exception
* handling targetting the current image is registered. No function
* using exception handling can be called in the current image until
* after __security_init_cookie has been called.
*/
__security_init_cookie();

return __tmainCRTStartup();
}

第一行security_init_cookie就是初始化缓冲区溢出检查的cookie值,这个cookie具体有什么用,可以看我另外一篇文章( http://blog.csdn.net/zhuobattle/article/details/17373521)

然后就是调用__tmainCRTStartup,

__tmainCRTStartup这个函数里会有如下代码来做C++初始化:

/*
* do C++ constructors (initializers) specific to this EXE
*/
if (__native_startup_state == __initializing)
{
_initterm( __xc_a, __xc_z );
__native_startup_state = __initialized;
}

调用完后,才会去调用main函数:

            mainret = main(argc, argv, envp);

g_A的构造函数就在_inititerm函数里去调用,具体有兴趣可以去看源码(X:\Program Files\Microsoft Visual Studio 8\VC\crt\src\crtexe.c)

2. 已初始化的 全局变量(静态变量) 那么有人会问,像如下的全局变量什么时候初始化呢:


int g_nTest2 = 1;

答案是这些已知类型的变量在PE文件中已经被硬编码了那个值,g_nTest2被硬编码成了1,

如果要证实可以用调试工具去看下那个地址的值是什么时候写入的。

用OD载入(第一次暂停记得选择在系统断点)为了方便,我选择了如下的测试代码:

int g_nTest2 = 0x001200FE;

void TestGolabal()
{
static int gA2 = 0x003400AB;
...
}

包括全局和静态变量,

系统断点下来,我们会看到,那个全局变量对应的地址早就被赋值了,如下图:

谈谈全局变量、静态变量的初始化问题

直接打开PE文件,我们也看到了如下的值:

谈谈全局变量、静态变量的初始化问题


3.未初始化全局变量

未初始化的全局变量gcc编译器中会分配一个 .bss section,在PE被加载时会根据PE header信息分配空间,

并初始化为0,但是VC编译器编译出来的并没有.bss节,未初始化的全局静态量也在.data段中


总结下,class等这些全局变量是在main函数之前,在__tmainCRTStartup里调用的构造函数进行初始化;

而像int等已知类型的已初始化全局变量和静态变量它的值已经写在PE文件里了,PE Loader加载时就已经写

入,未初始化的全局和静态变量则也是在PE加载时为其分配空间,并初始化成0.具体我们要看下PE加载逻辑了。

对于PE加载逻辑以后整理下。