Merge "linker_main: acquire loader lock earlier and release it later" into main
diff --git a/libc/include/bits/elf_common.h b/libc/include/bits/elf_common.h
index b3c57a2..ac89dd6 100644
--- a/libc/include/bits/elf_common.h
+++ b/libc/include/bits/elf_common.h
@@ -1248,6 +1248,7 @@
 
 /*
  * RISC-V relocation types.
+ * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#relocations
  */
 
 /* Relocation types used by the dynamic linker. */
@@ -1304,6 +1305,9 @@
 #define	R_RISCV_SET32		56
 #define	R_RISCV_32_PCREL	57
 #define	R_RISCV_IRELATIVE	58
+#define	R_RISCV_PLT32		59
+#define	R_RISCV_SET_ULEB128	60
+#define	R_RISCV_SUB_ULEB128	61
 
 #define	R_SPARC_NONE		0
 #define	R_SPARC_8		1
diff --git a/libc/platform/bionic/page.h b/libc/platform/bionic/page.h
index a75b3ac..65faba4 100644
--- a/libc/platform/bionic/page.h
+++ b/libc/platform/bionic/page.h
@@ -27,11 +27,19 @@
 #if defined(PAGE_SIZE)
   return PAGE_SIZE;
 #else
-  static const size_t page_size = getauxval(PAGE_SIZE);
+  static const size_t page_size = getauxval(AT_PAGESZ);
   return page_size;
 #endif
 }
 
+constexpr size_t max_page_size() {
+#if defined(PAGE_SIZE)
+  return PAGE_SIZE;
+#else
+  return 65536;
+#endif
+}
+
 // Returns the address of the page containing address 'x'.
 inline uintptr_t page_start(uintptr_t x) {
   return x & ~(page_size() - 1);
diff --git a/libc/private/WriteProtected.h b/libc/private/WriteProtected.h
index 746f72a..2faaf77 100644
--- a/libc/private/WriteProtected.h
+++ b/libc/private/WriteProtected.h
@@ -25,15 +25,16 @@
 #include <async_safe/log.h>
 
 #include "platform/bionic/macros.h"
+#include "platform/bionic/page.h"
 
 template <typename T>
 union WriteProtectedContents {
   T value;
-  char padding[PAGE_SIZE];
+  char padding[max_page_size()];
 
   WriteProtectedContents() = default;
   BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents);
-} __attribute__((aligned(PAGE_SIZE)));
+} __attribute__((aligned(max_page_size())));
 
 // Write protected wrapper class that aligns its contents to a page boundary,
 // and sets the memory protection to be non-writable, except when being modified
@@ -41,8 +42,8 @@
 template <typename T>
 class WriteProtected {
  public:
-  static_assert(sizeof(T) < PAGE_SIZE,
-                "WriteProtected only supports contents up to PAGE_SIZE");
+  static_assert(sizeof(T) < max_page_size(),
+                "WriteProtected only supports contents up to max_page_size()");
   static_assert(__is_pod(T), "WriteProtected only supports POD contents");
 
   WriteProtected() = default;
@@ -80,7 +81,7 @@
     // ourselves.
     addr = untag_address(addr);
 #endif
-    if (mprotect(reinterpret_cast<void*>(addr), PAGE_SIZE, prot) == -1) {
+    if (mprotect(reinterpret_cast<void*>(addr), max_page_size(), prot) == -1) {
       async_safe_fatal("WriteProtected mprotect %x failed: %s", prot, strerror(errno));
     }
   }
diff --git a/tests/Android.bp b/tests/Android.bp
index a4298ab..b105f6a 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -867,79 +867,8 @@
     ],
 }
 
-// -----------------------------------------------------------------------------
-// Tests for the device using bionic's .so. Run with:
-//   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
-//   adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests
-// -----------------------------------------------------------------------------
 cc_defaults {
-    name: "bionic_unit_tests_defaults",
-    host_supported: false,
-    gtest: false,
-
-    defaults: [
-        "bionic_tests_defaults",
-    ],
-
-    whole_static_libs: [
-        "libBionicTests",
-        "libBionicLoaderTests",
-        "libBionicElfTlsLoaderTests",
-    ],
-
-    static_libs: [
-        "libtinyxml2",
-        "liblog",
-        "libbase",
-        "libgtest_isolated",
-    ],
-
-    srcs: [
-        // TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
-        "__cxa_thread_atexit_test.cpp",
-        "gtest_globals.cpp",
-        "gtest_main.cpp",
-        "gwp_asan_test.cpp",
-        "thread_local_test.cpp",
-    ],
-
-    conlyflags: [
-        "-fexceptions",
-        "-fnon-call-exceptions",
-    ],
-
-    ldflags: ["-Wl,--export-dynamic"],
-
-    include_dirs: ["bionic/libc"],
-
-    stl: "libc++_static",
-
-    target: {
-        android: {
-            shared_libs: [
-                "ld-android",
-                "libdl",
-                "libdl_android",
-                "libdl_preempt_test_1",
-                "libdl_preempt_test_2",
-                "libdl_test_df_1_global",
-                "libtest_elftls_shared_var",
-                "libtest_elftls_tprel",
-            ],
-            static_libs: [
-                // The order of these libraries matters, do not shuffle them.
-                "libmeminfo",
-                "libziparchive",
-                "libz",
-                "libutils",
-            ],
-            ldflags: [
-                "-Wl,--rpath,${ORIGIN}/bionic-loader-test-libs",
-                "-Wl,--enable-new-dtags",
-            ],
-        },
-    },
-
+    name: "bionic_unit_tests_data",
     data_bins: [
         "cfi_test_helper",
         "cfi_test_helper2",
@@ -967,7 +896,6 @@
         "thread_exit_cb_helper",
         "tls_properties_helper",
     ],
-
     data_libs: [
         "libatest_simple_zip",
         "libcfi-test",
@@ -1104,6 +1032,81 @@
     ],
 }
 
