1adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov#!/usr/bin/python 2adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 3adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov''' 4adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov/* This file generates libgcc_compat.c file that contains dummy 5adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * references to libgcc.a functions to force the dynamic linker 6adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * to copy their definition into the final libc.so binary. 7adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 8adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * They are required to ensure backwards binary compatibility with 9adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * libc.so provided by the platform and binaries built with the NDK or 10adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * different versions/configurations of toolchains. 11adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 12adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * Now, for a more elaborate description of the issue: 13adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 14adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * libgcc.a is a compiler-specific library containing various helper 15adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * functions used to implement certain operations that are not necessarily 16adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * supported by the target CPU. For example, integer division doesn't have a 17adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * corresponding CPU instruction on ARMv5, and is instead implemented in the 18adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * compiler-generated machine code as a call to an __idiv helper function. 19adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 20adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * Normally, one has to place libgcc.a in the link command used to generate 21adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * target binaries (shared libraries and executables) after all objects and 22adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * static libraries, but before dependent shared libraries, i.e. something 23adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * like: 24adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * gcc <options> -o libfoo.so foo.a libgcc.a -lc -lm 25adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 26adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * This ensures that any helper function needed by the code in foo.a is copied 27adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * into the final libfoo.so. However, doing so will link a bunch of other __cxa 28adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * functions from libgcc.a into each .so and executable, causing 4k+ increase 29adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * in every binary. Therefore the Android platform build system has been 30adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * using this instead: 31adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 32adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * gcc <options> -o libfoo.so foo.a -lc -lm libgcc.a 33adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 34adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * The problem with this is that if one helper function needed by foo.a has 35adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * already been copied into libc.so or libm.so, then nothing will be copied 36adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * into libfoo.so. Instead, a symbol import definition will be added to it 37adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * so libfoo.so can directly call the one in libc.so at runtime. 38adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 39adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * When refreshing toolchains for new versions or using different architecture 40adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * flags, the set of helper functions copied to libc.so may change, which 41adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * resulted in some native shared libraries generated with the NDK or prebuilts 42adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * from vendors to fail to load properly. 43adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 44adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * The NDK has been fixed after 1.6_r1 to use the correct link command, so 45adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * any native shared library generated with it should now be safe from that 46adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * problem. On the other hand, existing shared libraries distributed with 47adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * applications that were generated with a previous version of the NDK 48adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * still need all 1.5/1.6 helper functions in libc.so and libm.so 49adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 50adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * After 3.2, the toolchain was updated again, adding __aeabi_f2uiz to the 51adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * list of requirements. Technically, this is due to mis-linked NDK libraries 52adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * but it is easier to add a single function here than asking several app 53adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * developers to fix their build. 54adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 55adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * The __aeabi_idiv function is added to the list since cortex-a15 supports 56adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * HW idiv instructions so the system libc.so doesn't pull in the reference to 57adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * __aeabi_idiv but legacy libraries built against cortex-a9 targets still need 58adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * it. 59adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * 60adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * Final note: some of the functions below should really be in libm.so to 61adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * completely reflect the state of 1.5/1.6 system images. However, 62adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * since libm.so depends on libc.so, it's easier to put all of 63adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * these in libc.so instead, since the dynamic linker will always 64adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov * search in libc.so before libm.so for dependencies. 65adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov */ 66adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov''' 67adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 68adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovimport os 69adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovimport sys 70adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovimport subprocess 71adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovimport tempfile 72adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovimport re 73adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 746a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanovlibgcc_compat_header = "/* Generated by genlibgcc_compat.py */\n\n" 75adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 76adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovclass Generator: 77adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov def process(self): 78adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov android_build_top_path = os.environ["ANDROID_BUILD_TOP"] 79adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 80adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov print "* ANDROID_BUILD_TOP=" + android_build_top_path 81adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 82adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov # Check TARGET_ARCH 83adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov arch = subprocess.check_output(["CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make --no-print-directory -f build/core/config.mk dumpvar-TARGET_ARCH"], 84adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov cwd=android_build_top_path, shell=True).strip() 85adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 866869d26ad9f0e42f7b8ca0a8a331e6119759d211Christopher Ferris if arch != 'arm' and arch != 'x86': 876869d26ad9f0e42f7b8ca0a8a331e6119759d211Christopher Ferris sys.exit("Error: Invalid TARGET_ARCH='" + arch + "' expecting 'arm' or 'x86'") 886869d26ad9f0e42f7b8ca0a8a331e6119759d211Christopher Ferris 896869d26ad9f0e42f7b8ca0a8a331e6119759d211Christopher Ferris build_path = android_build_top_path + "/bionic/libc" 906869d26ad9f0e42f7b8ca0a8a331e6119759d211Christopher Ferris file_name = "libgcc_compat.c" 916869d26ad9f0e42f7b8ca0a8a331e6119759d211Christopher Ferris file_path = build_path + "/arch-" + arch + "/bionic/" + file_name 92adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 93adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov build_output_file_path = tempfile.mkstemp()[1] 94adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 95adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov p = subprocess.Popen(["ONE_SHOT_MAKEFILE=bionic/libc/Android.mk make -C " + android_build_top_path 96adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov + " -f build/core/main.mk all_modules TARGET_LIBGCC= -j20 -B 2>&1 | tee " + build_output_file_path], 97adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov cwd=build_path, shell=True) 98adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov p.wait() 99adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 100adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov print "* Build complete, logfile: " + build_output_file_path 101adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 1026a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov symbol_set = set() 103adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov prog=re.compile("(?<=undefined reference to ')\w+") 104adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov fd = open(build_output_file_path, 'r') 105adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov for line in fd: 106adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov m = prog.search(line) 107adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov if m: 1086a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov symbol_set.add(m.group(0)) 109adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 110adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov fd.close() 111adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 1126a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov symbol_list = sorted(symbol_set) 113adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 1146a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov print "* Found " + repr(len(symbol_list)) + " referenced symbols: " + repr(symbol_list) 115adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 1166a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov if 0 == len(symbol_list): 1176a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov sys.exit("Error: symbol list is empty, please check the build log: " + build_output_file_path) 118adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 119adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov print "* Generating " + file_path 120adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov fres = open(file_path, 'w') 121adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov fres.write(libgcc_compat_header) 1226a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov 1236a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov for sym_name in symbol_list: 1246a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov fres.write("extern char "+sym_name+";\n") 1256a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov fres.write("\n"); 1266a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov 1276a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov fres.write("void* __bionic_libgcc_compat_symbols[] = {\n"); 1286a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov for sym_name in symbol_list: 1296a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov fres.write(" &"+sym_name+",\n") 1306a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov fres.write("};\n"); 1316a45fe98727f9ee39386d39fa18eea69c706bc9eDmitriy Ivanov 132adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov fres.close() 133adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 134adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovgenerator = Generator() 135adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanovgenerator.process() 136adab51aefdd00b65d631f64e6e313713d7dd9564Dmitriy Ivanov 137