summaryrefslogtreecommitdiffstats
path: root/linker
diff options
context:
space:
mode:
authorChristopher R. Palmer <crpalmer@gmail.com>2015-11-03 16:44:44 -0500
committerSteve Kondik <shade@chemlab.org>2015-11-07 01:16:16 -0800
commit8a044e6e632b6221b8a0dc2df918d7b01a77fb98 (patch)
tree59b8feb2605ddcb238ad49402b6295c8fb34350d /linker
parentcc20e751ce2c40ead4938cc7addc94100f9793c6 (diff)
downloadbionic-8a044e6e632b6221b8a0dc2df918d7b01a77fb98.zip
bionic-8a044e6e632b6221b8a0dc2df918d7b01a77fb98.tar.gz
bionic-8a044e6e632b6221b8a0dc2df918d7b01a77fb98.tar.bz2
linker: Add support for dynamic "shim" libs
Add a new environment variable LD_SHIM_LIBS that is a colon (":") separated list of vertical bar ("|") separated pairs. The pairs are the name for a soinfo reference (executable or shared library) followed by the name of the shim library to load. For example: LD_SHIM_LIBS=rmt_storage|libshim_ioprio.so:/system/lib/libicuuv.so|libshim_icu53.so will instruct the linker to load the dynamic library libshim_ioprio.so whenver rmt_storage is executed [*] and will load libshim_icu53.so whenever any executable or other shared library links against /system/lib/libicuuv.so. There are no restrictions against circular references. In this example, libshim_icu53.so can link against libicuuv.so which provides a simple and convenient means of adding compatibility symbols. [*] Note that the absolute path is not available to the linker and therefore using the name of executables does depend on the invocation and therefore should only be used if absolutely necessary. That is, running /system/bin/rmt_storage would not load any shim libs in this example because it does not match the name of the invocation of the command. If you have trouble determining the sonames being loaded, you can also set the environment variable LD_DEBUG=1 which will cause additional information to be logged to help trace the detection of the shim libs. Change-Id: I0ef80fa466167f7bcb7dac90842bef1c3cf879b6
Diffstat (limited to 'linker')
-rw-r--r--linker/linker.cpp63
1 files changed, 63 insertions, 0 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b860f70..146937a 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -882,6 +882,60 @@ typedef linked_list_t<soinfo> SoinfoLinkedList;
typedef linked_list_t<const char> StringLinkedList;
typedef linked_list_t<LoadTask> LoadTaskList;
+static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo);
+
+// g_ld_all_shim_libs maintains the references to memory as it used
+// in the soinfo structures and in the g_active_shim_libs list.
+
+static std::vector<std::string> g_ld_all_shim_libs;
+
+// g_active_shim_libs are all shim libs that are still eligible
+// to be loaded. We must remove a shim lib from the list before
+// we load the library to avoid recursive loops (load shim libA
+// for libB where libA also links against libB).
+
+static linked_list_t<const std::string> g_active_shim_libs;
+
+static void parse_LD_SHIM_LIBS(const char* path) {
+ parse_path(path, " :", &g_ld_all_shim_libs);
+ for (const auto& pair : g_ld_all_shim_libs) {
+ g_active_shim_libs.push_back(&pair);
+ }
+}
+
+static bool shim_lib_matches(const char *shim_lib, const char *realpath) {
+ const char *sep = strchr(shim_lib, '|');
+ return sep != nullptr && strncmp(realpath, shim_lib, sep - shim_lib) == 0;
+}
+
+template<typename F>
+static bool shim_libs_for_each(const char *const path, F action) {
+ if (path == nullptr) return true;
+ INFO("finding shim libs for \"%s\"\n", path);
+ std::vector<const std::string *> matched;
+
+ g_active_shim_libs.for_each([&](const std::string *a_pair) {
+ const char *pair = a_pair->c_str();
+ if (shim_lib_matches(pair, path)) {
+ matched.push_back(a_pair);
+ }
+ });
+
+ g_active_shim_libs.remove_if([&](const std::string *a_pair) {
+ const char *pair = a_pair->c_str();
+ return shim_lib_matches(pair, path);
+ });
+
+ for (const auto& one_pair : matched) {
+ const char* const pair = one_pair->c_str();
+ const char* sep = strchr(pair, '|');
+ INFO("found shim lib \"%s\"\n", sep+1);
+ soinfo *child = find_library(sep+1, RTLD_GLOBAL, nullptr);
+ if (! child) return false;
+ action(child);
+ }
+ return true;
+}
// This function walks down the tree of soinfo dependencies
// in breadth-first order and
@@ -914,6 +968,12 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s
si->get_children().for_each([&](soinfo* child) {
visit_list.push_back(child);
});
+
+ if (!shim_libs_for_each(si->get_realpath(), [&](soinfo* child) {
+ visit_list.push_back(child);
+ })) {
+ return false;
+ }
}
return true;
@@ -3154,9 +3214,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
// doesn't cost us anything.
const char* ldpath_env = nullptr;
const char* ldpreload_env = nullptr;
+ const char* ldshim_libs_env = nullptr;
if (!getauxval(AT_SECURE)) {
ldpath_env = getenv("LD_LIBRARY_PATH");
ldpreload_env = getenv("LD_PRELOAD");
+ ldshim_libs_env = getenv("LD_SHIM_LIBS");
}
INFO("[ android linker & debugger ]");
@@ -3210,6 +3272,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
// Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid).
parse_LD_LIBRARY_PATH(ldpath_env);
parse_LD_PRELOAD(ldpreload_env);
+ parse_LD_SHIM_LIBS(ldshim_libs_env);
somain = si;