Home | History | Annotate | Download | only in check-armeabi-v7a-prebuilts
      1 #!/bin/sh
      2 
      3 # The purpose of this dummy build test is to ensure that all the
      4 # armeabi-v7a prebuilt binaries distributed with the NDK were
      5 # properly built targetting VFPv3-D16, as per the ABI spec.
      6 #
      7 # For a related bug, see http://code.google.com/p/android/issues/detail?id=26199
      8 #
      9 
     10 #
     11 # $1: ELF binary
     12 # $2: Tag name (e.g. Tag_CPU_name)
     13 #
     14 extract_arch_tag ()
     15 {
     16     echo $(readelf -A "$1" | awk '$1 == "'$2':" { print $2; }' | sort -u | tr '\n' ' ')
     17 }
     18 
     19 # Returns success only if a file is a static object or library.
     20 # We simply check the suffix, which must be either .a or .o
     21 # $1: file name
     22 is_static_file ()
     23 {
     24     case $1 in
     25         *.o|*.a)
     26             return 0
     27             ;;
     28     esac
     29     return 1
     30 }
     31 
     32 
     33 #
     34 # WARNING: VERY IMPORTANT TECHNICAL NOTE:
     35 #
     36 # The function below works by inspecting the architecture-specific
     37 # attributes in an ELF file. Please be aware that the behaviour of
     38 # binutils-2.19 and binutils-2.21 is different when generating these
     39 # tags.
     40 #
     41 # 1/ When compiling for ARMv7-A targets, one can use any of the following
     42 #    labels for the -mfpu=<name> option:
     43 #
     44 #        vfp
     45 #        vfpv3
     46 #        vfpv3-d16
     47 #        neon
     48 #
     49 # 2/ There are two VFPv3 architectures defined by ARM:
     50 #
     51 #        VFPv3-D16  -> Mandates only 16 double FPU registers (d0-d15)
     52 #        VFPv3-D32  -> Mandates 32 double FPU registers (d0-d31)
     53 #
     54 #    In addition, NEON requires VFPv3-D32
     55 #
     56 #    There is also VFPv2, which is an earlier version of VFPv3. Technically
     57 #    speaking, VFPv3 is not completely backwards compatible with VFPv2 because
     58 #    there are a few VFPv2 instructions it doesn't support.
     59 #
     60 # 3/ The table below indicates, for each -mfpu label, the following:
     61 #
     62 #     - The value of the 'Tag_VFP_arch' attribute that will be placed in
     63 #       the generated object files or binaries (you can list them with
     64 #       'readelf -A <file>')
     65 #
     66 #     - Whether the generated code uses 16 or 32 FPU double registers
     67 #       (this is checked by looking at the disassembly of libgnustl_shared.so,
     68 #       more specifically functions like 'cosf' or 'sinf' inside it).
     69 #
     70 #  First, for binutils-2.19:
     71 #
     72 #     fpu value           EABI tag          FPU reg count
     73 #    -----------------------------------------------------
     74 #       vfp                 VFPv2            16
     75 #       vfpv3               VFPv3-D16        32 (*)
     76 #       vfpv3-d16           VFPv3            16 (*)
     77 #       neon                VFPv3            32
     78 #
     79 #  And now for binutils-2.21
     80 #
     81 #     fpu value           EABI tag          FPU reg count
     82 #    -----------------------------------------------------
     83 #       vfp                 VFPv2            16
     84 #       vfpv3               VFPv3            32
     85 #       vfpv3-d16           VFPv3-D16        16
     86 #       neon                VFPv3            32
     87 #
     88 #  This shows that:
     89 #
     90 #    - The 'VFPv3' tag seems to match VFPv3-D32 exclusively on 2.21,
     91 #      but is a mess with 2.19
     92 #
     93 #    - Similarly, the 'vfpv3' value seems to match VFPv3-D32 as well,
     94 #      with the exception that binutils-2.19 is buggy and will put an
     95 #      invalid tag (VFPv3-D16, instead of VFPv3) in the generate ELF file.
     96 #
     97 #    - binutils 2.19 puts the wrong tag in the executable for vfpv3 and
     98 #      vfpv3-d16, then should probably be inverted!
     99 #
    100 #  The end result is that we can't use the EABI tag to determine the number
    101 #  of hardware FPU registers that are really used by the machine code with
    102 #  binutils 2.19 :-(
    103 #
    104 #  BONUS:
    105 #
    106 #    - When using 'neon', binutils-2.21 will also add a new tag named
    107 #      'Tag_Advanced_SIMD_arch' with value 'NEONv1'. Sadly, binutils-2.19
    108 #      doesn't do any of this.
    109 #
    110 
    111 # Check that an ELF binary is compatible with our armeabi-v7a ABI
    112 # (i.e. no NEON, and only 16 hardware registers being used).
    113 #
    114 # See technical note above to understand how this currently works.
    115 # We're still assuming the toolchain is built with the buggy binutils-2.19.
    116 #
    117 # $1: path to an ARMv7-A ELF binary (static lib, shared lib or executable)
    118 #
    119 check_armv7_elf_binary ()
    120 {
    121     # We use a small awk script to parse the output of 'readelf -A'
    122     # Which typically looks like:
    123     #
    124     # Attribute Section: aeabi
    125     #   File Attributes
    126     #   Tag_CPU_name: "7-A"
    127     #   Tag_CPU_arch: v7
    128     #   Tag_CPU_arch_profile: Application
    129     #   Tag_ARM_ISA_use: Yes
    130     #   Tag_THUMB_ISA_use: Thumb-2
    131     #   Tag_VFP_arch: VFPv3-D16
    132     #   Tag_ABI_PCS_wchar_t: 4
    133     #   Tag_ABI_FP_denormal: Needed
    134     #   Tag_ABI_FP_exceptions: Needed
    135     #   Tag_ABI_FP_number_model: IEEE 754
    136     #   Tag_ABI_align8_needed: Yes
    137     #   Tag_ABI_align8_preserved: Yes, except leaf SP
    138     #   Tag_ABI_enum_size: int
    139     #   Tag_ABI_HardFP_use: SP and DP
    140     #   Tag_ABI_optimization_goals: Aggressive Speed
    141     #   Tag_unknown_44: 1 (0x1)
    142     #
    143     # Note that for static libraries, these sections will appear multiple
    144     # time in the output of 'readelf -A'.
    145 
    146     echo "Checking: $(basename $1)"
    147     if [ ! -f "$1" ]; then
    148         1>&2 echo "PANIC: Missing binary: $1"
    149         exit 1
    150     fi
    151 
    152     # We want to check the values of Tag_CPU_name
    153     CPU_NAMES=$(extract_arch_tag "$1" Tag_CPU_name)
    154     VFP_ARCHS=$(extract_arch_tag "$1" Tag_VFP_arch)
    155     NEON_ARCHS=$(extract_arch_tag "$1" Tag_Advanced_SIMD_arch)
    156 
    157     # IMPORTANT NOTE: Even when using -march=armv7-a, the compiler may not
    158     # necessarily use ARMv7-A specific instruction and will tag an object file
    159     # with the following attributes:
    160     #
    161     # Attribute Section: aeabi
    162     #   File Attributes
    163     #   Tag_CPU_name: "5TE"
    164     #   Tag_CPU_arch: v5TE
    165     #   Tag_ARM_ISA_use: Yes
    166     #   Tag_THUMB_ISA_use: Thumb-1
    167     #   Tag_ABI_PCS_wchar_t: 4
    168     #   Tag_ABI_FP_denormal: Needed
    169     #   Tag_ABI_FP_exceptions: Needed
    170     #   Tag_ABI_FP_number_model: IEEE 754
    171     #   Tag_ABI_align8_needed: Yes
    172     #   Tag_ABI_align8_preserved: Yes, except leaf SP
    173     #   Tag_ABI_enum_size: int
    174     #   Tag_ABI_optimization_goals: Aggressive Speed
    175     #   Tag_unknown_44: 1 (0x1)
    176     #
    177     # This means that in static libraries, you can have both
    178     # '5TE' and '7-A' CPU name tags at the same time, or only
    179     # '5TE' or only '7-A', deal with all these cases properly.
    180 
    181     echo "  found tags: CPU names:'$CPU_NAMES' VFP:'$VFP_ARCHS' NEON:'$NEON_ARCHS'"
    182 
    183     # Clearly, any trace of NEON is a deal-breaker!
    184     if [ "$NEON_ARCHS" ]; then
    185         1>&2 echo "PANIC: Binary file should not contain NEON instructions: $1"
    186         exit 1
    187     fi
    188 
    189     if is_static_file "$1"; then
    190         # For static libraries / object files, it's ok to contain ARMv5TE binaries
    191         if [ "$CPU_NAMES" == "\"5TE\"" -a "$CPU_NAMES" != "\"7-A\"" -a "$CPU_NAMES" != "\"5TE\" \"7-A\"" ]; then
    192             # Neither ARMv7-A or ARMv5TE+ARMv7-A, something's fishy
    193             1>&2 echo "PANIC: File is neither ARMv5TE or ARMv7-A binary: $1"
    194             exit 1
    195         fi
    196 
    197         # exit here because some static libraries can have a mix of several
    198         # VFP tags that make them difficult to check (e.g. libgnustl_static.a
    199         # can have 'VFPv1 VFPv2 VFPv3' at the same time :-(
    200         return
    201     fi
    202 
    203     # If we reach this point, we only contain ARMv7-A machine code, so look
    204     # at the VFP arch tag(s)
    205 
    206     # Sometimes no VFP_arch tag is placed in the final binary, this happens
    207     # with libgabi++_shared.so for example, because the code doesn't have
    208     # any floating point instructions.
    209     #
    210 
    211     # XXX: FOR NOW, ASSUME BROKEN binutils-2.19, AND THUS THAT 'VFPv3' IS VALID
    212 
    213     if [ "$VFP_ARCHS" != "VFPv3" -a "$VFP_ARCHS" != "VFPv3-D16" -a "$VFP_ARCHS" != "" ]; then
    214         1>&2 echo "PANIC: File is not a VFPv3-D16 binary: $1"
    215         exit 1
    216     fi
    217 }
    218 
    219 GABIXX_LIBS=$NDK/sources/cxx-stl/gabi++/libs/armeabi-v7a
    220 
    221 check_armv7_elf_binary $GABIXX_LIBS/libgabi++_shared.so
    222 check_armv7_elf_binary $GABIXX_LIBS/libgabi++_static.a
    223 
    224 STLPORT_LIBS=$NDK/sources/cxx-stl/stlport/libs/armeabi-v7a
    225 
    226 check_armv7_elf_binary $STLPORT_LIBS/libstlport_shared.so
    227 check_armv7_elf_binary $STLPORT_LIBS/libstlport_static.a
    228 
    229 . $NDK/build/tools/dev-defaults.sh
    230 
    231 for VERSION in $DEFAULT_GCC_VERSION_LIST; do
    232     GNUSTL_LIBS=$NDK/sources/cxx-stl/gnu-libstdc++/$VERSION/libs/armeabi-v7a
    233     check_armv7_elf_binary $GNUSTL_LIBS/libsupc++.a
    234     check_armv7_elf_binary $GNUSTL_LIBS/libgnustl_shared.so
    235     check_armv7_elf_binary $GNUSTL_LIBS/libgnustl_static.a
    236 done
    237 
    238 echo "Done!"
    239