Ich bin kürzlich auf die eingebauten Funktionen von GCC für einige der Speicherverwaltungsfunktionen der C-Bibliothek aufmerksam gemacht worden, insbesondere __builtin_malloc()
und verwandte integrierte Funktionen (siehe https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html). Beim Lernen über __builtin_malloc()
ich habe mich gefragt, wie es funktionieren könnte, um Leistungsverbesserungen über die Ebene bereitzustellen malloc()
verwandte Bibliotheksroutinen.
Wenn die Funktion beispielsweise erfolgreich ist, muss sie einen Block bereitstellen, der durch einen Aufruf von plain freigegeben werden kann free()
da der Zeiger möglicherweise durch ein Modul freigegeben wird, das ohne kompiliert wurde __builtin_malloc()
oder __builtin_free()
aktiviert (oder irre ich mich, und wenn __builtin_malloc()
verwendet wird, müssen die Builtins global verwendet werden?). Daher muss das zugewiesene Objekt etwas sein, das mit den Datenstrukturen so einfach verwaltet werden kann malloc()
und free()
bewältigen.
Ich kann keine Details finden, wie __builtin_malloc()
funktioniert oder was es genau tut (ich bin kein Compiler-Entwickler, also ist das Durchforsten des GCC-Quellcodes nicht in meinem Steuerhaus). In einigen einfachen Tests, in denen ich versucht habe, anzurufen __builtin_malloc()
direkt, es endet einfach damit, im Objektcode als Aufruf von plain ausgegeben zu werden malloc()
. Es kann jedoch Feinheiten oder Plattformdetails geben, die ich in diesen einfachen Tests nicht anführe.
Welche Arten von Leistungsverbesserungen können __builtin_malloc()
Stellen Sie über einen Anruf zu Plain bereit malloc()
? Tut __builtin_malloc()
haben eine Abhängigkeit von den recht komplexen Datenstrukturen der glibc malloc()
Implementierung verwenden? Oder umgekehrt, tut glibc’s malloc()
/free()
haben Sie etwas Code, um mit Blöcken umzugehen, die zugewiesen werden könnten __builtin_malloc()
?
Grundsätzlich, wie funktioniert es?
Ich glaube, es gibt keine spezielle GCC-interne Implementierung von __builtin_malloc()
. Vielmehr existiert es nur als Built-in, damit es unter bestimmten Umständen wegoptimiert werden kann.
Nehmen Sie dieses Beispiel:
#include <stdlib.h>
int main(void)
{
int *p = malloc(4);
*p = 7;
free(p);
return 0;
}
Wenn wir eingebaute Funktionen deaktivieren (mit -fno-builtins
) und sehen Sie sich die generierte Ausgabe an:
$ 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 <[email protected]>
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 <[email protected]>
40059c: b8 00 00 00 00 mov eax,0x0
4005a1: 48 83 c4 08 add rsp,0x8
4005a5: c3 ret
Ruft an malloc
/free
werden erwartungsgemäß emittiert.
Allerdings durch Zulassen malloc
eingebaut sein,
$ 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
Alle main()
wurde wegoptimiert!
Im Wesentlichen durch das Zulassen malloc
Da GCC eingebaut ist, steht es ihm frei, Aufrufe zu eliminieren, wenn sein Ergebnis nie verwendet wird, da es keine zusätzlichen Nebeneffekte gibt.
Es ist derselbe Mechanismus, der “verschwenderische” Aufrufe ermöglicht printf
zu Anrufen geändert werden puts
:
#include <stdio.h>
int main(void)
{
printf("hello\n");
return 0;
}
Builtins deaktiviert:
$ 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 <[email protected]>
400543: b8 00 00 00 00 mov eax,0x0
400548: 48 83 c4 08 add rsp,0x8
40054c: c3 ret
Builtins aktiviert:
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 <[email protected]>
40053e: b8 00 00 00 00 mov eax,0x0
400543: 48 83 c4 08 add rsp,0x8
400547: c3 ret