关于链接和可执行模块加载过程,我对C++中的变量初始化的实现有一些疑问.我主要关心的是全局变量和静态成员变量的动态初始化,其中初始化过程涉及代码的执行.我正在寻找解决Windows和Linux问题的答案.
我已经明白在静态初始化的情况下:
- 在编译期间将初始值放入其自己的部分
- 这些部分由OS模块加载器映射到内存中
- 通过应用DIR32类型重定位,为变量分配初始值的内存地址的位置
这是我的问题.
编译器将哪些信息放入与链接器要使用的全局变量的动态初始化相关的生成的目标文件中?请尽可能详细地了解相关部分和生成的符号.与非静态全局变量相比,静态成员变量有何不同?
链接器在链接过程中将哪些信息放入最终链接模块中,以便OS模块加载器能够正确初始化所有变量(包括动态初始化的全局/静态成员变量,这些变量使函数调用作为初始化的一部分)?
在动态变量初始化期间需要执行的函数如何映射到需要使用该代码初始化的特定变量?
加载可执行文件或动态链接模块时,如何执行变量的动态初始化?
与常规静态成员变量和函数的实现相比,C++ 11常量表达式(由constexpr说明符标记)的实现是否涉及任何特殊注意事项?
我有一个具体的例子,我希望答案可以在上述问题的框架内提及,因为我觉得有一个具体的例子来获取一个目标文件,识别相关的部分/符号以及这个特定的代码将如何链接和加载,以便可以执行静态变量的成功初始化将使答案更容易理解.此示例适用于使用MSVC作为编译器的Windows; 请提及gcc/linux的具体差异,无论它们存在于何处.
这是一个简单的C++代码示例,涉及一个常规变量和一个静态成员变量,根据我的理解需要在main之前由OS加载器动态初始化,因为它调用函数作为其初始化的一部分:
class Test
{
public:
static int testFunction()
{
return 10;
}
static int memberVar;
};
int Test::memberVar = Test::testFunction();
int foo()
{
return 5;
}
int var = foo();
int main(int argc, char* argv[])
{
var;
Test::memberVar;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里是MSVC使用在调试模式下编译的上述代码生成的目标文件的节和符号的转储(转储是使用llvm-readobj创建的,这是一个llvm/clang附带的实用程序):
File: Source.obj
Format: COFF-i386
Arch: i386
AddressSize: 32bit
Sections [
Section {
Number: 1
Name: .drectve (2E …Run Code Online (Sandbox Code Playgroud)