GCC的`__builtin_malloc()`对普通的'malloc()`提供了哪些改进?

时间:2014-09-24 05:58:02

标签: c gcc

我最近了解了GCC的一些C库内存管理功能的内置函数,特别是__builtin_malloc()和相关的内置函数(参见https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html })。在了解__builtin_malloc()之后,我想知道如何提供相对于普通malloc()相关库例程的性能改进。

例如,如果函数成功,则必须提供一个可以通过调用plain free()释放的块,因为指针可能被没有__builtin_malloc()编译的模块释放或者启用__builtin_free()(或者我错了,如果使用__builtin_malloc(),必须全局使用内置函数?)。因此,分配的对象必须是可以使用malloc()free()处理的数据结构来管理的。

我无法找到有关__builtin_malloc()如何工作或其确切工作方式的任何细节(我不是编译器开发人员,因此通过GCC源代码进行探索并不是我的驾驶室)。在我尝试直接调用__builtin_malloc()的一些简单测试中,它最终只是作为对普通malloc()的调用而在目标代码中发出。但是,在这些简单的测试中,我可能没有提供细微或平台细节。

通过调用普通__builtin_malloc()malloc()可以提供哪些性能改进? __builtin_malloc()是否依赖于glibc malloc()实现使用的相当复杂的数据结构?或者相反,glibc的malloc() / free()是否有一些代码来处理可能由__builtin_malloc()分配的块?

基本上,它是如何运作的?

1 个答案:

答案 0 :(得分:33)

我认为__builtin_malloc()没有特殊的海湾合作委员会内部实施。相反,它仅作为内置存在,因此可以在某些情况下进行优化。

举个例子:

#include <stdlib.h>
int main(void)
{
    int *p = malloc(4);
    *p = 7;
    free(p);
    return 0;
}

如果我们禁用内置函数(使用-fno-builtins)并查看生成的输出:

$ gcc -fno-builtins -O1 -Wall -Wextra builtin_malloc.c && objdump -d -Mintel a.out

0000000000400580 <main>:
  400580:   48 83 ec 08             sub    rsp,0x8
  400584:   bf 04 00 00 00          mov    edi,0x4
  400589:   e8 f2 fe ff ff          call   400480 <malloc@plt>
  40058e:   c7 00 07 00 00 00       mov    DWORD PTR [rax],0x7
  400594:   48 89 c7                mov    rdi,rax
  400597:   e8 b4 fe ff ff          call   400450 <free@plt>
  40059c:   b8 00 00 00 00          mov    eax,0x0
  4005a1:   48 83 c4 08             add    rsp,0x8
  4005a5:   c3                      ret    

按预期发出对malloc / free的来电。

但是,允许malloc是内置的

$ gcc -O1 -Wall -Wextra builtin_malloc.c && objdump -d -Mintel a.out

00000000004004f0 <main>:
  4004f0:   b8 00 00 00 00          mov    eax,0x0
  4004f5:   c3                      ret    

所有main()都被优化了!

基本上,通过允许malloc成为内置函数,如果从不使用结果,GCC可以自由地消除调用,因为没有其他副作用。


同样的机制允许将printf的“浪费”通话更改为对puts的通话:

#include <stdio.h>

int main(void)
{
    printf("hello\n");
    return 0;
}

内置禁用:

$ gcc -fno-builtin -O1 -Wall builtin_printf.c && objdump -d -Mintel a.out

0000000000400530 <main>:
  400530:   48 83 ec 08             sub    rsp,0x8
  400534:   bf e0 05 40 00          mov    edi,0x4005e0
  400539:   b8 00 00 00 00          mov    eax,0x0
  40053e:   e8 cd fe ff ff          call   400410 <printf@plt>
  400543:   b8 00 00 00 00          mov    eax,0x0
  400548:   48 83 c4 08             add    rsp,0x8
  40054c:   c3                      ret    

内置启用:

gcc -O1 -Wall builtin_printf.c && objdump -d -Mintel a.out

0000000000400530 <main>:
  400530:   48 83 ec 08             sub    rsp,0x8
  400534:   bf e0 05 40 00          mov    edi,0x4005e0
  400539:   e8 d2 fe ff ff          call   400410 <puts@plt>
  40053e:   b8 00 00 00 00          mov    eax,0x0
  400543:   48 83 c4 08             add    rsp,0x8
  400547:   c3                      ret