19

I've been trying to decypher for a while now what the status is of inline assembly on the various platforms since Apple announced bitcode.

As of right now (Xcode 7.1.1) this is what I observe:

  • OSX - allowed (I expect will always)
  • iOS - allowed, even with bitcode (inline assembly is put into the bitcode) with probable confirmation
  • watchOS - not allowed (won't compile, gives inline assembly is disabled error)
  • tvOS - allowed

However, these are dubious conclusions since I don't have apps on every market to verify this.

I've seen some posts from open source libraries and apps that iOS apps will be rejected when containing inline assembly and bitcode. I've seen some posts that tvOS is similar to watchOS and won't let you use inline assembly (maybe fixed in latest Xcode?)

Is there some solid reference from Apple or.. ANYWHERE as to what platforms I can use inline assembly on?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Earlz
  • 62,085
  • 98
  • 303
  • 499

1 Answers1

9

On any ARM platform (iOS, watchOS, tvOS), if you provide a mixed bitcode/asm archive, it can ONLY (see details below) be compiled for the same architecture as the embedded asm. This means that you might just as well submit a full binary application targeted at that architecture - there is absolutely no advantage to submitting bitcode (and therefore no reason for Apple to allow it).

As per Apple docs bitcode is required for watchOS and tvOS - and therefore inline assembly is disabled.

Note: For iOS apps, bitcode is the default, but optional. For watchOS and tvOS apps, bitcode is required. If you provide bitcode, all apps and frameworks in the app bundle (all targets in the project) need to include bitcode. After you distribute your app using iTunes Connect, you can download the dSYMs file for the build, described in Viewing and Importing Crashes in the Devices Window.

On X86, an archive containing a mixture of bitcode and X86 ASM can be compiled into a 64-bit application. It's not obvious that this is a sensible thing to do, because presumably the hand-crafted assembler is the performance critical section - but it can work.

The same is not true on ARM. The X86 case works because the X86 instruction set is a pure subset of X86_64 meaning that any X86 assembler is valid X86_64 assembler. On ARM a 64-bit processor needs to run in 32-bit state to execute 32-bit code. You cannot mix 32 and 64-bit assembly in the same application, as per the ARM docs (see Changing Execution State)

...Practically speaking, this means that you cannot have a mixed 32-bit and 64-bit application, because there is no direct way of calling between them.

This means that if you provide a mixture of bitcode plus inline asm targeting ARM architecture ARCH, practically the only thing that the AppStore can do (at least at present) is compile your bitcode for ARCH, which gives you (say) a fully 32 bit application running on a 64-bit processor. What's the point? It would be much simpler to upload a normal 32-bit executable with no bitcode in the first place.

Sevle
  • 3,109
  • 2
  • 19
  • 31
Airsource Ltd
  • 32,379
  • 13
  • 71
  • 75
  • I think I get what you're trying to say, but "disassembly of the source code" is clear as mud. Disassembly is the process of converting object code to assembly code. You might want to edit that section to clarify. – Caleb Nov 17 '15 at 19:42
  • 1
    This is not true, inline assembly perfectly capable of being put into LLVM IR and thus Apple's bitcode. Try putting some inline assembly in a program and seeing what clang outputs with `-S -emit-llvm`.. It'll end up looking similar to `call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #2, !srcloc !2` – Earlz Nov 17 '15 at 20:16
  • @Earlz - thank you for the example, but as you can see, it's still embedding inline assembly, not converting it back into 100% bitcode, which is what Apple want you to use. However I can see that the first line of my reply is a bit ambiguous in what I mean, and I will change it. – Airsource Ltd Nov 18 '15 at 10:15
  • @AirsourceLtd: the point is, having a few snippets of inline asm doesn't stop the rest of the app from being re-generated for new instruction set extensions. Just like compiling C source code that uses inline asm with `-march=native`, the inline-asm parts will stay the same, but everything else will potentially benefit. So this is fine in the typical case where almost all the code is *not* inline asm, and the new instruction set extensions don't enable something much better than what the inline asm does. – Peter Cordes Nov 19 '15 at 15:46
  • @PeterCordes - but if you do that, how does the AppStore know that what you have provided actually works on all processors? If you provide ARM32 code that can't run on ARM64, then what is going to happen? Dump the cache and switch execution mode every time it enters and exits your code block? The point of inline assembly is performance. Making part of your app architecture-dependent and the rest architecture-independent only works if you get to choose different code blocks for different architectures - and you don't... – Airsource Ltd Nov 19 '15 at 20:00
  • @AirsourceLtd: oh yeah, you're right. I was just thinking of the single-arch with extensions case. You'd need some facility for conditional use of asm. Maybe if you branch on a variable to select between versions of a hand-written asm function, then once this variable is a compile-time constant when the target arch is known, the branch could optimize away... (Like a CPU-dispatcher. Maybe set some function pointers at app startup, then call your functions through those pointers.) Except asm for the wrong arch won't even **compile**, let alone run. :( – Peter Cordes Nov 19 '15 at 23:51