c++混合使用不同标准编译潜在的问题
2020-12-13 06:00
标签:output 概念 字符串 执行 其它 结果 contain temp 静态库 最近项目使用的C++的版本到C++11了,但是由于有些静态库(.a)没有源码,因此链接时还在使用非C++11版本的库文件。目前跑了几天,似乎是没出什么问题,但是我还是想说一下这样做有哪些潜在的风险。 首先需要说明的是,升级到C++11之后,部分std的数据结构的内存布局有可能发生改变(待考究)。最开始,我认为只要静态库暴露出来的接口没有使用这些不兼容的数据结构即可。也就是说,如果静态库暴露的所有接口都是纯C风格的,没有使用任何C++ std的数据结构,则链接这种静态库应该是安全的。但是后来发现似乎并不是这样... 来看看C++消除重复代码的机制 假设有一个模板类MyClass Linux GCC通过ELF的COMDAT section来实现消除重复的模板代码。COMDAT是一种特殊的section(ELF和COFF都有COMDAT section的概念),通常它会关联一个字符串(也可能就是section的名字)。链接器在处理object file时,对遇到的同名的section会执行去重操作,保证在输出的output file中仅存在一份实例。 看看下面的代码 上述代码定义了模板类MyClass 可以看到,在x.cpp中没有定义宏TEST,而在y.cpp中定义了宏TEST。因此这两个编译单元看到的MyClass objdump -S x.o 看到成员函数func1的代码是这样的: objdump -S y.o 看到成员函数func1的代码是这样的: 看上述生成的汇编代码可知,MyClass 主函数代码如下: 运行程序,发现结果如下: 虽然我们在x.cpp和y.cpp都是对i1赋值为1,对i2赋值为2。但是却出现了一个i1值为2,i2值为1的结果。 objdump -S a.out 发现func1的代码如下: 可以发现,到了可执行程序中确实仅有一份MyClass 改变一下链接顺序,这次我们让链接器先处理y.o再处理x.o。再次运行程序,结果如下: 这次变成x.cpp中输出是错的,y.cpp中输出是对的了。 从上述例子可知:链接器在对COMDAT section去重时,并没有辨别section的内容是否一致。因此在不同的object file中内存布局不一致的C++模板被链接到一起是有潜在的风险的。静态库(.a)文件实际上是单纯的object file集合再加上一个符号表,因此链接静态库(.a)文件情况和链接object file是一样的。而动态库(.so)的情况可能稍有不同。 因此剩下的问题就是,使用不同C++标准去编译std的数据结构会生成同名COMDAT section吗? 以vector 发现为vector 还有一些问题尚未解决,这里记录一下: (1)不同C++版本编译对mangling的影响?对生成COMDAT section的影响? (2)动态库(.so)是否也存在这种问题?对动态库不同的使用方式会有影响?比如进程运行时链接和通过dlopen方式是否会不同? 参考资料: (1)https://forum.osdev.org/viewtopic.php?f=13&t=28618 (2)https://www.airs.com/blog/archives/52 c++混合使用不同标准编译潜在的问题 标签:output 概念 字符串 执行 其它 结果 contain temp 静态库 原文地址:https://www.cnblogs.com/adinosaur/p/11161081.html// my_template.h
template
// x.cpp
#include
0000000000000000 <_zn7myclassiie5func1ev>:
template
0000000000000000 <_zn7myclassiie5func1ev>:
template
void func_in_x();
void func_in_y();
int main()
{
func_in_x();
func_in_y();
return 0;
}
$ ./a.out
i1=1, i2=2
i1=2, i2=1
0000000000000712 <_zn7myclassiie5func1ev>:
template
$ g++ y.o x.o main.o
$ ./a.out
i1=2, i2=1
i1=1, i2=2
$ g++ -std=c++98 x.cpp -c
$ readelf -g x.o | grep push_back
COMDAT group section [ 4] `.group‘ [_ZNSt6vectorIiSaIiEE9push_backERKi] contains 2 sections:
[ 64] .text._ZNSt6vectorIiSaIiEE9push_backERKi
[ 65] .rela.text._ZNSt6vectorIiSaIiEE9push_backERKi
$ g++ -std=c++11 x.cpp -c
$ readelf -g x.o | grep push_back
COMDAT group section [ 5] `.group‘ [_ZNSt6vectorIiSaIiEE9push_backEOi] contains 2 sections:
[ 72] .text._ZNSt6vectorIiSaIiEE9push_backEOi
[ 73] .rela.text._ZNSt6vectorIiSaIiEE9push_backEOi