aboutsummaryrefslogtreecommitdiff
path: root/tests/build/check-armeabi-v7a-prebuilts/build.sh
blob: ff86ee3532e463d8b5c9ab97e0e737e911f30ccb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#!/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
}

. $NDK/build/tools/dev-defaults.sh

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_TAG=darwin-$(uname -m)
      ;;
    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

    GABIXX_LIBS=$NDK/sources/cxx-stl/gabi++/libs/$ABI
    check_armv7_elf_binary $GABIXX_LIBS/libgabi++_shared.so
    check_armv7_elf_binary $GABIXX_LIBS/libgabi++_static.a

    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++/$VERSION/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!"