Support DT_RUNPATH in the linker.

Only $ORIGIN substitution is supported, but not linux-specific $LIB
or $PLATFORM.

Change-Id: I5814a016c7c91afba080230a547a863686e7c2b9
diff --git a/tests/Android.build.mk b/tests/Android.build.mk
index 5b2b417..6d4faa9 100644
--- a/tests/Android.build.mk
+++ b/tests/Android.build.mk
@@ -48,6 +48,10 @@
     LOCAL_MULTILIB := $($(module)_multilib)
 endif
 
+ifneq ($($(module)_relative_path),)
+    LOCAL_MODULE_RELATIVE_PATH := $($(module)_relative_path)
+endif
+
 LOCAL_CFLAGS := \
     $(common_cflags) \
     $($(module)_cflags) \
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 3c9b8e3..1c01c62 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1062,3 +1062,17 @@
 extern "C" int version_zero_function2() {
   return 0;
 }
+
+TEST(dlfcn, dt_runpath) {
+  void* handle = dlopen("libtest_dt_runpath_d.so", RTLD_NOW);
+  ASSERT_TRUE(handle != nullptr) << dlerror();
+
+  typedef void *(* dlopen_b_fn)();
+  dlopen_b_fn fn = (dlopen_b_fn)dlsym(handle, "dlopen_b");
+  ASSERT_TRUE(fn != nullptr) << dlerror();
+
+  void *p = fn();
+  ASSERT_TRUE(p == nullptr);
+
+  dlclose(handle);
+}
diff --git a/tests/libs/Android.build.dt_runpath.mk b/tests/libs/Android.build.dt_runpath.mk
new file mode 100644
index 0000000..e9b5265
--- /dev/null
+++ b/tests/libs/Android.build.dt_runpath.mk
@@ -0,0 +1,66 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# -----------------------------------------------------------------------------
+# Libraries used by dt_runpath tests.
+# -----------------------------------------------------------------------------
+
+# A leaf library in a non-standard directory.
+libtest_dt_runpath_a_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_a_relative_path := dt_runpath_a
+module := libtest_dt_runpath_a
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# Depends on library A with a DT_RUNPATH
+libtest_dt_runpath_b_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_b_shared_libraries := libtest_dt_runpath_a
+libtest_dt_runpath_b_ldflags := -Wl,--rpath,\$${ORIGIN}/../dt_runpath_a
+libtest_dt_runpath_b_relative_path := dt_runpath_b_c_x
+module := libtest_dt_runpath_b
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# Depends on library A with an incorrect DT_RUNPATH. This does not matter
+# because B is the first in the D (below) dependency order, and library A
+# is already loaded using the correct DT_RUNPATH from library B.
+libtest_dt_runpath_c_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_c_shared_libraries := libtest_dt_runpath_a
+libtest_dt_runpath_c_ldflags := -Wl,--rpath,\$${ORIGIN}/invalid_dt_runpath
+libtest_dt_runpath_c_relative_path := dt_runpath_b_c_x
+module := libtest_dt_runpath_c
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# D depends on B and C with DT_RUNPATH.
+libtest_dt_runpath_d_src_files := \
+    dlopen_b.cpp
+
+libtest_dt_runpath_d_shared_libraries := libtest_dt_runpath_b libtest_dt_runpath_c
+libtest_dt_runpath_d_ldflags := -Wl,--rpath,\$${ORIGIN}/dt_runpath_b_c_x
+module := libtest_dt_runpath_d
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# A leaf library in a directory library D has DT_RUNPATH for.
+libtest_dt_runpath_x_src_files := \
+    empty.cpp
+
+libtest_dt_runpath_x_relative_path := dt_runpath_b_c_x
+module := libtest_dt_runpath_x
+include $(LOCAL_PATH)/Android.build.testlib.mk
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index a5ef622..662aeef 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -20,6 +20,7 @@
 common_cppflags += -std=gnu++11
 common_additional_dependencies := \
     $(LOCAL_PATH)/Android.mk \
+    $(LOCAL_PATH)/Android.build.dt_runpath.mk \
     $(LOCAL_PATH)/Android.build.dlext_testzip.mk \
     $(LOCAL_PATH)/Android.build.dlopen_2_parents_reloc.mk \
     $(LOCAL_PATH)/Android.build.dlopen_check_order_dlsym.mk \
@@ -180,6 +181,11 @@
 include $(LOCAL_PATH)/Android.build.testlib.mk
 
 # -----------------------------------------------------------------------------
+# Build DT_RUNPATH test helper libraries
+# -----------------------------------------------------------------------------
+include $(LOCAL_PATH)/Android.build.dt_runpath.mk
+
+# -----------------------------------------------------------------------------
 # Build library with two parents
 # -----------------------------------------------------------------------------
 include $(LOCAL_PATH)/Android.build.dlopen_2_parents_reloc.mk
diff --git a/tests/libs/dlopen_b.cpp b/tests/libs/dlopen_b.cpp
new file mode 100644
index 0000000..34f2881
--- /dev/null
+++ b/tests/libs/dlopen_b.cpp
@@ -0,0 +1,7 @@
+#include <dlfcn.h>
+extern "C" void *dlopen_b() {
+  // This is not supposed to succeed. Even though this library has DT_RUNPATH
+  // for libtest_dt_runpath_x.so, it is not taked into account for dlopen.
+  void *handle = dlopen("libtest_dt_runpath_x.so", RTLD_NOW);
+  return handle;
+}