page.title=ABI Management @jd:body

On this page

  1. Supported ABIs
  2. Generating Code for a Specific ABI
  3. ABI Management on the Android Platform

Different Android handsets use different CPUs, which in turn support different instruction sets. Each combination of CPU and instruction sets has its own Application Binary Interface, or ABI. The ABI defines, with great precision, how an application's machine code is supposed to interact with the system at runtime. You must specify an ABI for each CPU architecture you want your app to work with.

A typical ABI includes the following information:

This page enumerates the ABIs that the NDK supports, and provides information about how each ABI works.

Supported ABIs

Each ABI supports one or more instruction sets. Table 1 provides an at-a-glance overview of the instruction sets each ABI supports.

Table 1. ABIs and supported instruction sets.

ABI Supported Instruction Set(s) Notes
{@code armeabi}
  • ARMV5TE and later
  • Thumb-1
  • No hard float.
    {@code armeabi-v7a}
  • armeabi
  • Thumb-2
  • VFPv3-D16
  • Other, optional
  • Incompatible with ARMv5, v6 devices.
    {@code arm64-v8a}
  • AArch-64
  • {@code x86}
  • x86 (IA-32)
  • MMX
  • SSE/2/3
  • SSSE3
  • No support for MOVBE or SSE4.
    {@code x86_64}
  • x86-64
  • MMX
  • SSE/2/3
  • SSSE3
  • SSE4.1, 4.2
  • POPCNT
  • {@code mips}
  • MIPS32r1 and later
  • Uses hard-float, and assumes a CPU:FPU clock ratio of 2:1 for maximum compatibility. Provides neither micromips nor MIPS16.
    {@code mips64}
  • MIPS64r6
  • More detailed information about each ABI appears below.

    armeabi

    This ABI is for ARM-based CPUs that support at least the ARMv5TE instruction set. Please refer to the following documentation for more details:

    The AAPCS standard defines EABI as a family of similar but distinct ABIs. Also, Android follows the little-endian ARM GNU/Linux ABI.

    This ABI does not support hardware-assisted floating point computations. Instead, all floating-point operations use software helper functions from the compiler's {@code libgcc.a} static library.

    The armeabi ABI supports ARM’s Thumb (a.k.a. Thumb-1) instruction set. The NDK generates Thumb code by default unless you specify different behavior using the LOCAL_ARM_MODE variable in your {@code Android.mk} file.

    armeabi-v7a

    This ABI extends armeabi to include several CPU instruction set extensions. The instruction extensions that this Android-specific ABI supports are:

    Other extensions that the v7-a ARM spec describes, including Advanced SIMD (a.k.a. NEON), VFPv3-D32, and ThumbEE, are optional to this ABI. Since their presence is not guaranteed, the system should check at runtime whether the extensions are available. If they are not, you must use alternative code paths. This check is similar to the one that the system typically performs to check or use MMX, SSE2, and other specialized instruction sets on x86 CPUs.

    For information about how to perform these runtime checks, refer to The {@code cpufeatures} Library. Also, for information about the NDK's support for building machine code for NEON, see NEON Support.

    The {@code armeabi-v7a} ABI uses the {@code -mfloat-abi=softfp} switch to enforce the rule that the compiler must pass all double values in core register pairs during function calls, instead of dedicated floating-point ones. The system can perform all internal computations using the FP registers. Doing so speeds up the computations greatly.

    arm64-v8a

    This ABI is for ARMv8-based CPUs that support AArch64. It also includes the NEON and VFPv4 instruction sets.

    For more information, see the ARMv8 Technology Preview, and contact ARM for further details.

    x86

    This ABI is for CPUs supporting the instruction set commonly referred to as "x86" or "IA-32". Characteristics of this ABI include:

    The ABI does not include any other optional IA-32 instruction set extensions, such as:

    You can still use these extensions, as long as you use runtime feature-probing to enable them, and provide fallbacks for devices that do not support them.

    The NDK toolchain assumes 16-byte stack alignment before a function call. The default tools and options enforce this rule. If you are writing assembly code, you must make sure to maintain stack alignment, and ensure that other compilers also obey this rule.

    Refer to the following documents for more details:

    x86_64

    This ABI is for CPUs supporting the instruction set commonly referred to as "x86-64." It supports instructions that GCC typically generates with the following compiler flags:

    -march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel
    

    These flags target the x86-64 instruction set, according to the GCC documentation. along with the MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, and POPCNT instruction-set extensions. The generated code is an optimization balanced across the top Intel 64-bit CPUs.

    For more information on compiler flags, particularly related to performance optimization, refer to GCC x86 Performance.

    This ABI does not include any other optional x86-64 instruction set extensions, such as:

    You can still use these extensions, as long as you use runtime feature probing to enable them, and provide fallbacks for devices that do not support them.

    Refer to the following documents for more details:

    mips

    This ABI is for MIPS-based CPUs that support at least the MIPS32r1 instruction set. It includes the following features:

    For more information, please refer to the following documentation:

    For more specific details, see MIPS32 Architecture. Answers to common questions are in the MIPS FAQ.

    mips64

    This ABI is for MIPS64 R6. For more information, see MIPS64 Architecture.

    Generating Code for a Specific ABI

    By default, the NDK generates machine code for the armeabi ABI. You can generate ARMv7-a-compatible machine code, instead, by adding the following line to your {@code Application.mk} file.

    APP_ABI := armeabi-v7a
    

    To build machine code for two or more distinct ABIs, using spaces as delimiters. For example:

    APP_ABI := armeabi armeabi-v7a
    

    This setting tells the NDK to build two versions of your machine code: one for each ABI listed on this line. For more information on the values you can specify for the {@code APP_ABI} variable, see Android.mk.

    When you build multiple machine-code versions, the build system copies the libraries to your application project path, and ultimately packages them into your APK, so creating a fat binary. A fat binary is larger than one containing only the machine code for a single system; the tradeoff is gaining wider compatibility, but at the expense of a larger APK.

    At installation time, the package manager unpacks only the most appropriate machine code for the target device. For details, see Automatic extraction of native code at install time.

    ABI Management on the Android Platform

    This section provides details about how the Android platform manages native code in APKs.

    Native code in app packages

    Both the Play Store and Package Manager expect to find NDK-generated libraries on filepaths inside the APK matching the following pattern:

    /lib/<abi>/lib<name>.so
    

    Here, {@code } is one of the ABI names listed under Supported ABIs, and {@code } is the name of the library as you defined it for the {@code LOCAL_MODULE} variable in the {@code Android.mk} file. Since APK files are just zip files, it is trivial to open them and confirm that the shared native libraries are where they belong.

    If the system does not find the native shared libraries where it expects them, it cannot use them. In such a case, the app itself has to copy the libraries over, and then perform dlopen().

    In a fat binary, each library resides under a directory whose name matches a corresponding ABI. For example, a fat binary may contain:

    /lib/armeabi/libfoo.so
    /lib/armeabi-v7a/libfoo.so
    /lib/arm64-v8a/libfoo.so
    /lib/x86/libfoo.so
    /lib/x86_64/libfoo.so
    /lib/mips/libfoo.so
    /lib/mips64/libfoo.so
    

    Note: ARMv7-based Android devices running 4.0.3 or earlier install native libraries from the {@code armeabi} directory instead of the {@code armeabi-v7a} directory if both directories exist. This is because {@code /lib/armeabi/} comes after {@code /lib/armeabi-v7a/} in the APK. This issue is fixed from 4.0.4.

    Android Platform ABI support

    The Android system knows at runtime which ABI(s) it supports, because build-specific system properties indicate:

    This mechanism ensures that the system extracts the best machine code from the package at installation time.

    For best performance, you should compile directly for the primary ABI. For example, a typical ARMv5TE-based device would only define the primary ABI: {@code armeabi}. By contrast, a typical, ARMv7-based device would define the primary ABI as {@code armeabi-v7a} and the secondary one as {@code armeabi}, since it can run application native binaries generated for each of them.

    Many x86-based devices can also run {@code armeabi-v7a} and {@code armeabi} NDK binaries. For such devices, the primary ABI would be {@code x86}, and the second one, {@code armeabi-v7a}.

    A typical MIPS-based device only defines a primary abi: {@code mips}.

    Automatic extraction of native code at install time

    When installing an application, the package manager service scans the APK, and looks for any shared libraries of the form:

    lib/<primary-abi>/lib<name>.so
    

    If none is found, and you have defined a secondary ABI, the service scans for shared libraries of the form:

    lib/<secondary-abi>/lib<name>.so
    

    When it finds the libraries that it's looking for, the package manager copies them to /lib/lib<name>.so, under the application's {@code data} directory ({@code data/data//lib/}).

    If there is no shared-object file at all, the application builds and installs, but crashes at runtime.