LLVM IR、LLVM bitcodeを扱うコマンドたちのメモ
LLVM IR、LLVM bitcodeを扱うコマンドをよく忘れるのでメモしておく。 CのコードをLLVM IR、LLVM bitcodeに変換するコマンド、LLVM bitcodeをインタプリタから実行するコマンド、コンパイルするコマンドなどを書いておく。 以下のCのコードを変換していく。
# include <stdio.h> int main() { int a = 1; int b = 2; int sum = a + b; printf("%d", sum); return 0; }
LLVM IRを出力する
LLVM内ではLLVM IRという中間言語表現が用いられる。LLVM内で使えるアセンブリのようなものである。 LLVMを用いたコンパイラでは、ソースコードをLLVM IRコードに変換したあと、そのLLVM IRコードをターゲットのアーキテクチャのバイナリに変換することでコンパイルが行われる。
Cのコードを変換する
clangに-emit-llvm
、-S
の2つのオプションを指定して実行するとLLVM IRが出力される。
以下のようにコマンドを実行するとtest.llが出力される。
$ clang test.c -emit-llvm -S
出力されたLLVM IR
以下のようなLLVM IRのコードが出力される。
$ cat test.ll ; ModuleID = 'test.c' source_filename = "test.c" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.12.0" @.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1 ; Function Attrs: nounwind ssp uwtable define i32 @main() #0 { %1 = alloca i32, align 4 %2 = alloca i32, align 4 %3 = alloca i32, align 4 %4 = alloca i32, align 4 store i32 0, i32* %1, align 4 store i32 1, i32* %2, align 4 store i32 2, i32* %3, align 4 %5 = load i32, i32* %2, align 4 %6 = load i32, i32* %3, align 4 %7 = add nsw i32 %5, %6 store i32 %7, i32* %4, align 4 %8 = load i32, i32* %4, align 4 %9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i32 %8) ret i32 0 } declare i32 @printf(i8*, ...) #1 attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.module.flags = !{!0} !llvm.ident = !{!1} !0 = !{i32 1, !"PIC Level", i32 2} !1 = !{!"Apple LLVM version 8.0.0 (clang-800.0.38)"}
LLVM bitcodeを出力する
LLVM bitcodeはLLVM IRのバイナリフォーマットである。 LLVM IRと LLVM bitocodeは相互変換でき、LLVM bitcodeはバイナリ(.out, .exeなど)に変換せずとも、LLVMのインタプリタから直接実行することができる。
Cのコードを変換する
clangに-emit-llvm
、-c
の2つのオプションを指定して実行するとLLVM bitcodeが出力される。
以下のようにコマンドを実行するとtest.bcが出力される。
$ clang test.c -emit-llvm -c
LLVM IRを変換する
llvm-asコマンドを使うことでLLVM IRをLLVM bitcodeに変換できる。 以下のようにコマンドを実行するとtest.bcが出力される。
$ llvm-as test.ll
出力されたLLVM bitcode
人の目で直接読むのはきびしい。
$ file test.bc test.bc: LLVM bitcode, wrapper x86_64
$ hexdump -C test.bc 00000000 de c0 17 0b 00 00 00 00 14 00 00 00 a8 09 00 00 |................| 00000010 07 00 00 01 42 43 c0 de 35 14 00 00 05 00 00 00 |....BC..5.......| 00000020 62 0c 30 24 49 59 be a6 ee d3 3e 2d 44 01 32 05 |b.0$IY....>-D.2.| 00000030 00 00 00 00 21 0c 00 00 1e 02 00 00 0b 02 21 00 |....!.........!.| 00000040 02 00 00 00 13 00 00 00 07 81 23 91 41 c8 04 49 |..........#.A..I| 00000050 06 10 32 39 92 01 84 0c 25 05 08 19 1e 04 8b 62 |..29....%......b| 00000060 80 10 45 02 42 92 0b 42 84 10 32 14 38 08 18 4b |..E.B..B..2.8..K| 00000070 0a 32 42 88 48 90 14 20 43 46 88 a5 00 19 32 42 |.2B.H.. CF....2B| 00000080 04 49 0e 90 11 22 c4 50 41 51 81 8c e1 83 e5 8a |.I...".PAQ......| 00000090 04 21 46 06 51 18 00 00 e9 00 00 00 1b 4c 25 f8 |.!F.Q........L%.| 000000a0 ff ff ff ff 01 90 00 0d 08 03 82 1c d2 61 1e c2 |.............a..| 000000b0 41 1c d8 a1 1c da 80 1e c2 21 1d d8 a1 0d c6 21 |A........!.....!| ....
LLVM bitcodeをLLVM IRにデコンパイル
相互変換できるのでLLVM IRに戻すことができる。すごい。
$ llvm-dis test.bc
LLVM bitcodeをインタプリタで実行する
lliコマンドを使うことでLLVM bitcodeをインタプリタから直接実行できる。
$ lli test.bc 3
LLVMの bitcodeをバイナリにする
llcコマンドを使うことでLLVM bitcodeをターゲットアーキテクチャのアセンブリに変換し、そのアセンブリをclangでコンパイルすることでバイナリが出力される。
$ llc test.bc $ clang test.s $ ./a.out 3