+// -----------------------------------------------------------------------------
+// Tests for the device using bionic's .so. Run with:
+//   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
+//   adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests
+// -----------------------------------------------------------------------------
+cc_defaults {
+    name: "bionic_unit_tests_defaults",
+    host_supported: false,
+    gtest: false,
+
+    defaults: [
+        "bionic_tests_defaults",
+        "bionic_unit_tests_data",
+    ],
+
+    whole_static_libs: [
+        "libBionicTests",
+        "libBionicLoaderTests",
+        "libBionicElfTlsLoaderTests",
+    ],
+
+    static_libs: [
+        "libtinyxml2",
+        "liblog",
+        "libbase",
+        "libgtest_isolated",
+    ],
+
+    srcs: [
+        // TODO: Include __cxa_thread_atexit_test.cpp to glibc tests once it is upgraded (glibc 2.18+)
+        "__cxa_thread_atexit_test.cpp",
+        "gtest_globals.cpp",
+        "gtest_main.cpp",
+        "gwp_asan_test.cpp",
+        "thread_local_test.cpp",
+    ],
+
+    conlyflags: [
+        "-fexceptions",
+        "-fnon-call-exceptions",
+    ],
+
+    ldflags: ["-Wl,--export-dynamic"],
+
+    include_dirs: ["bionic/libc"],
+
+    stl: "libc++_static",
+
+    target: {
+        android: {
+            shared_libs: [
+                "ld-android",
+                "libdl",
+                "libdl_android",
+                "libdl_preempt_test_1",
+                "libdl_preempt_test_2",
+                "libdl_test_df_1_global",
+                "libtest_elftls_shared_var",
+                "libtest_elftls_tprel",
+            ],
+            static_libs: [
+                // The order of these libraries matters, do not shuffle them.
+                "libmeminfo",
+                "libziparchive",
+                "libz",
+                "libutils",
+            ],
+            ldflags: [
+                "-Wl,--rpath,${ORIGIN}/bionic-loader-test-libs",
+                "-Wl,--enable-new-dtags",
+            ],
+        },
+    },
+}
+
 cc_test {
     name: "bionic-unit-tests",
     defaults: [
diff --git a/tests/sys_hwprobe_test.cpp b/tests/sys_hwprobe_test.cpp
index 15028ff..a4b47c7 100644
--- a/tests/sys_hwprobe_test.cpp
+++ b/tests/sys_hwprobe_test.cpp
@@ -30,10 +30,11 @@
 
 #if __has_include(<sys/hwprobe.h>)
 #include <sys/hwprobe.h>
+#include <sys/syscall.h>
 #endif
 
 TEST(sys_hwprobe, __riscv_hwprobe) {
-#if defined(__riscv) && __has_include(<sys/cachectl.h>)
+#if defined(__riscv) && __has_include(<sys/hwprobe.h>)
   riscv_hwprobe probes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0},
                             {.key = RISCV_HWPROBE_KEY_CPUPERF_0}};
   ASSERT_EQ(0, __riscv_hwprobe(probes, 2, 0, nullptr, 0));
@@ -60,3 +61,25 @@
   GTEST_SKIP() << "__riscv_hwprobe requires riscv64";
 #endif
 }
+
+TEST(sys_hwprobe, __riscv_hwprobe_syscall_vdso) {
+#if defined(__riscv) && __has_include(<sys/hwprobe.h>)
+  riscv_hwprobe probes_vdso[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0},
+                                 {.key = RISCV_HWPROBE_KEY_CPUPERF_0}};
+  ASSERT_EQ(0, __riscv_hwprobe(probes_vdso, 2, 0, nullptr, 0));
+
+  riscv_hwprobe probes_syscall[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0},
+                                    {.key = RISCV_HWPROBE_KEY_CPUPERF_0}};
+  ASSERT_EQ(0, syscall(SYS_riscv_hwprobe, probes_syscall, 2, 0, nullptr, 0));
+
+  // Check we got the same answers from the vdso and the syscall.
+  EXPECT_EQ(RISCV_HWPROBE_KEY_IMA_EXT_0, probes_syscall[0].key);
+  EXPECT_EQ(probes_vdso[0].key, probes_syscall[0].key);
+  EXPECT_EQ(probes_vdso[0].value, probes_syscall[0].value);
+  EXPECT_EQ(RISCV_HWPROBE_KEY_CPUPERF_0, probes_syscall[1].key);
+  EXPECT_EQ(probes_vdso[1].key, probes_syscall[1].key);
+  EXPECT_EQ(probes_vdso[1].value, probes_syscall[1].value);
+#else
+  GTEST_SKIP() << "__riscv_hwprobe requires riscv64";
+#endif
+}