From 2f7f4f4405d0f9fcdf3dbcbe299f00e5c3208323 Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Mon, 20 Feb 2017 15:57:02 +0800 Subject: [PATCH] vndk-def: Link imported symbols. This commit resolves the library dependencies down to symbol level. It will traverse all undefined symbols and try to find a matching symbol from the libraries specified in DT_NEEDED entries. This algorithm won't be able to find symbols for the libraries that are not built with -Wl,--no-undefined. Unresolved weak symbols are added to unresolved_symbols as well. Test: ./tests/run.py Change-Id: I3b0f06e38f256025bb6993d5c9f3d8afc3a4bf0e --- .../definition-tool/tests/test_elf_linker.py | 50 +++++++++++++++++++ .../definition-tool/vndk_definition_tool.py | 24 ++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/vndk/tools/definition-tool/tests/test_elf_linker.py b/vndk/tools/definition-tool/tests/test_elf_linker.py index db4c0dc30..dad176b49 100755 --- a/vndk/tools/definition-tool/tests/test_elf_linker.py +++ b/vndk/tools/definition-tool/tests/test_elf_linker.py @@ -163,6 +163,56 @@ class ELFLinkerTest(unittest.TestCase): '/system/lib64/libdl.so'], self._get_paths_from_nodes(node.deps)) + def test_linked_symbols(self): + gb = self._create_normal_graph() + graph = gb.graph + + # Check the unresolved symbols. + for lib_set in (graph.lib32, graph.lib64): + for lib in lib_set.values(): + self.assertEqual(set(), lib.unresolved_symbols) + + # Check the linked symbols. + for lib in ('lib', 'lib64'): + libdl = graph.map_path_to_lib('/system/' + lib + '/libdl.so') + libm = graph.map_path_to_lib('/system/' + lib + '/libm.so') + libc = graph.map_path_to_lib('/system/' + lib + '/libc.so') + libRS = graph.map_path_to_lib('/system/' + lib + '/libRS.so') + libcutils = \ + graph.map_path_to_lib('/system/' + lib + '/libcutils.so') + libEGL = graph.map_path_to_lib('/vendor/' + lib + '/libEGL.so') + + # Check the linked symbols for libc.so. + self.assertIs(libdl, libc.linked_symbols['dlclose']) + self.assertIs(libdl, libc.linked_symbols['dlopen']) + self.assertIs(libm, libc.linked_symbols['cos']) + self.assertIs(libm, libc.linked_symbols['sin']) + + # Check the linked symbols for libRS.so. + self.assertIs(libdl, libRS.linked_symbols['dlclose']) + self.assertIs(libdl, libRS.linked_symbols['dlopen']) + self.assertIs(libdl, libRS.linked_symbols['dlsym']) + + # Check the linked symbols for libcutils.so. + self.assertIs(libdl, libcutils.linked_symbols['dlclose']) + self.assertIs(libdl, libcutils.linked_symbols['dlopen']) + self.assertIs(libc, libcutils.linked_symbols['fclose']) + self.assertIs(libc, libcutils.linked_symbols['fopen']) + + # Check the linked symbols for libEGL.so. + self.assertIs(libc, libEGL.linked_symbols['fclose']) + self.assertIs(libc, libEGL.linked_symbols['fopen']) + + def test_unresolved_symbols(self): + gb = GraphBuilder() + gb.add_lib(PT_SYSTEM, ELF.ELFCLASS64, 'libfoo', dt_needed=[], + exported_symbols={'foo', 'bar'}, + imported_symbols={'__does_not_exist'}) + gb.resolve() + + lib = gb.graph.map_path_to_lib('/system/lib64/libfoo.so') + self.assertEqual({'__does_not_exist'}, lib.unresolved_symbols) + def test_users(self): gb = self._create_normal_graph() graph = gb.graph diff --git a/vndk/tools/definition-tool/vndk_definition_tool.py b/vndk/tools/definition-tool/vndk_definition_tool.py index d44061968..c74e69b45 100755 --- a/vndk/tools/definition-tool/vndk_definition_tool.py +++ b/vndk/tools/definition-tool/vndk_definition_tool.py @@ -546,6 +546,8 @@ class ELFLinkData(object): self.deps = set() self.users = set() self.is_ndk = NDK_LIBS.is_ndk(path) + self.unresolved_symbols = set() + self.linked_symbols = dict() def add_dep(self, dst): self.deps.add(dst) @@ -631,7 +633,24 @@ class ELFLinker(object): if match: self.add_dep(match.group(1), match.group(2)) + def _find_exported_symbol(self, symbol, libs): + """Find the shared library with the exported symbol.""" + for lib in libs: + if symbol in lib.elf.exported_symbols: + return lib + return None + + def _resolve_lib_imported_symbols(self, lib, imported_libs): + """Resolve the imported symbols in a library.""" + for symbol in lib.elf.imported_symbols: + imported_lib = self._find_exported_symbol(symbol, imported_libs) + if imported_lib: + lib.linked_symbols[symbol] = imported_lib + else: + lib.unresolved_symbols.add(symbol) + def _resolve_lib_dt_needed(self, lib, resolver): + imported_libs = [] for dt_needed in lib.elf.dt_needed: dep = resolver.resolve(dt_needed, lib.elf.dt_rpath, lib.elf.dt_runpath) @@ -642,9 +661,12 @@ class ELFLinker(object): .format(lib.path, dt_needed, candidates), file=sys.stderr) continue lib.add_dep(dep) + imported_libs.append(dep) + return imported_libs def _resolve_lib_deps(self, lib, resolver): - self._resolve_lib_dt_needed(lib, resolver) + imported_libs = self._resolve_lib_dt_needed(lib, resolver) + self._resolve_lib_imported_symbols(lib, imported_libs) def _resolve_lib_set_deps(self, lib_set, resolver): for lib in lib_set.values():