Wie man Clang zu llvm IR kompiliert

150

Ich möchte, dass clang meinen C/C++Code zu LLVMBytecode kompiliert und nicht zu einer ausführbaren Binärdatei. Wie kann ich das erreichen? Und wenn ich den LLVMBytecode erhalte , wie kann ich ihn verwenden, um ihn weiter in eine ausführbare Binärdatei zu kompilieren?

Grundsätzlich möchte ich dem LLVMBytecode einen Teil meines eigenen Codes hinzufügen, bevor ich ihn in eine ausführbare Binärdatei kompiliere.

pythonisch
quelle
Ich denke, es heißt LLVM-Bitcode
PreeJackie

Antworten:

204

Angesichts einer C / C ++ - Datei foo.c:

> clang -S -emit-llvm foo.c

Erzeugt foo.lleine LLVM-IR-Datei.

Die -emit-llvmOption kann auch direkt an das Compiler-Frontend und nicht an den Treiber übergeben werden -cc1:

> clang -cc1 foo.c -emit-llvm

Produziert foo.llmit dem IR. -cc1fügt einige coole Optionen wie hinzu -ast-print. Schauen Sie sich -cc1 --helpfür weitere Details.


Verwenden Sie das folgende llcTool, um LLVM IR weiter nach der Assembly zu kompilieren :

> llc foo.ll

Produziert foo.smit Assembly (standardmäßig die Maschinenarchitektur, auf der Sie sie ausführen). llcist eines der LLVM-Tools - hier ist seine Dokumentation .

Eli Bendersky
quelle
7
Was macht -S hier?
Meawoppl
13
@meawoppl: -S wie in gcc sagt, emittieren Text-Assemblierung anstatt montierte Binärdatei
Eli Bendersky
Ahha. Es fiel mir schwer, in den Dokumenten etwas darüber zu finden. Es ist sicher anzunehmen, dass viele Flags in Clang Mirror Gcc Flag Struktur?
Meawoppl
@EliBendersky Wissen Sie, wie Sie mehrere .c- und .h-Dateien in einem für Menschen lesbaren IR kompilieren, damit ich den IR mit 'lli theIrFile' ausführen kann? Danke
Cache
1
@cache: kompilieren Sie jede in ihre eigene IR-Datei und verwenden Sie dann den LLVM-Linker, um zu kombinieren
Eli Bendersky
20

Verwenden

clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc
Christoph
quelle
9
Ich würde empfehlen, die Erweiterungsbedeutungen beizubehalten. IOW .osollte sich auf binäre Objektdateien, .sauf Assembly-Dateien und etwas anderes ( .llgemäß Konvention ) auf LLVM-IR-Dateien beziehen . Ansonsten ist es leicht, verwirrt zu werden. Clang / LLVM haben jetzt keinen eigenen Linker für binäre Objekte (obwohl einer in Arbeit ist). Der LLVM-Linker verbindet llvm-ldnur mehrere IR-Dateien zu einer
Eli Bendersky
1
@EliBendersky: Sie haben Recht, wenn es um Dateierweiterungen geht - und das Clang-Frontend macht tatsächlich das Richtige, wenn .bces verwendet wird. Denken Sie auch daran, dass llvm-lddies als Frontend für die System-Toolchain dienen kann, dh meine vorherige Antwort mit llvm-ld -nativesollte wie erwartet funktionieren ....
Christoph
1
@rickfoosusa: funktioniert für mich - foo.bcist eine LLVM-Bitcode-Datei
Christoph
1
Funktioniert für mich : clang -emit-llvm -o test.bc -c test.c && file test.bc: test.bc: LLVM IR bitcode.
Ntc2
18

Wenn Sie mehrere Quelldateien haben, möchten Sie wahrscheinlich die Link-Time-Optimierung verwenden, um eine Bitcode-Datei für das gesamte Programm auszugeben. Die anderen Antworten führen dazu, dass Sie für jede Quelldatei eine Bitcode-Datei erhalten.

Stattdessen möchten Sie mit der Optimierung der Verbindungszeit kompilieren

clang -flto -c program1.c -o program1.o
clang -flto -c program2.c -o program2.o

Fügen Sie für den letzten Verknüpfungsschritt das Argument -Wl, -plugin-opt = also-emit-llvm hinzu

clang -flto -Wl,-plugin-opt=also-emit-llvm program1.o program2.o -o program

Dies gibt Ihnen sowohl ein kompiliertes Programm als auch den entsprechenden Bitcode (program.bc). Sie können dann program.bc nach Belieben ändern und das geänderte Programm jederzeit neu kompilieren

clang program.bc -o program

Beachten Sie jedoch, dass Sie in diesem Schritt erneut alle erforderlichen Linker-Flags (für externe Bibliotheken usw.) einfügen müssen.

Beachten Sie, dass Sie den Gold-Linker verwenden müssen, damit dies funktioniert. Wenn Sie clang zwingen möchten, einen bestimmten Linker zu verwenden, erstellen Sie einen Symlink zu diesem Linker mit dem Namen "ld" in einem speziellen Verzeichnis namens "fakebin" irgendwo auf Ihrem Computer und fügen Sie die Option hinzu

-B/home/jeremy/fakebin

zu den oben genannten Verknüpfungsschritten.

Jeremy Salwen
quelle
13

Wenn Sie mehrere Dateien haben und nicht jede Datei eingeben müssen, würde ich empfehlen, dass Sie diese einfachen Schritte ausführen (ich verwende, clang-3.8aber Sie können jede andere Version verwenden):

  1. Generieren Sie alle .llDateien

    clang-3.8 -S -emit-llvm *.c
  2. Verknüpfe sie zu einer einzigen

    llvm-link-3.8 -S -v -o single.ll *.ll
  3. (Optional) Optimieren Sie Ihren Code (möglicherweise eine Alias-Analyse)

    opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
  4. Baugruppe generieren (generiert eine optimised.sDatei)

    llc-3.8 optimised.ll
  5. Erstellen Sie eine ausführbare Datei (benannt a.out)

    clang-3.8 optimised.s
Kiko Fernandez
quelle
Ihre Lösung ist ziemlich einzigartig: Sie haben "-S" verwendet, anstatt es nur als Binärausgabe zu belassen. Gibt es einen Unterschied zwischen "-S" und "-S"?
Peter Teoh
@PeterTeoh Ich verwende die -SOption (in Schritt 2) und gebe an , dass ich die Ausgabe in LLVM IR erzeugen möchte. Legen Sie grundsätzlich alle * .ll-Dateien in einer einzigen ab. Ich mache dies, um zu überprüfen, ob die Optimierungen den Code wirklich ändern, dh single.llund optimised.lljetzt anders aussehen sollten (in Bezug auf den Code ), und Sie könnten den Bericht auch anzeigen, um festzustellen, ob es überhaupt einen Unterschied gibt.
Kiko Fernandez
-basicaaaist eine falsche Flagge, -basicaamuss stattdessen verwendet werden.
anton_rh