Tengo un problema con el término de código de bits incrustado.
¿Qué es el código de bits incrustado?
¿Cuándo habilitar, ENABLE_BITCODE
en el nuevo Xcode?
¿Qué le sucede al binario cuando está habilitado, ENABLE_BITCODE
en Xcode 7?
Tengo un problema con el término de código de bits incrustado.
¿Qué es el código de bits incrustado?
¿Cuándo habilitar, ENABLE_BITCODE
en el nuevo Xcode?
¿Qué le sucede al binario cuando está habilitado, ENABLE_BITCODE
en Xcode 7?
Respuestas:
Bitcode se refiere al tipo de código: "LLVM Bitcode" que se envía a iTunes Connect. Esto le permite a Apple usar ciertos cálculos para volver a optimizar las aplicaciones (por ejemplo: posiblemente reducir el tamaño de los archivos ejecutables). Si Apple necesita alterar su ejecutable, puede hacerlo sin que se cargue una nueva compilación.
Esto difiere de: Slicing, que es el proceso de Apple para optimizar su aplicación para el dispositivo de un usuario en función de la resolución y la arquitectura del dispositivo. Rebanar no requiere Bitcode. (Ej: solo incluye imágenes @ 2x en un 5s)
App Thinning es la combinación de corte, código de bits y recursos a pedido
Bitcode es una representación intermedia de un programa compilado. Las aplicaciones que cargue en iTunes Connect que contengan código de bits se compilarán y vincularán en la App Store. La inclusión de código de bits permitirá a Apple volver a optimizar el binario de su aplicación en el futuro sin la necesidad de enviar una nueva versión de su aplicación a la tienda.
Según los documentos :
Bitcode es una representación intermedia de un programa compilado. Las aplicaciones que cargue en iTunes Connect que contengan código de bits se compilarán y vincularán en la App Store. La inclusión de código de bits permitirá a Apple volver a optimizar el binario de su aplicación en el futuro sin la necesidad de enviar una nueva versión de su aplicación a la tienda.
Actualización: esta frase en "Nuevas características en Xcode 7" me hizo pensar durante mucho tiempo que Bitcode es necesario para cortar para reducir el tamaño de la aplicación:
Cuando archiva para enviar a la App Store, Xcode compilará su aplicación en una representación intermedia. La App Store compilará el código de bits en los ejecutables de 64 o 32 bits según sea necesario.
Sin embargo eso no es verdad, código binario y rebanar trabajo de forma independiente: rebanar se trata de reducir el tamaño de aplicación y la generación de paquete de aplicación variantes, y código binario es acerca de ciertas optimizaciones binarios. He verificado esto comprobando las arquitecturas incluidas en los ejecutables de aplicaciones que no son de código de bits y descubriendo que solo incluyen las necesarias.
Bitcode permite que otro componente de reducción de aplicaciones llamado Slicing genere variantes de paquetes de aplicaciones con ejecutables particulares para arquitecturas particulares, por ejemplo, la variante de iPhone 5S incluirá solo el ejecutable arm64, iPad Mini armv7, etc.
Para las aplicaciones de iOS, el código de bits es el predeterminado, pero opcional. Si proporciona código de bits, todas las aplicaciones y marcos en el paquete de aplicaciones deben incluir código de bits. Para las aplicaciones watchOS y tvOS, se requiere un código de bits.
De la referencia Xcode 7:
La activación de esta configuración indica que el destino o proyecto debe generar código de bits durante la compilación para plataformas y arquitecturas que lo soportan. Para las compilaciones de archivo, el código de bits se generará en el binario vinculado para enviarlo a la tienda de aplicaciones. Para otras compilaciones, el compilador y el enlazador comprobarán si el código cumple con los requisitos para la generación de código de bits, pero no generará un código de bits real.
Aquí hay un par de enlaces que ayudarán a una comprensión más profunda de Bitcode :
Dado que la pregunta exacta es "¿qué hace el código de bits habilitado", me gustaría dar algunos detalles técnicos que he descubierto hasta ahora. La mayor parte de esto es prácticamente imposible de entender con 100% de certeza hasta que Apple publique el código fuente de este compilador
Primero, el código de bits de Apple no parece ser lo mismo que el código de bytes LLVM. Al menos, no he podido encontrar ningún parecido entre ellos. Parece tener un encabezado propietario (siempre comienza con "xar!") Y probablemente algo de magia de referencia de tiempo de enlace que evita las duplicaciones de datos. Si escribe una cadena codificada, esta cadena solo se colocará en los datos una vez, en lugar de dos veces como se esperaría si fuera un código de bytes LLVM normal.
En segundo lugar, el código de bits no se envía realmente en el archivo binario como una arquitectura separada como podría esperarse. No se envía de la misma manera que digamos x86 y ARM se colocan en un binario (archivo FAT). En su lugar, usan una sección especial en el binario MachO específico de la arquitectura llamada "__LLVM" que se envía con cada arquitectura compatible (es decir, duplicada). Supongo que esto es un inconveniente con su sistema de compilación y puede corregirse en el futuro para evitar la duplicación.
Código C (compilado con clang -fembed-bitcode hi.c -S -emit-llvm
):
#include <stdio.h>
int main() {
printf("hi there!");
return 0;
}
Salida IR LLVM:
; 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)"}
La matriz de datos que está en el IR también cambia según la optimización y otras configuraciones de generación de código de clang. Es completamente desconocido para mí en qué formato o cualquier cosa está esto.
EDITAR:
Siguiendo la pista en Twitter, decidí volver a visitar esto y confirmarlo. Seguí esta publicación de blog y usé su herramienta de extracción de código de bits para sacar el archivo binario de Apple Archive del ejecutable de MachO. Y después de extraer Apple Archive con la utilidad xar, obtuve esto (convertido a texto con llvm-dis, por supuesto)
; 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)"}
La única diferencia notable realmente entre el IR sin código de bits y el IR con código de bits es que los nombres de archivo se han eliminado a solo 1, 2, etc. para cada arquitectura.
También confirmó que el código de bits incrustado en un binario se genera después de las optimizaciones. Si compila con -O3 y extrae el código de bits, será diferente de si compila con -O0.
Y solo para obtener crédito adicional, también confirmó que Apple no envía código de bits a los dispositivos cuando descarga una aplicación iOS 9. Incluyen una serie de otras secciones extrañas que no reconocí como __LINKEDIT, pero no incluyen el paquete __LLVM .__ y, por lo tanto, no parecen incluir código de bits en el binario final que se ejecuta en un dispositivo. Por extraño que parezca, Apple todavía envía binarios gordos con código separado de 32/64 bits a dispositivos iOS 8.
xar!
es el formato de archivo de Apple.
Código de bits (iOS, watchOS)
Bitcode es una representación intermedia de un programa compilado. Las aplicaciones que cargue en iTunes Connect que contengan código de bits se compilarán y vincularán en la App Store. La inclusión de código de bits permitirá a Apple volver a optimizar el binario de su aplicación en el futuro sin la necesidad de enviar una nueva versión de su aplicación a la tienda.
Básicamente, este concepto es algo similar a Java, donde el código de bytes se ejecuta en diferentes JVM y, en este caso, el código de bits se coloca en la tienda iTune y, en lugar de proporcionar el código intermedio a diferentes plataformas (dispositivos), proporciona el código compilado que no necesita cualquier máquina virtual para ejecutar.
Por lo tanto, necesitamos crear el código de bits una vez y estará disponible para dispositivos existentes o futuros. Es el dolor de cabeza de Apple compilar y hacer que sea compatible con cada plataforma que tengan.
Los desarrolladores no tienen que hacer cambios y enviar la aplicación nuevamente para admitir nuevas plataformas.
Tomemos el ejemplo del iPhone 5s cuando Apple introdujo el x64
chip en él. Aunque las x86
aplicaciones eran totalmente compatibles con la x64
arquitectura, pero para utilizar completamente la x64
plataforma, el desarrollador tiene que cambiar la arquitectura o algún código. Una vez que haya terminado, la aplicación se envía a la tienda de aplicaciones para su revisión.
Si este concepto de código de bits se lanzó anteriormente, entonces los desarrolladores no tenemos que hacer ningún cambio para admitir la x64
arquitectura de bits.
Actualizar
Apple ha aclarado que el corte se produce independientemente de habilitar el código de bits. También he observado esto en la práctica, donde una aplicación sin código de bits solo se descargará como la arquitectura adecuada para el dispositivo de destino.
Original
Bitcode Archive su aplicación para enviarla a la App Store en una representación intermedia, que se compila en ejecutables de 64 o 32 bits para los dispositivos de destino cuando se entregan.
Rebanar Las ilustraciones incorporadas en el Catálogo de activos y etiquetadas para una plataforma permiten que la App Store entregue solo lo que se necesita para la instalación.
La forma en que leí esto, si admite código de bits, los descargadores de su aplicación solo obtendrán la arquitectura compilada necesaria para su propio dispositivo.