Xcode7でのembed-bitcodeオプション



こちらからの続きです。
LLVM bitcode基礎知識
http://qiita.com/gamako/items/f37dbb05de9d3832ce6b




Xcode7からデフォルトで有効になったembed-bitcodeオプションがどんな働きをしているか見てみましょう。

# ふつうのoファイル

まず前回と同じHelloWorldのソースコードから、ふつうにoファイルを出力してみます。

```
clang -c sample.c -o sample.o
```

中身はバイナリなので、hexdumpしてみます。

```bash
% 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の情報は含まれていません。

```bash
% /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