From adab51aefdd00b65d631f64e6e313713d7dd9564 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Wed, 19 Feb 2014 17:23:24 -0800 Subject: [PATCH] Added script generating additions to libgcc_compat.c from linker errors bug: 12234455 Change-Id: Icac35237f06e75745da5a91d9c4c941d7df4f84d --- libc/arch-arm/bionic/libgcc_compat.c | 246 ++++++++++++----------------------- libc/tools/genlibgcc_compat.py | 144 ++++++++++++++++++++ 2 files changed, 224 insertions(+), 166 deletions(-) create mode 100755 libc/tools/genlibgcc_compat.py diff --git a/libc/arch-arm/bionic/libgcc_compat.c b/libc/arch-arm/bionic/libgcc_compat.c index f694060e6..c45e6e2ca 100644 --- a/libc/arch-arm/bionic/libgcc_compat.c +++ b/libc/arch-arm/bionic/libgcc_compat.c @@ -1,176 +1,90 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* This file contains dummy references to libgcc.a functions to force the - * dynamic linker to copy their definition into the final libc.so binary. - * - * They are required to ensure backwards binary compatibility with - * libc.so provided by the platform and binaries built with the NDK or - * different versions/configurations of toolchains. - * - * Now, for a more elaborate description of the issue: - * - * libgcc.a is a compiler-specific library containing various helper - * functions used to implement certain operations that are not necessarily - * supported by the target CPU. For example, integer division doesn't have a - * corresponding CPU instruction on ARMv5, and is instead implemented in the - * compiler-generated machine code as a call to an __idiv helper function. - * - * Normally, one has to place libgcc.a in the link command used to generate - * target binaries (shared libraries and executables) after all objects and - * static libraries, but before dependent shared libraries, i.e. something - * like: - * gcc -o libfoo.so foo.a libgcc.a -lc -lm - * - * This ensures that any helper function needed by the code in foo.a is copied - * into the final libfoo.so. However, doing so will link a bunch of other __cxa - * functions from libgcc.a into each .so and executable, causing 4k+ increase - * in every binary. Therefore the Android platform build system has been - * using this instead: - * - * gcc -o libfoo.so foo.a -lc -lm libgcc.a - * - * The problem with this is that if one helper function needed by foo.a has - * already been copied into libc.so or libm.so, then nothing will be copied - * into libfoo.so. Instead, a symbol import definition will be added to it - * so libfoo.so can directly call the one in libc.so at runtime. - * - * When refreshing toolchains for new versions or using different architecture - * flags, the set of helper functions copied to libc.so may change, which - * resulted in some native shared libraries generated with the NDK or prebuilts - * from vendors to fail to load properly. - * - * The NDK has been fixed after 1.6_r1 to use the correct link command, so - * any native shared library generated with it should now be safe from that - * problem. On the other hand, existing shared libraries distributed with - * applications that were generated with a previous version of the NDK - * still need all 1.5/1.6 helper functions in libc.so and libm.so - * - * After 3.2, the toolchain was updated again, adding __aeabi_f2uiz to the - * list of requirements. Technically, this is due to mis-linked NDK libraries - * but it is easier to add a single function here than asking several app - * developers to fix their build. - * - * The __aeabi_idiv function is added to the list since cortex-a15 supports - * HW idiv instructions so the system libc.so doesn't pull in the reference to - * __aeabi_idiv but legacy libraries built against cortex-a9 targets still need - * it. - * - * Final note: some of the functions below should really be in libm.so to - * completely reflect the state of 1.5/1.6 system images. However, - * since libm.so depends on libc.so, it's easier to put all of - * these in libc.so instead, since the dynamic linker will always - * search in libc.so before libm.so for dependencies. - */ +/* Generated by genlibgcc_compat.py */ #define COMPAT_FUNCTIONS_LIST \ - XX(__adddf3) \ - XX(__addsf3) \ - XX(__aeabi_cdcmpeq) \ - XX(__aeabi_cdcmple) \ - XX(__aeabi_cdrcmple) \ - XX(__aeabi_d2f) \ - XX(__aeabi_d2iz) \ - XX(__aeabi_dadd) \ - XX(__aeabi_dcmpeq) \ - XX(__aeabi_dcmpge) \ - XX(__aeabi_dcmpgt) \ - XX(__aeabi_dcmple) \ - XX(__aeabi_dcmplt) \ - XX(__aeabi_dcmpun) \ - XX(__aeabi_ddiv) \ - XX(__aeabi_dmul) \ - XX(__aeabi_drsub) \ - XX(__aeabi_dsub) \ - XX(__aeabi_f2d) \ - XX(__aeabi_f2iz) \ - XX(__aeabi_f2uiz) \ - XX(__aeabi_fadd) \ - XX(__aeabi_fcmpun) \ - XX(__aeabi_fdiv) \ - XX(__aeabi_fmul) \ - XX(__aeabi_frsub) \ - XX(__aeabi_fsub) \ - XX(__aeabi_i2d) \ - XX(__aeabi_i2f) \ - XX(__aeabi_idiv) \ - XX(__aeabi_idivmod) \ - XX(__aeabi_l2d) \ - XX(__aeabi_l2f) \ - XX(__aeabi_lasr) \ - XX(__aeabi_ldivmod) \ - XX(__aeabi_llsl) \ - XX(__aeabi_llsr) \ - XX(__aeabi_lmul) \ - XX(__aeabi_ui2d) \ - XX(__aeabi_ui2f) \ - XX(__aeabi_uidiv) \ - XX(__aeabi_uidivmod) \ - XX(__aeabi_ul2d) \ - XX(__aeabi_ul2f) \ - XX(__aeabi_uldivmod) \ - XX(__cmpdf2) \ - XX(__divdf3) \ - XX(__divsf3) \ - XX(__eqdf2) \ - XX(__extendsfdf2) \ - XX(__fixdfsi) \ - XX(__fixsfsi) \ - XX(__floatdidf) \ - XX(__floatdisf) \ - XX(__floatsidf) \ - XX(__floatsisf) \ - XX(__floatundidf) \ - XX(__floatundisf) \ - XX(__floatunsidf) \ - XX(__floatunsisf) \ - XX(__gedf2) \ - XX(__gtdf2) \ - XX(__ledf2) \ - XX(__ltdf2) \ - XX(__muldf3) \ - XX(__muldi3) \ - XX(__mulsf3) \ - XX(__nedf2) \ - XX(__popcountsi2) \ - XX(__popcount_tab) \ - XX(__subdf3) \ - XX(__subsf3) \ - XX(__truncdfsf2) \ - XX(__unorddf2) \ - XX(__unordsf2) \ + XX(__adddf3) \ + XX(__addsf3) \ + XX(__aeabi_cdcmpeq) \ + XX(__aeabi_cdcmple) \ + XX(__aeabi_cdrcmple) \ + XX(__aeabi_d2f) \ + XX(__aeabi_d2iz) \ + XX(__aeabi_dadd) \ + XX(__aeabi_dcmpeq) \ + XX(__aeabi_dcmpge) \ + XX(__aeabi_dcmpgt) \ + XX(__aeabi_dcmple) \ + XX(__aeabi_dcmplt) \ + XX(__aeabi_dcmpun) \ + XX(__aeabi_ddiv) \ + XX(__aeabi_dmul) \ + XX(__aeabi_drsub) \ + XX(__aeabi_dsub) \ + XX(__aeabi_f2d) \ + XX(__aeabi_f2iz) \ + XX(__aeabi_f2uiz) \ + XX(__aeabi_fadd) \ + XX(__aeabi_fcmpun) \ + XX(__aeabi_fdiv) \ + XX(__aeabi_fmul) \ + XX(__aeabi_frsub) \ + XX(__aeabi_fsub) \ + XX(__aeabi_i2d) \ + XX(__aeabi_i2f) \ + XX(__aeabi_idiv) \ + XX(__aeabi_idivmod) \ + XX(__aeabi_l2d) \ + XX(__aeabi_l2f) \ + XX(__aeabi_lasr) \ + XX(__aeabi_ldivmod) \ + XX(__aeabi_llsl) \ + XX(__aeabi_llsr) \ + XX(__aeabi_lmul) \ + XX(__aeabi_ui2d) \ + XX(__aeabi_ui2f) \ + XX(__aeabi_uidiv) \ + XX(__aeabi_uidivmod) \ + XX(__aeabi_ul2d) \ + XX(__aeabi_ul2f) \ + XX(__aeabi_uldivmod) \ + XX(__aeabi_unwind_cpp_pr0) \ + XX(__aeabi_unwind_cpp_pr1) \ + XX(__cmpdf2) \ + XX(__divdf3) \ + XX(__divsf3) \ + XX(__eqdf2) \ + XX(__extendsfdf2) \ + XX(__fixdfsi) \ + XX(__fixsfsi) \ + XX(__floatdidf) \ + XX(__floatdisf) \ + XX(__floatsidf) \ + XX(__floatsisf) \ + XX(__floatundidf) \ + XX(__floatundisf) \ + XX(__floatunsidf) \ + XX(__floatunsisf) \ + XX(__gedf2) \ + XX(__gtdf2) \ + XX(__ledf2) \ + XX(__ltdf2) \ + XX(__muldf3) \ + XX(__muldi3) \ + XX(__mulsf3) \ + XX(__nedf2) \ + XX(__popcount_tab) \ + XX(__popcountsi2) \ + XX(__subdf3) \ + XX(__subsf3) \ + XX(__truncdfsf2) \ + XX(__unorddf2) \ + XX(__unordsf2) \ + #define XX(f) extern void f(void); COMPAT_FUNCTIONS_LIST #undef XX -void __bionic_libgcc_compat_hooks(void) -{ +void __bionic_libgcc_compat_hooks(void) { #define XX(f) f(); COMPAT_FUNCTIONS_LIST #undef XX diff --git a/libc/tools/genlibgcc_compat.py b/libc/tools/genlibgcc_compat.py new file mode 100755 index 000000000..f2ff7b028 --- /dev/null +++ b/libc/tools/genlibgcc_compat.py @@ -0,0 +1,144 @@ +#!/usr/bin/python + +''' +/* This file generates libgcc_compat.c file that contains dummy + * references to libgcc.a functions to force the dynamic linker + * to copy their definition into the final libc.so binary. + * + * They are required to ensure backwards binary compatibility with + * libc.so provided by the platform and binaries built with the NDK or + * different versions/configurations of toolchains. + * + * Now, for a more elaborate description of the issue: + * + * libgcc.a is a compiler-specific library containing various helper + * functions used to implement certain operations that are not necessarily + * supported by the target CPU. For example, integer division doesn't have a + * corresponding CPU instruction on ARMv5, and is instead implemented in the + * compiler-generated machine code as a call to an __idiv helper function. + * + * Normally, one has to place libgcc.a in the link command used to generate + * target binaries (shared libraries and executables) after all objects and + * static libraries, but before dependent shared libraries, i.e. something + * like: + * gcc -o libfoo.so foo.a libgcc.a -lc -lm + * + * This ensures that any helper function needed by the code in foo.a is copied + * into the final libfoo.so. However, doing so will link a bunch of other __cxa + * functions from libgcc.a into each .so and executable, causing 4k+ increase + * in every binary. Therefore the Android platform build system has been + * using this instead: + * + * gcc -o libfoo.so foo.a -lc -lm libgcc.a + * + * The problem with this is that if one helper function needed by foo.a has + * already been copied into libc.so or libm.so, then nothing will be copied + * into libfoo.so. Instead, a symbol import definition will be added to it + * so libfoo.so can directly call the one in libc.so at runtime. + * + * When refreshing toolchains for new versions or using different architecture + * flags, the set of helper functions copied to libc.so may change, which + * resulted in some native shared libraries generated with the NDK or prebuilts + * from vendors to fail to load properly. + * + * The NDK has been fixed after 1.6_r1 to use the correct link command, so + * any native shared library generated with it should now be safe from that + * problem. On the other hand, existing shared libraries distributed with + * applications that were generated with a previous version of the NDK + * still need all 1.5/1.6 helper functions in libc.so and libm.so + * + * After 3.2, the toolchain was updated again, adding __aeabi_f2uiz to the + * list of requirements. Technically, this is due to mis-linked NDK libraries + * but it is easier to add a single function here than asking several app + * developers to fix their build. + * + * The __aeabi_idiv function is added to the list since cortex-a15 supports + * HW idiv instructions so the system libc.so doesn't pull in the reference to + * __aeabi_idiv but legacy libraries built against cortex-a9 targets still need + * it. + * + * Final note: some of the functions below should really be in libm.so to + * completely reflect the state of 1.5/1.6 system images. However, + * since libm.so depends on libc.so, it's easier to put all of + * these in libc.so instead, since the dynamic linker will always + * search in libc.so before libm.so for dependencies. + */ +''' + +import os +import sys +import subprocess +import tempfile +import re + +libgcc_compat_header = "/* Generated by genlibgcc_compat.py */\n" + \ +""" +#define COMPAT_FUNCTIONS_LIST \\ +""" + +libgcc_compat_footer = """ + +#define XX(f) extern void f(void); +COMPAT_FUNCTIONS_LIST +#undef XX + +void __bionic_libgcc_compat_hooks(void) { +#define XX(f) f(); +COMPAT_FUNCTIONS_LIST +#undef XX +} +""" + +class Generator: + def process(self): + android_build_top_path = os.environ["ANDROID_BUILD_TOP"] + build_path = android_build_top_path + "/bionic/libc" + file_name = "libgcc_compat.c" + file_path = build_path + "/arch-arm/bionic/" + file_name + + print "* ANDROID_BUILD_TOP=" + android_build_top_path + + # Check TARGET_ARCH + arch = subprocess.check_output(["CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make --no-print-directory -f build/core/config.mk dumpvar-TARGET_ARCH"], + cwd=android_build_top_path, shell=True).strip() + + if arch != 'arm': + sys.exit("Error: Invalid TARGET_ARCH='" + arch + "' expecting 'arm'") + + build_output_file_path = tempfile.mkstemp()[1] + + p = subprocess.Popen(["ONE_SHOT_MAKEFILE=bionic/libc/Android.mk make -C " + android_build_top_path + + " -f build/core/main.mk all_modules TARGET_LIBGCC= -j20 -B 2>&1 | tee " + build_output_file_path], + cwd=build_path, shell=True) + p.wait() + + print "* Build complete, logfile: " + build_output_file_path + + func_set = set() + prog=re.compile("(?<=undefined reference to ')\w+") + fd = open(build_output_file_path, 'r') + for line in fd: + m = prog.search(line) + if m: + func_set.add(m.group(0)) + + fd.close() + + func_list = sorted(func_set) + + print "* Found " + repr(len(func_list)) + " referenced functions: " + repr(func_list) + + if 0 == len(func_list): + sys.exit("Error: function list is empty, please check the build log: " + build_output_file_path) + + print "* Generating " + file_path + fres = open(file_path, 'w') + fres.write(libgcc_compat_header) + for func_name in func_list: + fres.write(" XX("+func_name+") \\\n") + fres.write(libgcc_compat_footer) + fres.close() + +generator = Generator() +generator.process() + -- 2.11.0