277 lines
9 KiB
Bash
Executable file
277 lines
9 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
# The purpose of this dummy build test is to ensure that all the
|
|
# armeabi-v7a prebuilt binaries distributed with the NDK were
|
|
# properly built targetting VFPv3-D16, as per the ABI spec.
|
|
#
|
|
# For a related bug, see http://code.google.com/p/android/issues/detail?id=26199
|
|
#
|
|
|
|
#
|
|
# $1: ELF binary
|
|
# $2: Tag name (e.g. Tag_CPU_name)
|
|
#
|
|
extract_arch_tag ()
|
|
{
|
|
echo $($ARM_READELF -A "$1" | awk '$1 == "'$2':" { print $2; }' | sort -u | tr '\n' ' ')
|
|
}
|
|
|
|
# Returns success only if a file is a static object or library.
|
|
# We simply check the suffix, which must be either .a or .o
|
|
# $1: file name
|
|
is_static_file ()
|
|
{
|
|
case $1 in
|
|
*.o|*.a)
|
|
return 0
|
|
;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
|
|
#
|
|
# WARNING: VERY IMPORTANT TECHNICAL NOTE:
|
|
#
|
|
# The function below works by inspecting the architecture-specific
|
|
# attributes in an ELF file. Please be aware that the behaviour of
|
|
# binutils-2.19 and binutils-2.21 is different when generating these
|
|
# tags.
|
|
#
|
|
# 1/ When compiling for ARMv7-A targets, one can use any of the following
|
|
# labels for the -mfpu=<name> option:
|
|
#
|
|
# vfp
|
|
# vfpv3
|
|
# vfpv3-d16
|
|
# neon
|
|
#
|
|
# 2/ There are two VFPv3 architectures defined by ARM:
|
|
#
|
|
# VFPv3-D16 -> Mandates only 16 double FPU registers (d0-d15)
|
|
# VFPv3-D32 -> Mandates 32 double FPU registers (d0-d31)
|
|
#
|
|
# In addition, NEON requires VFPv3-D32
|
|
#
|
|
# There is also VFPv2, which is an earlier version of VFPv3. Technically
|
|
# speaking, VFPv3 is not completely backwards compatible with VFPv2 because
|
|
# there are a few VFPv2 instructions it doesn't support.
|
|
#
|
|
# 3/ The table below indicates, for each -mfpu label, the following:
|
|
#
|
|
# - The value of the 'Tag_VFP_arch' attribute that will be placed in
|
|
# the generated object files or binaries (you can list them with
|
|
# 'readelf -A <file>')
|
|
#
|
|
# - Whether the generated code uses 16 or 32 FPU double registers
|
|
# (this is checked by looking at the disassembly of libgnustl_shared.so,
|
|
# more specifically functions like 'cosf' or 'sinf' inside it).
|
|
#
|
|
# First, for binutils-2.19:
|
|
#
|
|
# fpu value EABI tag FPU reg count
|
|
# -----------------------------------------------------
|
|
# vfp VFPv2 16
|
|
# vfpv3 VFPv3-D16 32 (*)
|
|
# vfpv3-d16 VFPv3 16 (*)
|
|
# neon VFPv3 32
|
|
#
|
|
# And now for binutils-2.21
|
|
#
|
|
# fpu value EABI tag FPU reg count
|
|
# -----------------------------------------------------
|
|
# vfp VFPv2 16
|
|
# vfpv3 VFPv3 32
|
|
# vfpv3-d16 VFPv3-D16 16
|
|
# neon VFPv3 32
|
|
#
|
|
# This shows that:
|
|
#
|
|
# - The 'VFPv3' tag seems to match VFPv3-D32 exclusively on 2.21,
|
|
# but is a mess with 2.19
|
|
#
|
|
# - Similarly, the 'vfpv3' value seems to match VFPv3-D32 as well,
|
|
# with the exception that binutils-2.19 is buggy and will put an
|
|
# invalid tag (VFPv3-D16, instead of VFPv3) in the generate ELF file.
|
|
#
|
|
# - binutils 2.19 puts the wrong tag in the executable for vfpv3 and
|
|
# vfpv3-d16, then should probably be inverted!
|
|
#
|
|
# The end result is that we can't use the EABI tag to determine the number
|
|
# of hardware FPU registers that are really used by the machine code with
|
|
# binutils 2.19 :-(
|
|
#
|
|
# BONUS:
|
|
#
|
|
# - When using 'neon', binutils-2.21 will also add a new tag named
|
|
# 'Tag_Advanced_SIMD_arch' with value 'NEONv1'. Sadly, binutils-2.19
|
|
# doesn't do any of this.
|
|
#
|
|
|
|
# Check that an ELF binary is compatible with our armeabi-v7a ABI
|
|
# (i.e. no NEON, and only 16 hardware registers being used).
|
|
#
|
|
# See technical note above to understand how this currently works.
|
|
# We're still assuming the toolchain is built with the buggy binutils-2.19.
|
|
#
|
|
# $1: path to an ARMv7-A ELF binary (static lib, shared lib or executable)
|
|
#
|
|
check_armv7_elf_binary ()
|
|
{
|
|
# We use a small awk script to parse the output of 'readelf -A'
|
|
# Which typically looks like:
|
|
#
|
|
# Attribute Section: aeabi
|
|
# File Attributes
|
|
# Tag_CPU_name: "7-A"
|
|
# Tag_CPU_arch: v7
|
|
# Tag_CPU_arch_profile: Application
|
|
# Tag_ARM_ISA_use: Yes
|
|
# Tag_THUMB_ISA_use: Thumb-2
|
|
# Tag_VFP_arch: VFPv3-D16
|
|
# Tag_ABI_PCS_wchar_t: 4
|
|
# Tag_ABI_FP_denormal: Needed
|
|
# Tag_ABI_FP_exceptions: Needed
|
|
# Tag_ABI_FP_number_model: IEEE 754
|
|
# Tag_ABI_align8_needed: Yes
|
|
# Tag_ABI_align8_preserved: Yes, except leaf SP
|
|
# Tag_ABI_enum_size: int
|
|
# Tag_ABI_HardFP_use: SP and DP
|
|
# Tag_ABI_optimization_goals: Aggressive Speed
|
|
# Tag_unknown_44: 1 (0x1)
|
|
#
|
|
# Note that for static libraries, these sections will appear multiple
|
|
# time in the output of 'readelf -A'.
|
|
|
|
echo "Checking: $(basename $1)"
|
|
if [ ! -f "$1" ]; then
|
|
1>&2 echo "PANIC: Missing binary: $1"
|
|
exit 1
|
|
fi
|
|
|
|
# We want to check the values of Tag_CPU_name
|
|
CPU_NAMES=$(extract_arch_tag "$1" Tag_CPU_name)
|
|
VFP_ARCHS=$(extract_arch_tag "$1" Tag_VFP_arch)
|
|
NEON_ARCHS=$(extract_arch_tag "$1" Tag_Advanced_SIMD_arch)
|
|
|
|
# IMPORTANT NOTE: Even when using -march=armv7-a, the compiler may not
|
|
# necessarily use ARMv7-A specific instruction and will tag an object file
|
|
# with the following attributes:
|
|
#
|
|
# Attribute Section: aeabi
|
|
# File Attributes
|
|
# Tag_CPU_name: "5TE"
|
|
# Tag_CPU_arch: v5TE
|
|
# Tag_ARM_ISA_use: Yes
|
|
# Tag_THUMB_ISA_use: Thumb-1
|
|
# Tag_ABI_PCS_wchar_t: 4
|
|
# Tag_ABI_FP_denormal: Needed
|
|
# Tag_ABI_FP_exceptions: Needed
|
|
# Tag_ABI_FP_number_model: IEEE 754
|
|
# Tag_ABI_align8_needed: Yes
|
|
# Tag_ABI_align8_preserved: Yes, except leaf SP
|
|
# Tag_ABI_enum_size: int
|
|
# Tag_ABI_optimization_goals: Aggressive Speed
|
|
# Tag_unknown_44: 1 (0x1)
|
|
#
|
|
# This means that in static libraries, you can have both
|
|
# '5TE' and '7-A' CPU name tags at the same time, or only
|
|
# '5TE' or only '7-A', deal with all these cases properly.
|
|
|
|
echo " found tags: CPU names:'$CPU_NAMES' VFP:'$VFP_ARCHS' NEON:'$NEON_ARCHS'"
|
|
|
|
# Clearly, any trace of NEON is a deal-breaker!
|
|
if [ "$NEON_ARCHS" ]; then
|
|
1>&2 echo "PANIC: Binary file should not contain NEON instructions: $1"
|
|
exit 1
|
|
fi
|
|
|
|
if is_static_file "$1"; then
|
|
# For static libraries / object files, it's ok to contain ARMv5TE binaries
|
|
if [ "$CPU_NAMES" == "\"5TE\"" -a "$CPU_NAMES" != "\"7-A\"" -a "$CPU_NAMES" != "\"5TE\" \"7-A\"" ]; then
|
|
# Neither ARMv7-A or ARMv5TE+ARMv7-A, something's fishy
|
|
1>&2 echo "PANIC: File is neither ARMv5TE or ARMv7-A binary: $1"
|
|
exit 1
|
|
fi
|
|
|
|
# exit here because some static libraries can have a mix of several
|
|
# VFP tags that make them difficult to check (e.g. libgnustl_static.a
|
|
# can have 'VFPv1 VFPv2 VFPv3' at the same time :-(
|
|
return
|
|
fi
|
|
|
|
# If we reach this point, we only contain ARMv7-A machine code, so look
|
|
# at the VFP arch tag(s)
|
|
|
|
# Sometimes no VFP_arch tag is placed in the final binary, this happens
|
|
# with libgabi++_shared.so for example, because the code doesn't have
|
|
# any floating point instructions.
|
|
#
|
|
|
|
# XXX: FOR NOW, ASSUME BROKEN binutils-2.19, AND THUS THAT 'VFPv3' IS VALID
|
|
|
|
if [ "$VFP_ARCHS" != "VFPv3" -a "$VFP_ARCHS" != "VFPv3-D16" -a "$VFP_ARCHS" != "" ]; then
|
|
1>&2 echo "PANIC: File is not a VFPv3-D16 binary: $1"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
export ANDROID_NDK_ROOT=$NDK
|
|
|
|
NDK_BUILDTOOLS_PATH=$NDK/build/tools
|
|
. $NDK/build/tools/prebuilt-common.sh
|
|
|
|
if [ -n "$APP_ABI" ]; then
|
|
if [ "$(convert_abi_to_arch $APP_ABI)" != "arm" ]; then
|
|
echo "Skipping ARM only test"
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
ARM_TOOLCHAIN_NAME=$(get_default_toolchain_name_for_arch arm)
|
|
ARM_TOOLCHAIN_PREFIX=$(get_default_toolchain_prefix_for_arch arm)
|
|
|
|
case $(uname -s) in
|
|
Darwin)
|
|
HOST_ARCH=`uname -m`
|
|
case "$HOST_ARCH" in
|
|
i?86) HOST_ARCH=x86
|
|
if ! echo __LP64__ | (CCOPTS= gcc -E - 2>/dev/null) | grep -q __LP64__ ; then
|
|
HOST_ARCH=x86_64
|
|
fi
|
|
;;
|
|
esac
|
|
HOST_TAG=darwin-$HOST_ARCH
|
|
;;
|
|
Linux)
|
|
HOST_TAG=linux-$(uname -p)
|
|
;;
|
|
*)
|
|
echo "WARNING: This test cannot run on this machine!" >&2
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
ARM_READELF=$NDK/toolchains/$ARM_TOOLCHAIN_NAME/prebuilt/$HOST_TAG/bin/${ARM_TOOLCHAIN_PREFIX}-readelf
|
|
if [ ! -f "$ARM_READELF" ]; then
|
|
echo "ERROR: Missing binary: $ARM_READELF" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ARMv7_ABIS="armeabi-v7a armeabi-v7a-hard"
|
|
for ABI in $ARMv7_ABIS; do
|
|
|
|
STLPORT_LIBS=$NDK/sources/cxx-stl/stlport/libs/$ABI
|
|
check_armv7_elf_binary $STLPORT_LIBS/libstlport_shared.so
|
|
check_armv7_elf_binary $STLPORT_LIBS/libstlport_static.a
|
|
|
|
|
|
for VERSION in $DEFAULT_GCC_VERSION_LIST; do
|
|
GNUSTL_LIBS=$NDK/sources/cxx-stl/gnu-libstdc++/4.9/libs/$ABI
|
|
check_armv7_elf_binary $GNUSTL_LIBS/libsupc++.a
|
|
check_armv7_elf_binary $GNUSTL_LIBS/libgnustl_shared.so
|
|
check_armv7_elf_binary $GNUSTL_LIBS/libgnustl_static.a
|
|
done
|
|
done
|
|
|
|
echo "Done!"
|