Since 2015, Apple gives you the possibility to include bitcode in your iOS application or SDK. To dissipate the confusion surrounding bitcode, we have gathered the essential information in this blog. We cover the following topics: What is bitcode? What are bitcode-enabled builds? What does Apple do with the embedded bitcode? Are there security implications to embedding bitcode?
To understand what bitcode is, we need to take a step back and look at the process of compiling. A compiler is a program that processes human-readable source code and converts it into machine code, that is code a computer or mobile device can read and execute.
The process of compiling consists of three different steps:
The compiler front-end converts the source code into some kind of intermediate representation (IR).
The optimizer performs a sequence of optimizing transformations on the IR to render it smaller and more performant: redundant code is removed, results are precalculated, code is inlined, etc. This crucial step of the compilation process makes use of IR, rather than source code or machine code, because it can more easily be interpreted by the optimizer.
The compiler back-end generates machine code based on the optimized IR.
When we are talking about bitcode, we are actually talking about the IR used by the Clang compiler (or more accurately, about the representation on disk of this compiler’s IR). Clang is a widely used C/C++/Objective-C language family compiler that makes use of the LLVM framework. It is also the compiler that Apple uses in Xcode to compile iOS and macOS applications. You could say that bitcode is nothing new as it has always existed in the LLVM compiler framework.
At the same time, it is clear that something has changed. In 2015, Apple added the option to embed bitcode into applications compiled with Xcode. When this option is disabled, the compiler generates an executable file that only contains machine code.
But when it is enabled, the bitcode is included in the executable file alongside the generated machine code.
When executing an application that contains embedded bitcode, this bitcode is ignored and the application runs the machine code in exactly the same way as it would run an ordinary executable.
The question remains: why does Apple offer the option to embed bitcode? The answer is straightforward. With the bitcode embedded in the executable, Apple is able to recompile applications without interacting with the developer. This has a lot of advantages.
Apple is continuously enhancing the optimization performed by the Clang compiler to further improve the performance of mobile applications and reduce their size. Using the embedded bitcode, Apple itself can recompile applications using the latest, improved version of the compiler. This frees app developers from the burden of continuously having to update their development environment and recompile and reupload their applications to benefit from the latest improvements.
By embedding the bitcode, developers enable Apple to migrate their applications to new types of devices. The embedded bitcode enables Apple to recompile existing applications and make them compatible with the chipsets of new devices.
There has been some discussion about the security implications of embedding bitcode. The crucial piece of information here is that the bitcode is never sent to a mobile device. Apple stores the bitcode of your applications on its servers and uses it whenever it needs to, but strips it off before deploying the applications to the end user’s device. In other words, only Apple will ever have access to the bitcode. The end-user won’t even notice the difference between an application that initially contained bitcode and one that didn’t. Since the bitcode doesn’t leave Apple’s servers, enabling bitcode doesn’t have any security implications at all (unless you consider Apple itself as an adversary in your threat model).