Visual C++ 2015 /GL(整个程序优化)和/OPT:REF(优化引用)防止调用静态初始值设定项
Visual C++ 2015 /GL (whole program optimization) and /OPT:REF (optimize references) prevent static initializers being called
简介: C++中的全局静态对象在main()
启动前初始化。考虑:
#include <stdio.h>
int calc_it() {
return 1;
}
int glob = calc_it();
int main() {
printf("glob = %d\n", glob);
return 0;
}
输出是glob = 1
,因为calc_it()
和赋值是在main()
开始之前执行的。代码顺序与此无关
现在想象一下,您有多个包含这样代码的源文件,并且进一步想象它们以某种方式相互依赖(无论出于何种原因,您都需要某种执行顺序。让我们先不讨论这是好设计还是坏设计.)
标准未定义执行顺序,但在 Visual C++ 中存在对它们施加特定顺序的方法。对于global static objects,可以在object定义前使用#pragma init_seg(SECTIONNAME)
指定某个section name。
但最后这只会导致编译器将 (__cdecl *)(void)
指针指向某些链接器部分中的函数(它们都以 .CRT$XC
开头)。
在链接器确定内存布局之前,节名称按字典顺序排序。默认的部分名称是 .CRT$XCU
。
C/C++ init代码然后将.CRT$XCA
和.CRT$XCZ
之间的这些段的内容视为指向函数的指针并逐一调用它们。
我们也可以使用 #pragma data_seg(SECTIONNAME)
指令手动完成此操作。所以这个:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#pragma data_seg(".CRT$XCM")
typedef void (__cdecl *atexit_func)(void);
atexit_func _init_ptr[] = { hi_there };
将输出:
hi there!
bye!
这有多好? :)
问题描述:
AFAIK,自 Visual C++ 2015 起,如果您将 /GL
选项(全程序优化)与 /OPT:REF
链接器选项(删除未使用的函数和数据)一起使用,这将不再有效。原因可能是从链接器的角度来看 _init_ptr
从未使用过。在旧的 Visual Studio 版本中,这仍然有效,因为他们从未删除未使用的 data,仅使用了 code.
问题:如何避免仅对单个交易品种出现这种情况?
Visual Studio 链接器可以选择包含某个符号,无论它是否被引用:/INCLUDE:symbol
。
Visual C++ 提供了一种将此链接器选项添加到已编译目标文件的方法:#pragma comment(linker, "/include:symbol")
。
即使使用 cl /O2 /GL x.cpp /link /OPT:REF
(即对于 x86,32 位)编译,以下代码也会 运行:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#pragma data_seg(".CRT$XCM")
typedef void (__cdecl *atexit_func)(void);
extern "C" atexit_func _init_ptr[] = { hi_there };
#pragma comment(linker, "/include:__init_ptr")
请注意 /include:
和 extern "C"
之后的前导额外下划线以防止名称混淆。
更新: 为了让代码也能编译为 x64,我们需要添加一些额外的东西:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#ifdef _M_X64
#define INCLUDE_SYM(s) comment(linker, "/include:" #s)
#else
#define INCLUDE_SYM(s) comment(linker, "/include:_" #s)
#endif
#pragma data_seg(".CRT$XCM")
#pragma section(".CRT$XCM", read)
typedef void (__cdecl *atexit_func)(void);
extern "C" atexit_func _init_ptr[] = { hi_there };
#pragma INCLUDE_SYM(_init_ptr)
简介: C++中的全局静态对象在main()
启动前初始化。考虑:
#include <stdio.h>
int calc_it() {
return 1;
}
int glob = calc_it();
int main() {
printf("glob = %d\n", glob);
return 0;
}
输出是glob = 1
,因为calc_it()
和赋值是在main()
开始之前执行的。代码顺序与此无关
现在想象一下,您有多个包含这样代码的源文件,并且进一步想象它们以某种方式相互依赖(无论出于何种原因,您都需要某种执行顺序。让我们先不讨论这是好设计还是坏设计.)
标准未定义执行顺序,但在 Visual C++ 中存在对它们施加特定顺序的方法。对于global static objects,可以在object定义前使用#pragma init_seg(SECTIONNAME)
指定某个section name。
但最后这只会导致编译器将 (__cdecl *)(void)
指针指向某些链接器部分中的函数(它们都以 .CRT$XC
开头)。
在链接器确定内存布局之前,节名称按字典顺序排序。默认的部分名称是 .CRT$XCU
。
C/C++ init代码然后将.CRT$XCA
和.CRT$XCZ
之间的这些段的内容视为指向函数的指针并逐一调用它们。
我们也可以使用 #pragma data_seg(SECTIONNAME)
指令手动完成此操作。所以这个:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#pragma data_seg(".CRT$XCM")
typedef void (__cdecl *atexit_func)(void);
atexit_func _init_ptr[] = { hi_there };
将输出:
hi there!
bye!
这有多好? :)
问题描述:
AFAIK,自 Visual C++ 2015 起,如果您将 /GL
选项(全程序优化)与 /OPT:REF
链接器选项(删除未使用的函数和数据)一起使用,这将不再有效。原因可能是从链接器的角度来看 _init_ptr
从未使用过。在旧的 Visual Studio 版本中,这仍然有效,因为他们从未删除未使用的 data,仅使用了 code.
问题:如何避免仅对单个交易品种出现这种情况?
Visual Studio 链接器可以选择包含某个符号,无论它是否被引用:/INCLUDE:symbol
。
Visual C++ 提供了一种将此链接器选项添加到已编译目标文件的方法:#pragma comment(linker, "/include:symbol")
。
即使使用 cl /O2 /GL x.cpp /link /OPT:REF
(即对于 x86,32 位)编译,以下代码也会 运行:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#pragma data_seg(".CRT$XCM")
typedef void (__cdecl *atexit_func)(void);
extern "C" atexit_func _init_ptr[] = { hi_there };
#pragma comment(linker, "/include:__init_ptr")
请注意 /include:
和 extern "C"
之后的前导额外下划线以防止名称混淆。
更新: 为了让代码也能编译为 x64,我们需要添加一些额外的东西:
#include <stdio.h>
void hi_there() {
printf("hi there!\n");
}
int main() {
printf("bye!\n");
return 0;
}
#ifdef _M_X64
#define INCLUDE_SYM(s) comment(linker, "/include:" #s)
#else
#define INCLUDE_SYM(s) comment(linker, "/include:_" #s)
#endif
#pragma data_seg(".CRT$XCM")
#pragma section(".CRT$XCM", read)
typedef void (__cdecl *atexit_func)(void);
extern "C" atexit_func _init_ptr[] = { hi_there };
#pragma INCLUDE_SYM(_init_ptr)