glibc函数的GCC、-flto、-fno内置和自定义函数实现
GCC, -flto, -fno-builtin and custom function implementation of glibc functions
我观察到GCC标志-flto
和jemalloc
/tcmalloc
的意外行为(至少我找不到解释)。一旦使用了-flto
,并且我与上面的库malloc/caloc链接,并且朋友没有被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;
}
编译:
/usr/bin/c++-O2-g-DNDEBUG-flto-std=gnu++14-oCMakeFiles/flto.dir/main.cpp.o-c/主页/用户/开发/CPPUnk/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/jemallac-ljemalloc
EDIT002:
更合适的样本代码
#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;
}
首先,您的示例代码是错误的。仔细阅读C11标准n1570。当您想要使用标准malloc
时,您应该使用#include <stdlib.h>
。
在C++11中(读作n3337),malloc
是不受欢迎的,不应该使用(更喜欢new
)。如果你仍然想在C++中使用std::malloc
,你应该使用#include <cstdlib>
(在GCC中,它在内部包括<stdlib.h>
)
那么您的示例代码几乎是C代码(一旦用void*
替换auto
),而不是C++。它可以优化(一旦包含<stdlib.h>
),甚至在没有-flto
但只有-O3
的情况下,根据假设规则,也可以优化为空的main
。(我甚至写了一份公开报告,bismon-chariot-doc.pdf,其中有一节§1.4.2,在几页中解释了优化是如何发生的)。
为了围绕malloc
和free
进行优化,GCC在malloc
的声明(<stdlib.h>
内部)中使用了一些__attribute__(malloc)
函数属性。
-flto机器是如何工作的?
LTO在GCC内部§25中进行了解释
它通过在"编译"answers"链接"时使用代码的一些内部(类似于GIMPLE和/或SSA)表示来工作(实际上,链接步骤变成了另一个具有整个程序优化的编译,因此您的代码在实践中会被"编译"两次)。
LTO总是应该(在实践中)在编译和链接时与一些优化标志(例如-O2
甚至-O3
)一起使用。因此,您应该编译并用g++ -flto -O2
链接(使用不带的-flto
至少-O2
是没有实际意义的,并且在编译和链接时应该使用完全相同的优化标志)。
更准确地说,-flto
还将源代码的一些内部(类似于GIMPLE)表示嵌入到对象文件中,并且也在"链接时"使用(尤其是在"链接"整个程序时,再次使用其GIMPLE进行优化和内联)。事实上,GCC包含一些LTO前端和名为lto1
的编译器(除了C++前端和称为cc1plus
的编译器),而lto1
(当您与g++ -flto -O2
链接时)在链接时用于重新处理这些GIMPLE表示。
libjemalloc
可能有自己的头,并且可能有inline
(或可内联)函数。然后,当从源代码编译该库时,您还需要使用-flto -O2
(以便其Gimple存储在库中)
最后,通常的malloc
被调用的事实是独立于-flto
的。这是一个链接器问题,而不是编译器问题。您可以尝试静态链接-ljemalloc
(然后最好也使用gcc -flto -O2
构建该库;如果不这样构建,就无法在malloc
调用中获得LTO优化)。
您还可以将-v
传递给编译和链接命令,以了解g++
的作用。您甚至可以通过-Wl,--verbose
来要求ld
(由g++
启动)冗长。
请注意,LTO(以及它正在使用的内部表示)是编译器和版本特定的。内部(Gimple&SSA)表示在GCC7&GCC 8(在Clang中,它与非常不同,因此当然不兼容)。动态链接器ld-linux(8)不知道LTO。
PS。您可以安装libjemalloc-dev
软件包并在代码中添加#include <jemalloc/jemalloc.h>
。另请参阅jemalloc(3)手册页。可能CCD_ 57可以被配置或修补以定义某个CCD_ 58符号作为CCD_ 59的替换。那么(对于LTO)在代码中使用je_malloc
会更简单(以避免几个malloc
ELF符号之间的冲突)。要了解有关共享库中符号的更多信息,请阅读Drepper的如何编写共享库论文。当然,你应该期待LTO改变链接的行为!
- 将自定义函数传递到基抽象类中以延迟执行
- Arduino:在 loop() 和自定义函数中运行相同的代码时出现问题
- 将具有固定签名的自定义函数名称注入 CRTP
- 每个类实例的自定义函数 (C++)
- C++,当函子不是一个选项时,我如何编写带有自定义函数调用的模板化 RAII 包装器?
- 具有自定义函数的 C++ 矢量构造函数
- 自定义函数转换错误?
- C++ 中是否有任何内置阶乘函数?
- 模板中的自定义函数C++
- 如何将CString转换为使用WCHAR的Windows API和自定义函数?
- r-工作程序中对自定义函数的未定义引用(C++和RcppParallel)
- 传递自定义函数类型时的'incompatible types in assignment'
- 从状态内的自定义函数(不是操作)提升 MSM 调用process_event?
- 如何使用C 代码调用MATLAB自定义函数
- 如何在 std::vector 内的自定义对象上使用 std::find
- glibc函数的GCC、-flto、-fno内置和自定义函数实现
- 自定义函数中断
- 在1语句中传递一个自定义函数作为模板参数
- "stoi"没有在此范围内声明,即使添加 -std=c++0x 和自定义函数,仍然适用
- Qt c++ -未定义的参考…内联QImage自定义函数