C++ glibc函数的GCC、-flto、-fno内置函数和自定义函数实现
我正在观察GCC标志C++ glibc函数的GCC、-flto、-fno内置函数和自定义函数实现,c++,c,gcc,compilation,linkage,C++,C,Gcc,Compilation,Linkage,我正在观察GCC标志-flto和jemalloc/tcmalloc的意外行为(至少我找不到解释)。一旦使用了-flto,并且我与上述库malloc/calloc和friends的链接没有被je/tc malloc实现所取代,就会调用glibc实现。一旦我删除-flto标志,一切都会按预期进行。我尝试将-fno-builtin/-fno-builtin-*与-flto一起使用,但它仍然没有选择je/tc malloc实现 -flto机器是如何工作的?为什么二进制文件不选择新的实现?当它在未解决的外
-flto
和jemalloc
/tcmalloc
的意外行为(至少我找不到解释)。一旦使用了-flto
,并且我与上述库malloc/calloc和friends的链接没有被je/tc malloc
实现所取代,就会调用glibc实现。一旦我删除-flto
标志,一切都会按预期进行。我尝试将-fno-builtin
/-fno-builtin-*
与-flto
一起使用,但它仍然没有选择je/tc malloc
实现
-flto
机器是如何工作的?为什么二进制文件不选择新的实现?当它在未解决的外部问题(例如,printf
)上出现故障时,它如何与-fno-builtin
链接
EDIT001:GCC 7.3
示例代码
int main()
{
auto p = malloc(1024);
free(p);
return 0;
}
#include <cstdlib>
int main()
{
auto p = malloc(1024);
if (p) {
free(p);
}
auto p1 = new int;
if (p1) {
delete p1;
}
auto p2 = new int[32];
if (p2) {
delete[] p2;
}
return 0;
}
编译:/usr/bin/c++-O2-g-DNDEBUG-flto-std=gnu++14-o CMakeFiles/flto.dir/main.cpp.o-c /home/user/Development/cppcrunk/flto/main.cpp 链接:
/usr/bin/c++-O2-g-DNDEBUG-flto-CMakeFiles/flto.dir/main.cpp.o -o flto-L/home/user/Development/jemalloc-Wl,-rpath,/home/user/Development/jemalloc-ljemalloc EDIT002:
更合适的示例代码
int main()
{
auto p = malloc(1024);
free(p);
return 0;
}
#include <cstdlib>
int main()
{
auto p = malloc(1024);
if (p) {
free(p);
}
auto p1 = new int;
if (p1) {
delete p1;
}
auto p2 = new int[32];
if (p2) {
delete[] p2;
}
return 0;
}
#包括
int main()
{
自动p=malloc(1024);
如果(p){
自由基(p);
}
自动p1=新整数;
如果(p1){
删除p1;
}
自动p2=新整数[32];
如果(p2){
删除[]p2;
}
返回0;
}
首先,您的示例代码是错误的。仔细阅读C11标准。当您想要使用标准的malloc
时,您应该#包括
在C++11(read)中,malloc
不受欢迎,不应使用(首选new
)。如果你还想在C++中使用,你应该<代码>包含< <代码>(在GCC中,它内部包括<代码> >
那么,你的样例代码几乎是C代码(一旦你用<代码> VoU**/COD>)替换<代码> Audio<代码>,而不是C++。根据规则,即使没有
-flto
,但只有-O3
,它也可以(一旦包含
)到空的main
。(我甚至写了一份公开报告,其中第§1.4.2节在几页中解释了优化是如何发生的)
为了优化malloc
和free
,GCC在malloc
的声明(内部
)中使用了一些\uuuu属性(malloc)
flto机器是如何工作的
LTO在中进行了解释。
它通过在“编译”和“链接”时使用代码的一些内部(-like和/或-like)表示来工作(实际上,链接步骤变成了另一个带有整个程序优化的编译,因此您的代码实际上会被“编译”两次)
在编译和链接时,LTO应始终(实际上)与一些优化标志一起使用(例如-O2
甚至-O3
)。因此,您应该编译并链接g++-flto-O2
(使用-flto
没有至少-O2
,没有实际意义,并且应该在编译和链接时使用完全相同的优化标志)
更准确地说,-flto
还将源代码的一些内部(-like)表示嵌入到目标文件中,并且也在“链接时”使用(尤其是在“链接”整个程序时,重复使用其框架时再次使用)。实际上,GCC包含了一些LTO前端和编译器,称为“代码> Lto1 < /Cube >(除了C++前端和编译器称为<代码> CcPulle)和<代码> LTO1(当您链接到<代码> G++-FLTO-O2/COD>)时,使用链接时间来重新处理这些GIMPLE表示。
可能,libjemalloc
有自己的头,并且可能有inline
(或inlineable)函数。然后,在从源代码编译该库时,还需要使用-flto-O2
(以便将其Gimple存储在库中)
最后,通常调用的malloc
独立于-flto
。这是一个链接器问题,而不是编译器问题。您可以尝试静态链接-ljemalloc
(然后您最好也使用gcc-flto-O2
构建该库;如果您不这样构建它,您将无法跨malloc
调用获得LTO优化)
您还可以将-v
传递给编译和链接命令,以了解g++
在做什么。您甚至可以通过-Wl,--verbose
请求ld
(由g++
启动)变得详细
请注意,LTO(及其使用的内部表示)是特定于编译器和版本的。内部(Gimple&)表示形式在&(在Clang中是非常不同的,所以当然不兼容)。动态链接器不知道LTO
另外,您可以安装libjemalloc dev
包,并在代码中添加#include
。另请参见手册页。可能可以配置或修补libjemalloc
,以定义一些je_malloc
符号作为malloc
的替代品。然后(对于LTO)在代码中使用je_malloc
(避免多个malloc
符号之间的冲突)会更简单。要了解更多关于共享库中符号的信息,请阅读Drepper的论文。当然,您应该期望LTO改变链接的行为 请你发一封邮件好吗?你没有提供足够的细节。您应该指定gcc版本、用于生成此命令行的命令行以及可以演示此行为的代码。@Groo您知道了吗?您是否也使用-flto
编译了libjemalloc
?没有。。。我应该吗?为什么?例如,我想我所有的boost
库都不是共同的