Jak skompilować clang do llvm IR

150

Chcę, aby Clang skompilował mój C/C++kod do LLVMkodu bajtowego, a nie do pliku binarnego. Jak mogę to osiągnąć? A jeśli otrzymam LLVMkod bajtowy, jak mogę go dalej skompilować do binarnego pliku wykonywalnego.

Zasadniczo chcę dodać część własnego kodu do LLVMkodu bajtowego przed skompilowaniem do binarnego pliku wykonywalnego.

pythonic
źródło
Myślę, że nazywa się to Bitcode LLVM
PreeJackie

Odpowiedzi:

204

Biorąc pod uwagę plik C / C ++ foo.c:

> clang -S -emit-llvm foo.c

Tworzy foo.llplik LLVM IR.

-emit-llvmOpcja może być także przekazane do kompilatora frontonu bezpośrednio, a nie sterownika za pomocą -cc1:

> clang -cc1 foo.c -emit-llvm

Produkuje foo.llz IR. -cc1dodaje kilka fajnych opcji, takich jak -ast-print. Sprawdź -cc1 --helpwięcej szczegółów.


Aby skompilować LLVM IR po złożeniu, użyj llcnarzędzia:

> llc foo.ll

Produkuje foo.sz montażem (domyślnie do architektury maszyny, na której go uruchamiasz). llcjest jednym z narzędzi LLVM - oto jego dokumentacja .

Eli Bendersky
źródło
7
Co robi -S tutaj?
meawoppl
13
@meawoppl: -S jak w gcc mówi, że emituje zestaw tekstowy, a nie złożony plik binarny
Eli Bendersky
Ahha. Trudno mi było znaleźć cokolwiek w dokumentach na ten temat. Można bezpiecznie założyć, że wiele flag w strukturze flag clang mirror gcc?
meawoppl
@EliBendersky Czy wiesz, jak skompilować wiele plików .c i .h w jeden czytelny dla człowieka IR, aby móc uruchomić IR za pomocą „lli theIrFile”? Dzięki
pamięć podręczna
1
@cache: skompiluj każdy do osobnego pliku IR, a następnie użyj linkera LLVM do połączenia
Eli Bendersky,
20

Posługiwać się

clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc
Christoph
źródło
9
Zalecałbym, aby znaczenia rozszerzenia pozostały nienaruszone. IOW, .opowinno odnosić się do binarnych plików obiektów, .sdo plików asemblerów i czegoś innego (zgodnie z konwencją .ll) do plików LLVM IR. W przeciwnym razie łatwo się pogubić. Clang / LLVM nie ma teraz własnego konsolidatora dla obiektów binarnych (chociaż jeden jest w przygotowaniu). Linker LLVM llvm-ldpo prostu łączy kilka plików IR w jeden
Eli Bendersky,
1
@EliBendersky: masz rację, jeśli chodzi o rozszerzenia plików - a nakładka clang działa właściwie, jeśli .bcjest używana; również pamiętaj o tymllvm-ld może działać jako nakładka na systemowy łańcuch narzędzi, tj. moja poprzednia odpowiedź llvm-ld -nativepowinna działać zgodnie z oczekiwaniami ....
Christoph
1
@rickfoosusa: działa dla mnie - foo.bcto plik kodu bitowego LLVM
Christoph
1
Pracuje dla mnie: clang -emit-llvm -o test.bc -c test.c && file test.bc: test.bc: LLVM IR bitcode .
ntc2
18

Jeśli masz wiele plików źródłowych, prawdopodobnie chcesz użyć optymalizacji czasu łącza, aby wygenerować jeden plik kodu bitowego dla całego programu. Inne podane odpowiedzi spowodują, że otrzymasz plik kodu bitcode dla każdego pliku źródłowego.

Zamiast tego chcesz kompilować z optymalizacją czasu łącza

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

a na ostatnim etapie łączenia dodaj argument -Wl, -plugin-opt = also-emit-llvm

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

Daje to zarówno skompilowany program, jak i odpowiadający mu kod bitowy (program.bc). Następnie możesz zmodyfikować program.bc w dowolny sposób i ponownie skompilować zmodyfikowany program w dowolnym momencie, wykonując czynności

clang program.bc -o program

chociaż pamiętaj, że musisz ponownie dołączyć wszystkie niezbędne flagi konsolidatora (dla bibliotek zewnętrznych itp.).

Zauważ, że musisz użyć złotego linkera, aby to zadziałało. Jeśli chcesz zmusić clang do użycia określonego konsolidatora, utwórz dowiązanie symboliczne do tego konsolidatora o nazwie "ld" w specjalnym katalogu o nazwie "fakebin" gdzieś na twoim komputerze i dodaj opcję

-B/home/jeremy/fakebin

do powyższych kroków łączenia.

Jeremy Salwen
źródło
13

Jeśli masz wiele plików i nie chcesz wpisywać każdego pliku, polecam wykonanie tych prostych kroków (używam, clang-3.8ale możesz użyć dowolnej innej wersji):

  1. wygeneruj wszystkie .llpliki

    clang-3.8 -S -emit-llvm *.c
  2. połącz je w jeden

    llvm-link-3.8 -S -v -o single.ll *.ll
  3. (Opcjonalnie) Zoptymalizuj swój kod (może trochę analizy aliasów)

    opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
  4. Generuj zespół (generuje optimised.splik)

    llc-3.8 optimised.ll
  5. Utwórz plik wykonywalny (nazwany a.out)

    clang-3.8 optimised.s
Kiko Fernandez
źródło
Twoje rozwiązanie jest dość wyjątkowe: użyłeś "-S" zamiast po prostu zostawić to jako wyjście binarne. Czy jest jakaś różnica pomiędzy posiadaniem „-S” a brakiem „-S”?
Peter Teoh
@PeterTeoh Używam -Sopcji (w kroku 2), określam, że chciałbym wyprodukować wyjście w LLVM IR. Zasadniczo umieść wszystkie pliki * .ll w jednym. Robię to, aby sprawdzić, czy optymalizacje naprawdę zmieniają kod, tj. single.llI optimised.llpowinny teraz wyglądać inaczej (pod względem kodu), a także możesz wyświetlić raport, aby zobaczyć, czy w ogóle jest jakaś różnica.
Kiko Fernandez
-basicaaajest złą flagą, -basicaanależy jej użyć.
anton_rh