2013-07-11 20 views
10

Sto imparando llvm e volevo fare una dimostrazione del concetto di un'idea che ho.Chiama le funzioni C/C++ da ExecutionEngine

Fondamentalmente, voglio dividere il mio compilatore e il mio runtime. Il compilatore darebbe un file .bc e il runtime lo caricherà tramite ParseBitcodeFile e userà ExecutionEngine per eseguirlo. Questa parte sta funzionando.

Ora, per effettuare facilmente chiamate di sistema, voglio essere in grado di implementare nelle mie funzioni di runtime C/C++ che eseguono tutte le chiamate di sistema (file io, stdout printing, ecc.). La mia domanda è, come potrei chiamare queste funzioni dal codice del mio compilatore giocattolo, che è compilato in un passo diverso da llvm, e permettere che venga usato quando viene eseguito.

risposta

9

Buone notizie: quando si utilizza il JIT ExecutionEngine, questo sarà funziona solo. Quando JIT-er trova un simbolo esterno usato dall'IR che non si trova nell'IR stesso, guarda nel processo stesso JIT, quindi tutti i simboli visibili dal programma host possono essere richiamati.

questo è spiegato direttamente in part 4 of the LLVM tutorial:

Whoa, come fa il JIT conoscono peccato e cos? La risposta è sorprendentemente semplice: in questo esempio, il JIT ha iniziato l'esecuzione di una funzione e ha ottenuto una chiamata di funzione. Si rese conto che la funzione era non ancora compilata JIT e invocata la serie standard di routine per risolvere la funzione . In questo caso, non esiste un corpo definito per la funzione , quindi il JIT ha finito per chiamare "dlsym (" sin ")" sul processo Kaleidoscope stesso. Poiché "sin" è definito all'interno dello spazio di indirizzamento dello JIT , esso semplicemente effettua il patch delle chiamate nel modulo per chiamare direttamente la versione della libm di libm.

Per i dettagli cruenti guardare lib/ExecutionEngine/JIT/JIT.cpp - in particolare l'utilizzo di DynamicLibrary.

8

La risposta di Eli è ottima e dovresti accettarla. C'è un'altra alternativa, però, che consiste nel compilare separatamente i file sorgente del runtime in moduli LLVM (ad esempio con Clang) e utilizzare ExecutionEngine::addModule() per aggiungerli.

È meno conveniente, e significa compilare gli stessi file due volte (una volta per il programma host, un'altra per ottenere Module da loro), ma il vantaggio è che consente la inlining e altre ottimizzazioni incrociate dal codice JITted .