Clangをllvm IRにコンパイルする方法


150

clang でバイナリ実行可能ファイルではなくバイトC/C++コードにLLVMコードをコンパイルしてほしい。どうすればそれを達成できますか?そして、LLVMバイトコードを取得した場合、それをバイナリ実行可能ファイルにさらにコンパイルするにはどうすればよいでしょうか。

基本的にLLVM、バイナリ実行可能ファイルにコンパイルする前に、独自のコードの一部をバイトコードに追加します。


私はそれがLLVMビットコードと呼ばれていると思います
PreeJackie

回答:


204

いくつかのC / C ++ファイルを考えますfoo.c

> clang -S -emit-llvm foo.c

生成しfoo.llLLVM IRファイルです。

-emit-llvmオプションもによってドライバを直接コンパイラのフロントエンドに渡され、そしてませんすることができます-cc1

> clang -cc1 foo.c -emit-llvm

foo.llIRで制作。-cc1のようないくつかのクールなオプションを追加します-ast-print。チェックアウト-cc1 --help詳細については。


LLVM IRをさらにアセンブリにコンパイルするには、次のllcツールを使用します:

> llc foo.ll

生成しfoo.s(あなたがそれを実行するマシンのアーキテクチャをデフォルト)のアセンブリで。llcはLLVMツールの1つです。ここにそのドキュメントがあります


7
ここで-Sは何をしますか?
meawoppl 2014

13
@meawoppl:-Sはgccのように、バイナリを組み立てるのではなく、テキストのアセンブリを出力することを示しています
Eli Bendersky

ああ。それに関するドキュメントで何かを見つけるのに苦労していました。clangの多くのフラグがgccフラグ構造を反映していると想定しても安全ですか?
meawoppl 14

@EliBendersky複数の.cおよび.hファイルを人間が読める1つのIRにコンパイルして、「lli theIrFile」を使用してIRを実行できるようにする方法を知っていますか?おかげで
キャッシュ

1
@cache:それぞれを独自のIRファイルにコンパイルし、LLVMリンカーを使用して結合する
Eli Bendersky 14

20

使用する

clang -emit-llvm -o foo.bc -c foo.c
clang -o foo foo.bc

9
拡張機能の意味はそのままにしておくことをお勧めします。IOWは、.oバイナリオブジェクトファイル、.sアセンブリファイル、および.llLLVM IRファイルの他の(慣例により)を参照する必要があります。そうでなければ、混乱するのは簡単です。Clang / LLVMには、バイナリオブジェクト用の独自のリンカーはありません(1つは開発中です)。LLVMリンカーllvm-ldは、複数のIRファイルを1つに結合するだけです
Eli Bendersky

1
@EliBendersky:ファイル拡張子が関係するところは正しいです-そして、clangフロントエンド.bcが使用されている場合、実際には正しいことを行います。心の中でも、キープllvm-ldシステムツールチェーンのためのフロントエンドとして機能することができ、すなわち私の前の回答使用してllvm-ld -native期待通りに動作するはずです....
クリストフ・

1
@rickfoosusa:私のための作品- foo.bcLLVMのビットコードファイルである
クリストフ・

1
私のために働く:clang -emit-llvm -o test.bc -c test.c && file test.bc: test.bc: LLVM IR bitcode
ntc2

18

複数のソースファイルがある場合、実際にはリンク時最適化を使用して、プログラム全体の1つのビットコードファイルを出力する必要があります。与えられた他の答えは、すべてのソースファイルのビットコードファイルで終わることになります。

代わりに、リンク時の最適化でコンパイルしたい

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

最後のリンク手順では、引数-Wl、-plugin-opt = also-emit-llvmを追加します

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

これにより、コンパイルされたプログラムとそれに対応するビットコード(program.bc)の両方が提供されます。次に、program.bcを好きなように変更し、変更したプログラムをいつでも再コンパイルできます。

clang program.bc -o program

ただし、このステップでは、必要なリンカーフラグ(外部ライブラリなど)を再度含める必要があることに注意してください。

これを機能させるには、ゴールドリンカーを使用する必要があることに注意してください。clangで特定のリンカーを使用するように強制するには、コンピューターのどこかにある「fakebin」という特別なディレクトリに「ld」という名前のリンカーへのシンボリックリンクを作成し、オプションを追加します。

-B/home/jeremy/fakebin

上記のリンク手順に。


13

複数のファイルがあり、各ファイルを入力する必要がない場合は、次の簡単な手順に従うことをお勧めします(私は使用してclang-3.8いますが、他のバージョンも使用できます)。

  1. すべての.llファイルを生成する

    clang-3.8 -S -emit-llvm *.c
  2. それらを単一のものにリンクする

    llvm-link-3.8 -S -v -o single.ll *.ll
  3. (オプション)コードを最適化します(おそらくエイリアス分析)

    opt-3.8 -S -O3 -aa -basicaaa -tbaa -licm single.ll -o optimised.ll
  4. アセンブリを生成(optimised.sファイルを生成)

    llc-3.8 optimised.ll
  5. 実行可能ファイルを作成(名前はa.out

    clang-3.8 optimised.s

あなたのソリューションは非常にユニークです:あなたはそれを単にバイナリ出力として残す代わりに「-S」を使いました。「-S」がある場合とない場合に違いはありますか?
Peter Teoh 2017

@PeterTeoh -S(ステップ2で)オプションを使用して、LLVM IRで出力を生成することを指定します。基本的に、すべての* .llファイルを1つにまとめます。これを実行して、最適化によってコードが実際に変更されていることを確認します。つまりsingle.lloptimised.ll今度は異なる(コードごとに)見えるはずです。また、レポートを表示して、違いがあるかどうかを確認することもできます。
Kiko Fernandez

-basicaaa間違ったフラグ-basicaaです。代わりに使用する必要があります。
anton_rh

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.