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