|  | #!/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 <options> -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 <options> -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\n" | 
|  |  | 
|  | class Generator: | 
|  | def process(self): | 
|  | android_build_top_path = os.environ["ANDROID_BUILD_TOP"] | 
|  |  | 
|  | 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' and arch != 'x86': | 
|  | sys.exit("Error: Invalid TARGET_ARCH='" + arch + "' expecting 'arm' or 'x86'") | 
|  |  | 
|  | build_path =  android_build_top_path + "/bionic/libc" | 
|  | file_name = "libgcc_compat.c" | 
|  | file_path = build_path + "/arch-" + arch + "/bionic/" + file_name | 
|  |  | 
|  | 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 | 
|  |  | 
|  | symbol_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: | 
|  | symbol_set.add(m.group(0)) | 
|  |  | 
|  | fd.close() | 
|  |  | 
|  | symbol_list = sorted(symbol_set) | 
|  |  | 
|  | print "* Found " + repr(len(symbol_list)) + " referenced symbols: " + repr(symbol_list) | 
|  |  | 
|  | if 0 == len(symbol_list): | 
|  | sys.exit("Error: symbol 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 sym_name in symbol_list: | 
|  | fres.write("extern char "+sym_name+";\n") | 
|  | fres.write("\n"); | 
|  |  | 
|  | fres.write("void* __bionic_libgcc_compat_symbols[] = {\n"); | 
|  | for sym_name in symbol_list: | 
|  | fres.write("    &"+sym_name+",\n") | 
|  | fres.write("};\n"); | 
|  |  | 
|  | fres.close() | 
|  |  | 
|  | generator = Generator() | 
|  | generator.process() | 
|  |  |