我正在观察带有GCC标志-fltojemalloc / 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节在几页中解释了优化是如何发生的)。

为了优化mallocfree,GCC在__attribute__(malloc)的声明(在<stdlib.h>内)中使用了一些malloc function attribute



LTO在GCC internals §25中说明。

它通过在“编译”和“链接”时都使用一些内部(类似于GIMPLE和/或类似SSA)代码的表示来工作(实际上,链接步骤成为具有整个程序优化的另一个编译,因此您的代码在实践中两次被“编译”。

LTO在实践中始终应在编译时和链接时与一些优化标志(例如-O2甚至-O3)一起使用。因此,您应该使用g++ -flto -O2进行编译和链接(使用没有至少-flto-O2并没有实际意义,并且应该在编译时和链接时使用完全相同的优化标志)。

更准确地说,-flto还在目标文件中嵌入了源代码的一些内部(类似于GIMPLE的)表示,并且还“在链接时”使用(特别是当“链接”整个程序时,optimizationinlining再次发生,使用其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 7GCC 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/

10-11 21:57