我正在观察带有GCC标志-flto
和jemalloc
/ tcmalloc
的意外行为(至少我找不到解释)。一旦使用了-flto
,并且我与上面的库malloc / calloc链接,并且 friend 不被je/tc malloc
实现取代,则调用glibc实现。删除-flto
标志后,一切都会按预期进行。我尝试将-fno-builtin
/ -fno-builtin-*
与-flto
一起使用,但仍然没有选择je/tc malloc
实现。-flto
机制如何工作?为什么二进制文件不选择新的实现?当它在诸如-fno-builtin
的未解决的外部失败时,它甚至如何与printf
链接?
EDIT001:
GCC 7.3
样例代码
int main()
{
auto p = malloc(1024);
free(p);
return 0;
}
汇编:
链式:
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代码(一旦将auto
替换为void*
),而不是C++。根据optimized规则,即使没有<stdlib.h>
,但只有-flto
,也可能是as-if(如果包含-O3
)为空的main
。 (我什至写了一个公共(public)报告bismon-chariot-doc.pdf,其中有第1.4.2节在几页中解释了优化是如何发生的)。
为了优化malloc
和free
,GCC在__attribute__(malloc)
的声明(在<stdlib.h>
内)中使用了一些malloc
function attribute。
LTO在GCC internals §25中说明。
它通过在“编译”和“链接”时都使用一些内部(类似于GIMPLE和/或类似SSA)代码的表示来工作(实际上,链接步骤成为具有整个程序优化的另一个编译,因此您的代码在实践中两次被“编译”。
LTO在实践中始终应在编译时和链接时与一些优化标志(例如-O2
甚至-O3
)一起使用。因此,您应该使用g++ -flto -O2
进行编译和链接(使用没有至少-flto
的-O2
并没有实际意义,并且应该在编译时和链接时使用完全相同的优化标志)。
更准确地说,-flto
还在目标文件中嵌入了源代码的一些内部(类似于GIMPLE的)表示,并且还“在链接时”使用(特别是当“链接”整个程序时,optimization和inlining再次发生,使用其GIMPLE)。实际上,GCC包含一些LTO前端和称为lto1
的编译器(除了C++前端和称为cc1plus
的编译器),并且lto1
(在与g++ -flto -O2
链接时)在链接时用于重新处理这些GIMPLE表示形式。libjemalloc
可能有其自己的 header ,并且可能具有inline
(或inlinable)函数。然后,从源代码编译该库时,您还需要使用-flto -O2
(以便将其Gimple存储在该库中)
最后,通常的malloc
被调用的事实独立于-flto
。这是一个链接器问题,而不是编译器问题。您可以尝试静态链接-ljemalloc
(然后最好也使用gcc -flto -O2
构建该库;如果不这样构建,就不会在malloc
调用中获得LTO优化)。
您也可以将-v
传递给编译和链接命令,以了解g++
在做什么。您甚至可以传递-Wl,--verbose
来要求ld
(以g++
开头)是冗长的。
请注意,LTO(及其使用的内部表示形式)是特定于编译器和版本的。内部(Gimple和SSA)表示形式在GCC 7和GCC 8之间略有不同(在Clang中,它是非常不同的,因此当然是不兼容的)。动态链接器ld-linux(8)不了解LTO。
PS。您可以安装libjemalloc-dev
软件包并在代码中添加#include <jemalloc/jemalloc.h>
。另请参见jemalloc(3)手册页。可以配置或修补libjemalloc
来定义一些je_malloc
符号,以代替malloc
。然后(对于LTO)在代码中使用je_malloc
会更简单(避免几个malloc
ELF符号之间的冲突)。要了解有关共享库中符号的更多信息,请阅读Drepper的How to Write Shared Libraries论文。当然,您应该期望LTO改变链接的行为!
关于c++ - Glibc函数的GCC,-flto,-fno-builtin和自定义函数实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53904726/