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
This commit is contained in:
Logan Chien
2017-02-20 15:57:02 +08:00
parent 18e0749a9c
commit 2f7f4f4405
2 changed files with 73 additions and 1 deletions

View File

@@ -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

View File

@@ -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():