답변:
비트 코드는 iTunes Connect로 전송되는 "LLVM 비트 코드"코드 유형을 나타냅니다. 이를 통해 Apple은 특정 계산을 사용하여 앱을 다시 최적화 할 수 있습니다 (예 : 실행 파일 크기 축소 가능). Apple이 실행 파일을 변경해야하는 경우 새 빌드를 업로드하지 않고도이 작업을 수행 할 수 있습니다.
Apple은 기기의 해상도와 아키텍처를 기반으로 사용자 기기에 맞게 앱을 최적화하는 프로세스 인 슬라이스 와 다릅니다 . 슬라이싱에는 비트 코드가 필요하지 않습니다. (예 : 5 초에 @ 2x 이미지 만 포함)
App Thinning 은 슬라이싱, 비트 코드 및 주문형 리소스의 조합입니다.
비트 코드는 컴파일 된 프로그램의 중간 표현입니다. 비트 코드가 포함 된 iTunes Connect에 업로드 한 앱은 App Store에서 컴파일되고 링크됩니다. 비트 코드를 포함하면 Apple은 새로운 버전의 앱을 스토어에 제출할 필요없이 향후 앱 바이너리를 다시 최적화 할 수 있습니다.
문서 에 따르면 :
비트 코드는 컴파일 된 프로그램의 중간 표현입니다. 비트 코드가 포함 된 iTunes Connect에 업로드 한 앱은 App Store에서 컴파일되고 링크됩니다. 비트 코드를 포함하면 Apple은 새로운 버전의 앱을 스토어에 제출할 필요없이 향후 앱 바이너리를 다시 최적화 할 수 있습니다.
업데이트 : "Xcode 7의 새로운 기능"에 나오는이 문구는 슬라이싱 에 앱 크기를 줄이기 위해 Bitcode 가 오랫동안 필요 하다고 생각했습니다 .
App Store에 제출하기 위해 보관할 때 Xcode는 앱을 중간 표현으로 컴파일합니다. 그런 다음 App Store는 필요에 따라 비트 코드를 64 또는 32 비트 실행 파일로 컴파일합니다.
그러나 사실은 아닙니다. 비트 코드 와 슬라이싱 은 독립적으로 작동합니다. 슬라이스 는 앱 크기를 줄이고 앱 번들 변형을 생성하는 것이며 비트 코드 는 특정 이진 최적화를위한 것입니다. 비트 코드가 아닌 앱의 실행 파일에 포함 된 아키텍처를 확인하고 필요한 아키텍처 만 포함 함을 확인하여이를 확인했습니다.
비트 코드를 사용하면 슬라이싱 이라는 다른 App Thinning 구성 요소 가 특정 아키텍처에 대한 특정 실행 파일로 앱 번들 변형을 생성 할 수 있습니다. 예를 들어 iPhone 5S 변형에는 arm64 실행 파일, iPad Mini armv7 등 만 포함됩니다.
iOS 앱의 경우 비트 코드가 기본값이지만 선택 사항입니다. 비트 코드를 제공하는 경우 앱 번들의 모든 앱 및 프레임 워크에 비트 코드가 포함되어야합니다. watchOS 및 tvOS 앱의 경우 비트 코드가 필요합니다.
Xcode 7 참조에서 :
이 설정을 활성화하면 대상 또는 프로젝트가이를 지원하는 플랫폼 및 아키텍처의 컴파일 중에 비트 코드를 생성해야 함을 나타냅니다. 보관 빌드의 경우 비트 코드는 연결된 바이너리에 생성되어 앱 스토어에 제출됩니다. 다른 빌드의 경우 컴파일러와 링커는 코드가 비트 코드 생성 요구 사항을 준수하는지 확인하지만 실제 비트 코드는 생성하지 않습니다.
다음은 Bitcode에 대한 심층적 인 이해에 도움이되는 몇 가지 링크입니다 .
정확한 질문은 "비트 코드를 가능하게하는 것"이므로 지금까지 알아 낸 몇 가지 간단한 기술적 세부 사항을 제공하고자합니다. 애플이이 컴파일러에 대한 소스 코드를 공개 할 때까지 100 % 확실하게 파악하는 것은 사실상 불가능하다
첫째, 애플의 비트 코드는하지 않습니다 표시 LLVM 바이트 코드와 같은 일이 될 수 있습니다. 적어도 나는 그들 사이의 어떤 유사점도 알 수 없었습니다. 독점 헤더 (항상 "xar!"로 시작)와 데이터 복제를 방지하는 링크 타임 참조 매직이있는 것으로 보입니다. 하드 코딩 된 문자열을 작성하는 경우이 문자열은 정상적인 LLVM 바이트 코드 인 경우 예상되는 것보다 두 번이 아니라 한 번만 데이터에 저장됩니다.
둘째, 비트 코드는 실제로 바이너리 아카이브에 별도의 아키텍처로 제공되지는 않습니다. x86 및 ARM이 하나의 이진 (FAT 아카이브)에 저장되는 것과 같은 방식으로 제공되지 않습니다. 대신, 아키텍처가 지원되는 모든 아키텍처와 함께 제공되는 "__LLVM"이라는 아키텍처 특정 MachO 바이너리의 특수 섹션을 사용합니다 (예 : 복제). 필자는 이것이 컴파일러 시스템과 함께 제공되며 복제를 피하기 위해 향후에 수정 될 수 있다고 가정합니다.
C 코드 (로 컴파일 clang -fembed-bitcode hi.c -S -emit-llvm
) :
#include <stdio.h>
int main() {
printf("hi there!");
return 0;
}
LLVM IR 출력 :
; ModuleID = '/var/folders/rd/sv6v2_f50nzbrn4f64gnd4gh0000gq/T/hi-a8c16c.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 [10 x i8] c"hi there!\00", align 1
@llvm.embedded.module = appending constant [1600 x i8] c"\DE\C0\17\0B\00\00\00\00\14\00\00\00$\06\00\00\07\00\00\01BC\C0\DE!\0C\00\00\86\01\00\00\0B\82 \00\02\00\00\00\12\00\00\00\07\81#\91A\C8\04I\06\1029\92\01\84\0C%\05\08\19\1E\04\8Bb\80\10E\02B\92\0BB\84\102\148\08\18I\0A2D$H\0A\90!#\C4R\80\0C\19!r$\07\C8\08\11b\A8\A0\A8@\C6\F0\01\00\00\00Q\18\00\00\C7\00\00\00\1Bp$\F8\FF\FF\FF\FF\01\90\00\0D\08\03\82\1D\CAa\1E\E6\A1\0D\E0A\1E\CAa\1C\D2a\1E\CA\A1\0D\CC\01\1E\DA!\1C\C8\010\87p`\87y(\07\80p\87wh\03s\90\87ph\87rh\03xx\87tp\07z(\07yh\83r`\87th\07\80\1E\E4\A1\1E\CA\01\18\DC\E1\1D\DA\C0\1C\E4!\1C\DA\A1\1C\DA\00\1E\DE!\1D\DC\81\1E\CAA\1E\DA\A0\1C\D8!\1D\DA\A1\0D\DC\E1\1D\DC\A1\0D\D8\A1\1C\C2\C1\1C\00\C2\1D\DE\A1\0D\D2\C1\1D\CCa\1E\DA\C0\1C\E0\A1\0D\DA!\1C\E8\01\1D\00s\08\07v\98\87r\00\08wx\876p\87pp\87yh\03s\80\876h\87p\A0\07t\00\CC!\1C\D8a\1E\CA\01 \E6\81\1E\C2a\1C\D6\A1\0D\E0A\1E\DE\81\1E\CAa\1C\E8\E1\1D\E4\A1\0D\C4\A1\1E\CC\C1\1C\CAA\1E\DA`\1E\D2A\1F\CA\01\C0\03\80\A0\87p\90\87s(\07zh\83q\80\87z\00\C6\E1\1D\E4\A1\1C\E4\00 \E8!\1C\E4\E1\1C\CA\81\1E\DA\C0\1C\CA!\1C\E8\A1\1E\E4\A1\1C\E6\01X\83y\98\87y(\879`\835\18\07|\88\03;`\835\98\87y(\076X\83y\98\87r\90\036X\83y\98\87r\98\03\80\A8\07w\98\87p0\87rh\03s\80\876h\87p\A0\07t\00\CC!\1C\D8a\1E\CA\01 \EAa\1E\CA\A1\0D\E6\E1\1D\CC\81\1E\DA\C0\1C\D8\E1\1D\C2\81\1E\00s\08\07v\98\87r\006\C8\88\F0\FF\FF\FF\FF\03\C1\0E\E50\0F\F3\D0\06\F0 \0F\E50\0E\E90\0F\E5\D0\06\E6\00\0F\ED\10\0E\E4\00\98C8\B0\C3<\94\03@\B8\C3;\B4\819\C8C8\B4C9\B4\01<\BCC:\B8\03=\94\83<\B4A9\B0C:\B4\03@\0F\F2P\0F\E5\00\0C\EE\F0\0Em`\0E\F2\10\0E\EDP\0Em\00\0F\EF\90\0E\EE@\0F\E5 \0FmP\0E\EC\90\0E\ED\D0\06\EE\F0\0E\EE\D0\06\ECP\0E\E1`\0E\00\E1\0E\EF\D0\06\E9\E0\0E\E60\0Fm`\0E\F0\D0\06\ED\10\0E\F4\80\0E\809\84\03;\CCC9\00\84;\BCC\1B\B8C8\B8\C3<\B4\819\C0C\1B\B4C8\D0\03:\00\E6\10\0E\EC0\0F\E5\00\10\F3@\0F\E10\0E\EB\D0\06\F0 \0F\EF@\0F\E50\0E\F4\F0\0E\F2\D0\06\E2P\0F\E6`\0E\E5 \0Fm0\0F\E9\A0\0F\E5\00\E0\01@\D0C8\C8\C39\94\03=\B4\C18\C0C=\00\E3\F0\0E\F2P\0Er\00\10\F4\10\0E\F2p\0E\E5@\0Fm`\0E\E5\10\0E\F4P\0F\F2P\0E\F3\00\AC\C1<\CC\C3<\94\C3\1C\B0\C1\1A\8C\03>\C4\81\1D\B0\C1\1A\CC\C3<\94\03\1B\AC\C1<\CCC9\C8\01\1B\AC\C1<\CCC9\CC\01@\D4\83;\CCC8\98C9\B4\819\C0C\1B\B4C8\D0\03:\00\E6\10\0E\EC0\0F\E5\00\10\F50\0F\E5\D0\06\F3\F0\0E\E6@\0Fm`\0E\EC\F0\0E\E1@\0F\809\84\03;\CCC9\00\00I\18\00\00\02\00\00\00\13\82`B \00\00\00\89 \00\00\0D\00\00\002\22\08\09 d\85\04\13\22\A4\84\04\13\22\E3\84\A1\90\14\12L\88\8C\0B\84\84L\100s\04H*\00\C5\1C\01\18\94`\88\08\AA0F7\10@3\02\00\134|\C0\03;\F8\05;\A0\836\08\07x\80\07v(\876h\87p\18\87w\98\07|\88\038p\838\80\037\80\83\0DeP\0Em\D0\0Ez\F0\0Em\90\0Ev@\07z`\07t\D0\06\E6\80\07p\A0\07q \07x\D0\06\EE\80\07z\10\07v\A0\07s \07z`\07t\D0\06\B3\10\07r\80\07:\0FDH #EB\80\1D\8C\10\18I\00\00@\00\00\C0\10\A7\00\00 \00\00\00\00\00\00\00\868\08\10\00\02\00\00\00\00\00\00\90\05\02\00\00\08\00\00\002\1E\98\0C\19\11L\90\8C\09&G\C6\04C\9A\22(\01\0AM\D0i\10\1D]\96\97C\00\00\00y\18\00\00\1C\00\00\00\1A\03L\90F\02\134A\18\08&PIC Level\13\84a\D80\04\C2\C05\08\82\83c+\03ab\B2j\02\B1+\93\9BK{s\03\B9q\81q\81\01A\19c\0Bs;k\B9\81\81q\81q\A9\99q\99I\D9\10\14\8D\D8\D8\EC\DA\5C\DA\DE\C8\EA\D8\CA\5C\CC\D8\C2\CE\E6\A6\04C\1566\BB6\974\B227\BA)A\01\00y\18\00\002\00\00\003\08\80\1C\C4\E1\1Cf\14\01=\88C8\84\C3\8CB\80\07yx\07s\98q\0C\E6\00\0F\ED\10\0E\F4\80\0E3\0CB\1E\C2\C1\1D\CE\A1\1Cf0\05=\88C8\84\83\1B\CC\03=\C8C=\8C\03=\CCx\8Ctp\07{\08\07yH\87pp\07zp\03vx\87p \87\19\CC\11\0E\EC\90\0E\E10\0Fn0\0F\E3\F0\0E\F0P\0E3\10\C4\1D\DE!\1C\D8!\1D\C2a\1Ef0\89;\BC\83;\D0C9\B4\03<\BC\83<\84\03;\CC\F0\14v`\07{h\077h\87rh\077\80\87p\90\87p`\07v(\07v\F8\05vx\87w\80\87_\08\87q\18\87r\98\87y\98\81,\EE\F0\0E\EE\E0\0E\F5\C0\0E\EC\00q \00\00\05\00\00\00&`<\11\D2L\85\05\10\0C\804\06@\F8\D2\14\01\00\00a \00\00\0B\00\00\00\13\04A,\10\00\00\00\03\00\00\004#\00dC\19\020\18\83\01\003\11\CA@\0C\83\11\C1\00\00#\06\04\00\1CB\12\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", section "__LLVM,__bitcode"
@llvm.cmdline = appending constant [67 x i8] c"-triple\00x86_64-apple-macosx10.10.0\00-emit-llvm\00-disable-llvm-optzns\00", section "__LLVM,__cmdline"
; 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 ([10 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.53.3)"}
IR에있는 데이터 배열도 clang의 최적화 및 기타 코드 생성 설정에 따라 변경됩니다. 이것이 어떤 형식 또는 어떤 형식인지 전혀 알 수 없습니다.
편집하다:
트위터의 힌트에 따라, 나는 이것을 다시 확인하고 확인하기로 결정했습니다. 필자는 이 블로그 게시물을 따르고 그의 비트 코드 추출기 도구를 사용하여 MachO 실행 파일에서 Apple Archive 바이너리를 가져 왔습니다. 그리고 xar 유틸리티로 Apple Archive를 추출한 후 이것을 얻었습니다 (물론 llvm-dis를 사용하여 텍스트로 변환)
; ModuleID = '1'
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 [10 x i8] c"hi there!\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 ([10 x i8], [10 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.1.76)"}
비 비트 코드 IR과 비트 코드 IR의 유일한 차이점은 파일 이름이 각 아키텍처마다 1, 2 등으로 스트립되었다는 것입니다.
또한 바이너리에 포함 된 비트 코드가 최적화 후 생성되었음을 확인했습니다. -O3으로 컴파일하고 비트 코드를 추출하면 -O0으로 컴파일하는 것과 다릅니다.
또한 추가 크레딧을 얻기 위해 iOS 9 앱을 다운로드 할 때 Apple이 기기에 비트 코드를 제공하지 않는다는 것을 확인했습니다. 여기에는 __LINKEDIT와 같이 인식되지 않는 다른 이상한 섹션이 포함되어 있지만 __LLVM .__ bundle은 포함되어 있지 않으므로 장치에서 실행되는 최종 바이너리에 비트 코드가 포함되지 않은 것으로 보입니다. 이상하게도, 애플은 여전히 팻 바이너리를 별도의 32/64 비트 코드와 함께 iOS 8 기기에 제공합니다.
xar!
애플의 아카이브 파일 형식입니다.
비트 코드 (iOS, watchOS)
비트 코드는 컴파일 된 프로그램의 중간 표현입니다. 비트 코드가 포함 된 iTunes Connect에 업로드 한 앱은 App Store에서 컴파일되고 링크됩니다. 비트 코드를 포함하면 Apple은 새로운 버전의 앱을 스토어에 제출할 필요없이 향후 앱 바이너리를 다시 최적화 할 수 있습니다.
기본적 으로이 개념은 바이트 코드가 다른 JVM에서 실행되는 Java와 다소 유사 하며이 경우 비트 코드는 iTune 저장소에 배치되며 중간 코드를 다른 플랫폼 (장치)에 제공하는 대신 필요하지 않은 컴파일 된 코드를 제공합니다 실행할 가상 머신
따라서 비트 코드를 한 번 작성해야하며 기존 또는 향후 장치에서 사용할 수 있습니다. 각 플랫폼과 호환되도록 컴파일하는 것은 Apple의 골치 아픈 일입니다.
개발자는 새로운 플랫폼을 지원하기 위해 변경하거나 앱을 다시 제출할 필요가 없습니다.
애플이 x64
칩을 도입했을 때 아이폰 5 의 예를 들어 보자 . 하지만 x86
애플 리케이션과 완전히 호환 있었다 x64
아키텍처하지만 완전히 활용하는 x64
플랫폼을 개발자는 아키텍처 또는 일부 코드를 변경해야합니다. 완료되면 앱이 검토를 위해 앱 스토어에 제출됩니다.
이 비트 코드 개념이 이전에 시작된 경우 개발자는 x64
비트 아키텍처 를 지원하기 위해 변경할 필요가 없습니다 .
최신 정보
애플은 슬라이싱이 비트 코드 활성화와 무관하게 발생한다고 밝혔습니다. 비트 코드를 사용하지 않는 앱이 대상 장치에 적합한 아키텍처로만 다운로드되는 곳에서도 실제로 이것을 관찰했습니다.
실물
더 구체적으로 :
비트 코드. 앱 스토어에 제출할 수 있도록 앱을 중간 표현으로 보관합니다. 제공되는 대상 장치에 대해 64 비트 또는 32 비트 실행 파일로 컴파일됩니다.
슬라이싱. 자산 카탈로그에 통합되고 플랫폼에 태그가 지정된 아트 워크를 통해 App Store는 설치에 필요한 항목 만 제공 할 수 있습니다.
내가 읽는 방식으로 비트 코드를 지원하면 앱 다운로더는 자신의 장치에 필요한 컴파일 된 아키텍처 만 가져옵니다.