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