alexrp’s blog

ramblings usually related to software

Android Hard Float Support

Stop the presses! The Android developers did something almost sane!

As of Android NDK revision 9c, the GCC and Clang included in the NDK can build programs for the hardware floating point ABI on ARM. This is basically a free performance boost for all floating point code.

Almost. There are some caveats that you need to be aware of. They didn’t add support for hard float by recompiling everything in user space; instead, hard float programs execute within a system that is technically soft float. What does that mean in practice?

First, to utilize the hard float ABI, you must either compile every last component of your application as hard float (the -mhard-float GCC/Clang switch), or mark individual functions with the appropriate __attribute__ to indicate the desired ABI. For example, to mark a function so that it’s called with the soft float ABI, stick __attribute__((pcs("aapcs"))) on it.

Note that the NDK will link to a libm which uses the aforementioned attribute on all of its functions. This means that if you use libm functions a lot, you’re not likely to get much of a boost in those places. The way to fix this is to add -mhard-float -D_NDK_MATH_NO_SOFTFP=1 to your GCC/Clang command line. Then add -lm_hard to your linker command line (or -Wl,-lm_hard if you just invoke GCC/Clang to link). This will make your application link statically to a libm compiled for the hard float ABI. The only downside of this is that your application will increase somewhat in size.

You will want to pass --no-warn-mismatch to the linker to silence all warnings about mixed floating point ABIs in objects. This is not ideal since it could actually be helpful in some cases, but it’s not great to see a ton of useless warnings either.

If you interact with any kind of FFI at all, such as JNI or P/Invoke, you’re in for a bad time. Due to the fact that user space is still technically soft float, VMs like Dalvik and Mono have absolutely no way of knowing whether a native function should be invoked as soft float or hard float. Dalvik ‘solves’ this by forcing all JNI functions to use soft float (ugh). Make sure to slap JNICALL on your JNI functions so they are marked as soft float - it seems a lot of code exists that doesn’t do this, and it will break if compiled for hard float.

Also, keep in mind that hard float (obviously) assumes the presence of an FPU. As such, it will only work on ARM v7 (armeabi-v7a in Android terms). It may work by chance on some armeabi devices, but don’t rely on that.

So what about Mono?

There’s no real story for Mono at the moment - we don’t have the liberty to force all native libraries to be recompiled with annotations to use the soft float ABI, and it would undermine the performance gain of the hard float ABI. We also have no way for users to mark native methods as soft or hard float and, besides, that would require recompiling a ton of code and adding special cases for hard float on ARM - not really acceptable for users. To make matters even worse, since the hard float support on Android isn’t a proper Android ABI (like armeabi, armeabi-v7a, mips, and x86), we can’t ask the C compiler which ABI we should be using when invoking native functions.

In short: We’re screwed.

If Mono is ever going to support hard float on Android, we need the Android developers to make it a first-class ABI, and not just a compatibility hack.

That being said, Mono does support hard float on regular Linux!