こちらからの続きです。
LLVM bitcode基礎知識
http://qiita.com/gamako/items/f37dbb05de9d3832ce6b
Xcode7からデフォルトで有効になったembed-bitcodeオプションがどんな働きをしているか見てみましょう。
ふつうのoファイル
まず前回と同じHelloWorldのソースコードから、ふつうにoファイルを出力してみます。
clang -c sample.c -o sample.o
中身はバイナリなので、hexdumpしてみます。
% hexdump -C -v sample.o
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 01 00 00 00 |................|
00000010 04 00 00 00 00 02 00 00 00 20 00 00 00 00 00 00 |......... ......|
00000020 19 00 00 00 88 01 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 98 00 00 00 00 00 00 00 20 02 00 00 00 00 00 00 |........ .......|
00000050 98 00 00 00 00 00 00 00 07 00 00 00 07 00 00 00 |................|
00000060 04 00 00 00 00 00 00 00 5f 5f 74 65 78 74 00 00 |........__text..|
...
00000300 00 5f 6d 61 69 6e 00 5f 70 72 69 6e 74 66 00 4c |._main._printf.L|
00000310 5f 2e 73 74 72 00 00 00 |_.str...|
00000318
llvm-objdumpコマンドで、もう少し人間に優しい出力をしてくれます。当たり前ですが、この中にbitcodeの情報は含まれていません。
% /usr/local/Cellar/llvm/3.6.1/bin/llvm-objdump -private-headers -section-headers -disassemble -s sample.o
sample.o: file format Mach-O 64-bit x86-64
Disassembly of section __TEXT,__text:
_main:
0: 55 pushq %rbp
1: 48 89 e5 movq %rsp, %rbp
4: 48 83 ec 10 subq $16, %rsp
8: 48 8d 3d 00 00 00 00 leaq (%rip), %rdi
f: c7 45 fc 00 00 00 00 movl $0, -4(%rbp)
16: b0 00 movb $0, %al
18: e8 00 00 00 00 callq 0
1d: 31 c9 xorl %ecx, %ecx
1f: 89 45 f8 movl %eax, -8(%rbp)
22: 89 c8 movl %ecx, %eax
24: 48 83 c4 10 addq $16, %rsp
28: 5d popq %rbp
29: c3 retq
Sections:
Idx Name Size Address Type
0 __text 0000002a 0000000000000000 TEXT
1 __cstring 0000000e 000000000000002a DATA
2 __compact_unwind 00000020 0000000000000038 DATA
3 __eh_frame 00000040 0000000000000058 DATA
Contents of section __text:
0000 554889e5 4883ec10 488d3d00 000000c7 UH..H...H.=.....
0010 45fc0000 0000b000 e8000000 0031c989 E............1..
0020 45f889c8 4883c410 5dc3 E...H...].
Contents of section __cstring:
002a 48656c6c 6f2c2057 6f726c64 0a00 Hello, World..
Contents of section __compact_unwind:
0038 00000000 00000000 2a000000 00000001 ........*.......
0048 00000000 00000000 00000000 00000000 ................
Contents of section __eh_frame:
0058 14000000 00000000 037a5200 01781001 .........zR..x..
0068 100c0708 90010000 24000000 1c000000 ........$.......
0078 88ffffff ffffffff 2a000000 00000000 ........*.......
0088 00410e10 8602430d 06000000 00000000 .A....C.........
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 X86_64 ALL 0x00 OBJECT 4 512 SUBSECTIONS_VIA_SYMBOLS
Load command 0
...
osxのotoolコマンドでも中身をみることができます。
% otool -hfavltVdoj sample.o
sample.o:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 X86_64 ALL 0x00 OBJECT 4 512 SUBSECTIONS_VIA_SYMBOLS
...
embed-bitcodeでbitcodeを埋め込む
Xcode7 betaのclangで-fembed-bitcodeをつけてオブジェクトファイルを作ってみます
% /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -c -fembed-bitcode sample.c -o sample1.o
出力されたオブジェクトファイルのサイズは、先ほどのものに比べてかなり大きいようです。
% ls -al
...
-rw-r--r-- 1 gamako staff 75 9 4 13:43 sample.c
-rw-r--r-- 1 gamako staff 792 9 4 14:38 sample.o
-rw-r--r-- 1 gamako staff 2676 9 4 15:25 sample1.o
中身をダンプしてみましょう
% hexdump -C -v sample1.o
00000000 cf fa ed fe 07 00 00 01 03 00 00 00 01 00 00 00 |................|
00000010 04 00 00 00 a0 02 00 00 00 20 00 00 00 00 00 00 |......... ......|
00000020 19 00 00 00 28 02 00 00 00 00 00 00 00 00 00 00 |....(...........|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
...
00000a40 00 5f 6d 61 69 6e 00 5f 70 72 69 6e 74 66 00 5f |._main._printf._|
00000a50 6c 6c 76 6d 2e 63 6d 64 6c 69 6e 65 00 5f 6c 6c |llvm.cmdline._ll|
00000a60 76 6d 2e 65 6d 62 65 64 64 65 64 2e 6d 6f 64 75 |vm.embedded.modu|
00000a70 6c 65 00 00 |le..|
00000a74
llvm-objdumpで中身を見てみると、__bitcodeと__cmdlineのセクションが増えているのがわかります。
% /usr/local/Cellar/llvm/3.6.1/bin/llvm-objdump -private-headers -section-headers -disassemble -s sample1.o
sample1.o: file format Mach-O 64-bit x86-64
Disassembly of section __TEXT,__text:
_main:
0: 55
...
Sections:
Idx Name Size Address Type
0 __text 0000002a 0000000000000000 TEXT
1 __cstring 0000000e 000000000000002a DATA
2 __bitcode 00000640 0000000000000040 DATA
3 __cmdline 00000042 0000000000000680 DATA
4 __compact_unwind 00000020 00000000000006c8 DATA
5 __eh_frame 00000040 00000000000006e8 DATA
Contents of section __text:
0000 554889e5 4883ec10 488d3d1b 000000c7 UH..H...H.=.....
0010 45fc0000 0000b000 e8000000 0031c989 E............1..
0020 45f889c8 4883c410 5dc3 E...H...].
Contents of section __cstring:
002a 48656c6c 6f2c2057 6f726c64 0a00 Hello, World..
Contents of section __bitcode:
0040 dec0170b 00000000 14000000 28060000 ............(...
0050 07000001 4243c0de 210c0000 87010000 ....BC..!.......
0060 0b822000 02000000 12000000 07812391 .. ...........#.
0070 41c80449 06103239 9201840c 25050819 A..I..29....%...
0080 1e048b62 80104502 42920b42 84103214 ...b..E.B..B..2.
...
0640 14010000 61200000 0b000000 1304412c ....a ........A,
0650 10000000 03000000 34230064 43190230 ........4#.dC..0
0660 18830100 3311ca40 0c8311c1 00002306 ....3..@......#.
0670 04001c42 12000000 00000000 00000000 ...B............
Contents of section __cmdline:
0680 2d747269 706c6500 7838365f 36342d61 -triple.x86_64-a
0690 70706c65 2d6d6163 6f737831 302e3130 pple-macosx10.10
06a0 2e30002d 656d6974 2d6f626a 002d6469 .0.-emit-obj.-di
06b0 7361626c 652d6c6c 766d2d6f 70747a6e sable-llvm-optzn
06c0 7300 s.
Contents of section __compact_unwind:
06c8 00000000 00000000 2a000000 00000001 ........*.......
06d8 00000000 00000000 00000000 00000000 ................
Contents of section __eh_frame:
06e8 14000000 00000000 037a5200 01781001 .........zR..x..
06f8 100c0708 90010000 24000000 1c000000 ........$.......
0708 f8f8ffff ffffffff 2a000000 00000000 ........*.......
0718 00410e10 8602430d 06000000 00000000 .A....C.........
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 X86_64 ALL 0x00 OBJECT 4 672 SUBSECTIONS_VIA_SYMBOLS
Load command 0
...
Section
sectname __bitcode
segname __LLVM
addr 0x0000000000000040
size 0x0000000000000640
offset 768
align 2^4 (16)
reloff 0
nreloc 0
type S_REGULAR
attributes (none)
reserved1 0
reserved2 0
Section
sectname __cmdline
segname __LLVM
addr 0x0000000000000680
size 0x0000000000000042
offset 2368
align 2^4 (16)
reloff 0
nreloc 0
type S_REGULAR
attributes (none)
reserved1 0
reserved2 0
Section
sectname __compact_unwind
...
bitcodeの抜き出し
bitcodeのセクションはoffsetが768でsizeが0x640とあるので、この部分をファイルに抜き出してみましょう。ddコマンドでできます。
% dd if=sample1.o bs=1 skip=768 count=0x640 of=sample1.bc
1600+0 records in
1600+0 records out
1600 bytes transferred in 0.002806 secs (570217 bytes/sec)
% hexdump -C -v sample1.bc
00000000 de c0 17 0b 00 00 00 00 14 00 00 00 28 06 00 00 |............(...|
00000010 07 00 00 01 42 43 c0 de 21 0c 00 00 87 01 00 00 |....BC..!.......|
00000020 0b 82 20 00 02 00 00 00 12 00 00 00 07 81 23 91 |.. ...........#.|
...
00000620 18 83 01 00 33 11 ca 40 0c 83 11 c1 00 00 23 06 |....3..@......#.|
00000630 04 00 1c 42 12 00 00 00 00 00 00 00 00 00 00 00 |...B............|
00000640
抜き出した部分はllvm-disコマンドでLLVM IRのテキストに変換できます。
% /usr/local/Cellar/llvm/3.6.1/bin/llvm-dis sample1.bc
% cat sample1.ll
; ModuleID = 'sample1.bc'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"
@.str = private unnamed_addr constant [14 x i8] c"Hello, World\0A\00", align 1
; Function Attrs: nounwind ssp uwtable
define i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0, i32* %1
%2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0))
ret i32 0
}
declare i32 @printf(i8*, ...) #1
attributes #0 = { nounwind ssp uwtable "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"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "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"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "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 7.0.0 (clang-700.0.72)"}
ソースからコンパイルしたbitcodeとの比較
これをxcode7 betaのclangで出力したbitcodeと比較してみましょう。
% /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -c -emit-llvm sample.c
% hexdump -C -v sample.bc
00000000 de c0 17 0b 00 00 00 00 14 00 00 00 38 06 00 00 |............8...|
00000010 07 00 00 01 42 43 c0 de 21 0c 00 00 8b 01 00 00 |....BC..!.......|
00000020 0b 82 20 00 02 00 00 00 12 00 00 00 07 81 23 91 |.. ...........#.|
...
00000630 04 00 1c 42 12 21 31 00 02 00 00 00 0b 0a 60 08 |...B.!1.......`.|
00000640 04 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000650
% /usr/local/Cellar/llvm/3.6.1/bin/llvm-dis sample.bc
% cat sample.ll
; ModuleID = 'sample.bc'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"
@.str = private unnamed_addr constant [14 x i8] c"Hello, World\0A\00", align 1
; Function Attrs: nounwind ssp uwtable
define i32 @main() #0 {
%1 = alloca i32, align 4
store i32 0, i32* %1
%2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0))
ret i32 0
}
declare i32 @printf(i8*, ...) #1
attributes #0 = { nounwind ssp uwtable "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"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "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"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "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 7.0.0 (clang-700.0.72)"}
bitcodeの中身とサイズは若干違うようですが、、、
% ls -al
...
-rw-r--r-- 1 gamako staff 1616 9 4 15:38 sample.bc
-rw-r--r-- 1 gamako staff 1268 9 4 15:43 sample.ll
-rw-r--r-- 1 gamako staff 1600 9 4 15:47 sample1.bc
-rw-r--r-- 1 gamako staff 1269 9 4 15:55 sample1.ll
llファイルのdiffをとってみるとわかるように、中の情報はほぼ同一であることがわかります。
% diff sample.ll sample1.ll
1c1
< ; ModuleID = 'sample.bc'
---
> ; ModuleID = 'sample1.bc'
__cmdlineセクション
一方__cmdlineセクションは以下のようになっていました。ビルド時のオプションが格納されているようにみえます。これをヒントにストア側での再最適化が行われるのでしょう。
Contents of section __cmdline:
0680 2d747269 706c6500 7838365f 36342d61 -triple.x86_64-a
0690 70706c65 2d6d6163 6f737831 302e3130 pple-macosx10.10
06a0 2e30002d 656d6974 2d6f626a 002d6469 .0.-emit-obj.-di
06b0 7361626c 652d6c6c 766d2d6f 70747a6e sable-llvm-optzn
06c0 7300 s.
最後に
Xcodeでのビルドについては、こちらも参考にどうぞ
XcodeでArchive以外のビルド結果にはbitcodeが埋め込まれない
http://qiita.com/gamako/items/66d3a8164678e525a26e