Merge "sysconf(): implement cache queries." into main
diff --git a/docs/status.md b/docs/status.md
index 5514935..de2fa10 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -65,6 +65,10 @@
* New system call wrappers: `__riscv_flush_icache` (`<sys/cachectl.h>`),
`__riscv_hwprobe` (`<sys/hwprobe.h>`).
+New libc behavior in V (API level 35):
+ * Added `LD_SHOW_AUXV` to the dynamic linker to dump the ELF auxiliary
+ vector if the environment variable is set.
+
New libc functions in U (API level 34):
* `close_range` and `copy_file_range` (Linux-specific GNU extensions).
* `memset_explicit` in <string.h> (C23 addition).
diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp
index 420560f..2bff616 100644
--- a/libc/async_safe/async_safe_log.cpp
+++ b/libc/async_safe/async_safe_log.cpp
@@ -207,10 +207,12 @@
// Decode the conversion specifier.
int is_signed = (conversion == 'd' || conversion == 'i' || conversion == 'o');
int base = 10;
- if (conversion == 'x' || conversion == 'X') {
+ if (tolower(conversion) == 'x') {
base = 16;
} else if (conversion == 'o') {
base = 8;
+ } else if (tolower(conversion) == 'b') {
+ base = 2;
}
bool caps = (conversion == 'X');
@@ -360,7 +362,8 @@
format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x');
} else if (c == 'm') {
strerror_r(errno, buffer, sizeof(buffer));
- } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') {
+ } else if (tolower(c) == 'b' || c == 'd' || c == 'i' || c == 'o' || c == 'u' ||
+ tolower(c) == 'x') {
/* integers - first read value from stack */
uint64_t value;
int is_signed = (c == 'd' || c == 'i' || c == 'o');
@@ -391,10 +394,10 @@
value = static_cast<uint64_t>((static_cast<int64_t>(value << shift)) >> shift);
}
- if (alternate && value != 0 && (c == 'x' || c == 'o')) {
- if (c == 'x') {
+ if (alternate && value != 0 && (tolower(c) == 'x' || c == 'o' || tolower(c) == 'b')) {
+ if (tolower(c) == 'x' || tolower(c) == 'b') {
buffer[0] = '0';
- buffer[1] = 'x';
+ buffer[1] = c;
format_integer(buffer + 2, sizeof(buffer) - 2, value, c);
} else {
buffer[0] = '0';
diff --git a/libc/bionic/bionic_call_ifunc_resolver.cpp b/libc/bionic/bionic_call_ifunc_resolver.cpp
index 410eb78..3cfb8b5 100644
--- a/libc/bionic/bionic_call_ifunc_resolver.cpp
+++ b/libc/bionic/bionic_call_ifunc_resolver.cpp
@@ -58,12 +58,12 @@
}
return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(hwcap);
#elif defined(__riscv)
- // This argument and its value is just a placeholder for now,
- // but it means that if we do pass something in future (such as
- // getauxval() and/or hwprobe key/value pairs), callees will be able to
- // recognize what they're being given.
- typedef ElfW(Addr) (*ifunc_resolver_t)(void*);
- return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(nullptr);
+ // The pointer argument is currently unused, but reserved for future
+ // expansion. If we pass nullptr from the beginning, it'll be easier
+ // to recognize if/when we pass actual data (and matches glibc).
+ typedef ElfW(Addr) (*ifunc_resolver_t)(uint64_t, void*);
+ static uint64_t hwcap = getauxval(AT_HWCAP);
+ return reinterpret_cast<ifunc_resolver_t>(resolver_addr)(hwcap, nullptr);
#else
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
return reinterpret_cast<ifunc_resolver_t>(resolver_addr)();
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index d7a2856..a3c66d4 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -356,7 +356,7 @@
if (memtag_stack) {
void* pg_start =
reinterpret_cast<void*>(page_start(reinterpret_cast<uintptr_t>(stack_top)));
- if (mprotect(pg_start, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_MTE | PROT_GROWSDOWN)) {
+ if (mprotect(pg_start, page_size(), PROT_READ | PROT_WRITE | PROT_MTE | PROT_GROWSDOWN)) {
async_safe_fatal("error: failed to set PROT_MTE on main thread stack: %m");
}
}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index 7efbf6d..3b9e6a4 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -38,6 +38,8 @@
#define __hwasan_thread_exit()
#endif
+#include "platform/bionic/page.h"
+
#include "private/bionic_elf_tls.h"
#include "private/bionic_lock.h"
#include "private/bionic_tls.h"
@@ -236,7 +238,7 @@
// On LP64, we could use more but there's no obvious advantage to doing
// so, and the various media processes use RLIMIT_AS as a way to limit
// the amount of allocation they'll do.
-#define PTHREAD_GUARD_SIZE PAGE_SIZE
+#define PTHREAD_GUARD_SIZE max_page_size()
// SIGSTKSZ (8KiB) is not big enough.
// An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack.
diff --git a/libc/include/bits/page_size.h b/libc/include/bits/page_size.h
new file mode 100644
index 0000000..ca434e5
--- /dev/null
+++ b/libc/include/bits/page_size.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#if !defined(__BIONIC_NO_PAGE_SIZE_MACRO)
+#define PAGE_SIZE 4096
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+#endif
+
+__END_DECLS
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 1f08628..4feade5 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -34,6 +34,7 @@
*/
#include <limits.h>
+#include <bits/page_size.h>
#include <bits/pthread_types.h>
#include <sched.h>
#include <sys/cdefs.h>
@@ -73,9 +74,14 @@
#define PTHREAD_BARRIER_SERIAL_THREAD (-1)
#endif
+
#if defined(__LP64__)
+#if defined(PAGE_SIZE)
#define PTHREAD_STACK_MIN (4 * PAGE_SIZE)
#else
+#define PTHREAD_STACK_MIN 65536
+#endif
+#else
#define PTHREAD_STACK_MIN (2 * PAGE_SIZE)
#endif
diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h
index 6d047ae..0aaaac5 100644
--- a/libc/include/setjmp.h
+++ b/libc/include/setjmp.h
@@ -66,12 +66,14 @@
/**
* The size in words of a riscv64 jmp_buf. Room for callee-saved registers,
* including floating point, stack pointer and program counter, various
- * internal implementation details, and leaving some free space.
+ * internal implementation details, and leaving lots of free space.
*
- * Coincidentally matches OpenBSD, though they also save/restore the
- * floating point status register too.
+ * Deliberately very large given the uncertainty around the final form of
+ * hardware shadow stack, and the fact that x86-64 glibc needed to steal
+ * space from their enormous sigset_t (which we don't have) to be able to
+ * implement the CET shadow stack.
*/
-#define _JBLEN 32
+#define _JBLEN 64
#elif defined(__x86_64__)
/** The size in words of an x86-64 jmp_buf. Inherited from OpenBSD. */
#define _JBLEN 11
diff --git a/libc/include/sys/user.h b/libc/include/sys/user.h
index 0ea0285..1d20034 100644
--- a/libc/include/sys/user.h
+++ b/libc/include/sys/user.h
@@ -32,12 +32,9 @@
#include <stddef.h> /* For size_t. */
#include <stdint.h>
-__BEGIN_DECLS
+#include <bits/page_size.h>
-#if !defined(__BIONIC_NO_PAGE_SIZE_MACRO)
-#define PAGE_SIZE 4096
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-#endif
+__BEGIN_DECLS
#if defined(__i386__)
diff --git a/linker/Android.bp b/linker/Android.bp
index 020bd7d..0ccd16d 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -169,6 +169,7 @@
srcs: [
"dlfcn.cpp",
"linker.cpp",
+ "linker_auxv.cpp",
"linker_block_allocator.cpp",
"linker_dlwarning.cpp",
"linker_cfi.cpp",
diff --git a/linker/NOTICE b/linker/NOTICE
index d61a193..7fd1877 100644
--- a/linker/NOTICE
+++ b/linker/NOTICE
@@ -362,3 +362,31 @@
-------------------------------------------------------------------
+Copyright (C) 2023 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
diff --git a/linker/linker_auxv.cpp b/linker/linker_auxv.cpp
new file mode 100644
index 0000000..d8e4a3e
--- /dev/null
+++ b/linker/linker_auxv.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "linker_auxv.h"
+
+#include <elf.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <unistd.h>
+
+#include <async_safe/log.h>
+
+static const char* auxv_name(int at) {
+ switch (at) {
+ case AT_NULL: return "AT_NULL";
+ case AT_IGNORE: return "AT_IGNORE";
+ case AT_EXECFD: return "AT_EXECFD";
+ case AT_PHDR: return "AT_PHDR";
+ case AT_PHENT: return "AT_PHENT";
+ case AT_PHNUM: return "AT_PHNUM";
+ case AT_PAGESZ: return "AT_PAGESZ";
+ case AT_BASE: return "AT_BASE";
+ case AT_FLAGS: return "AT_FLAGS";
+ case AT_ENTRY: return "AT_ENTRY";
+ case AT_NOTELF: return "AT_NOTELF";
+ case AT_UID: return "AT_UID";
+ case AT_EUID: return "AT_EUID";
+ case AT_GID: return "AT_GID";
+ case AT_EGID: return "AT_EGID";
+ case AT_PLATFORM: return "AT_PLATFORM";
+ case AT_HWCAP: return "AT_HWCAP";
+ case AT_CLKTCK: return "AT_CLKTCK";
+ case AT_SECURE: return "AT_SECURE";
+ case AT_BASE_PLATFORM: return "AT_BASE_PLATFORM";
+ case AT_RANDOM: return "AT_RANDOM";
+ case AT_HWCAP2: return "AT_HWCAP2";
+ case AT_RSEQ_FEATURE_SIZE: return "AT_RSEQ_FEATURE_SIZE";
+ case AT_RSEQ_ALIGN: return "AT_RSEQ_ALIGN";
+ case AT_EXECFN: return "AT_EXECFN";
+ case AT_SYSINFO_EHDR: return "AT_SYSINFO_EHDR";
+#if defined(AT_MINSIGSTKSZ)
+ case AT_MINSIGSTKSZ: return "AT_MINSIGSTKSZ";
+#endif
+#if defined(AT_SYSINFO)
+ case AT_SYSINFO: return "AT_SYSINFO";
+#endif
+#if defined(AT_L1I_CACHESIZE)
+ case AT_L1I_CACHESIZE: return "AT_L1I_CACHESIZE";
+#endif
+#if defined(AT_L1I_CACHEGEOMETRY)
+ case AT_L1I_CACHEGEOMETRY: return "AT_L1I_CACHEGEOMETRY";
+#endif
+#if defined(AT_L1D_CACHESIZE)
+ case AT_L1D_CACHESIZE: return "AT_L1D_CACHESIZE";
+#endif
+#if defined(AT_L1D_CACHEGEOMETRY)
+ case AT_L1D_CACHEGEOMETRY: return "AT_L1D_CACHEGEOMETRY";
+#endif
+#if defined(AT_L2_CACHESIZE)
+ case AT_L2_CACHESIZE: return "AT_L2_CACHESIZE";
+#endif
+#if defined(AT_L2_CACHEGEOMETRY)
+ case AT_L2_CACHEGEOMETRY: return "AT_L2_CACHEGEOMETRY";
+#endif
+ }
+ static char name[32];
+ snprintf(name, sizeof(name), "AT_??? (%d)", at);
+ return name;
+}
+
+void ld_show_auxv(ElfW(auxv_t)* auxv) {
+ for (ElfW(auxv_t)* v = auxv; v->a_type != AT_NULL; ++v) {
+ const char* name = auxv_name(v->a_type);
+ long value = v->a_un.a_val;
+ switch (v->a_type) {
+ case AT_SYSINFO_EHDR:
+ case AT_PHDR:
+ case AT_BASE:
+ case AT_ENTRY:
+ case AT_RANDOM:
+ async_safe_format_fd(STDOUT_FILENO, "%-20s %#lx\n", name, value);
+ break;
+ case AT_FLAGS:
+ case AT_HWCAP:
+ case AT_HWCAP2:
+ async_safe_format_fd(STDOUT_FILENO, "%-20s %#lb\n", name, value);
+ break;
+ case AT_EXECFN:
+ case AT_PLATFORM:
+ async_safe_format_fd(STDOUT_FILENO, "%-20s \"%s\"\n", name, reinterpret_cast<char*>(value));
+ break;
+ default:
+ async_safe_format_fd(STDOUT_FILENO, "%-20s %ld\n", name, value);
+ break;
+ }
+ }
+}
diff --git a/linker/linker_auxv.h b/linker/linker_auxv.h
new file mode 100644
index 0000000..c093283
--- /dev/null
+++ b/linker/linker_auxv.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <elf.h>
+#include <link.h>
+
+void ld_show_auxv(ElfW(auxv_t)* auxv);
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 8a20670..5a33a63 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -32,6 +32,7 @@
#include <sys/auxv.h>
#include "linker.h"
+#include "linker_auxv.h"
#include "linker_cfi.h"
#include "linker_debug.h"
#include "linker_debuggerd.h"
@@ -324,12 +325,14 @@
g_linker_logger.ResetState();
- // Get a few environment variables.
+ // Enable debugging logs?
const char* LD_DEBUG = getenv("LD_DEBUG");
if (LD_DEBUG != nullptr) {
g_ld_debug_verbosity = atoi(LD_DEBUG);
}
+ if (getenv("LD_SHOW_AUXV") != nullptr) ld_show_auxv(args.auxv);
+
#if defined(__LP64__)
INFO("[ Android dynamic linker (64-bit) ]");
#else
diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp
index dc4db07..cc1b598 100644
--- a/tests/async_safe_test.cpp
+++ b/tests/async_safe_test.cpp
@@ -45,6 +45,15 @@
async_safe_format_buffer(buf, sizeof(buf), "aa%scc", "bb");
EXPECT_STREQ("aabbcc", buf);
+ async_safe_format_buffer(buf, sizeof(buf), "a%bb", 1234);
+ EXPECT_STREQ("a10011010010b", buf);
+
+ async_safe_format_buffer(buf, sizeof(buf), "a%#bb", 1234);
+ EXPECT_STREQ("a0b10011010010b", buf);
+
+ async_safe_format_buffer(buf, sizeof(buf), "a%#Bb", 1234);
+ EXPECT_STREQ("a0B10011010010b", buf);
+
async_safe_format_buffer(buf, sizeof(buf), "a%cc", 'b');
EXPECT_STREQ("abc", buf);
@@ -76,9 +85,15 @@
async_safe_format_buffer(buf, sizeof(buf), "a%xz", 0x12ab);
EXPECT_STREQ("a12abz", buf);
+ async_safe_format_buffer(buf, sizeof(buf), "a%#xz", 0x12ab);
+ EXPECT_STREQ("a0x12abz", buf);
+
async_safe_format_buffer(buf, sizeof(buf), "a%Xz", 0x12ab);
EXPECT_STREQ("a12ABz", buf);
+ async_safe_format_buffer(buf, sizeof(buf), "a%#Xz", 0x12ab);
+ EXPECT_STREQ("a0X12ABz", buf);
+
async_safe_format_buffer(buf, sizeof(buf), "a%08xz", 0x123456);
EXPECT_STREQ("a00123456z", buf);
diff --git a/tests/ifunc_test.cpp b/tests/ifunc_test.cpp
index e3c437e..1fdbf1a 100644
--- a/tests/ifunc_test.cpp
+++ b/tests/ifunc_test.cpp
@@ -60,6 +60,26 @@
return ret42;
}
+#elif defined(__riscv)
+
+#include <sys/hwprobe.h>
+
+static uint64_t g_hwcap;
+
+static riscv_hwprobe g_hwprobes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0}};
+
+extern "C" fn_ptr_t hwcap_resolver(uint64_t hwcap, void* null) {
+ // Check hwcap like arm32/arm64.
+ g_hwcap = hwcap;
+
+ // For now, the pointer argument is reserved for future expansion.
+ if (null != NULL) abort();
+
+ // Ensure that __riscv_hwprobe() can be called from an ifunc.
+ if (__riscv_hwprobe(g_hwprobes, 1, 0, nullptr, 0) != 0) return nullptr;
+ return ret42;
+}
+
#else
extern "C" fn_ptr_t hwcap_resolver() {
@@ -81,6 +101,12 @@
EXPECT_EQ(getauxval(AT_HWCAP2), g_arg._hwcap2);
#elif defined(__arm__)
EXPECT_EQ(getauxval(AT_HWCAP), g_hwcap);
+#elif defined(__riscv)
+ EXPECT_EQ(getauxval(AT_HWCAP), g_hwcap);
+
+ riscv_hwprobe probes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0}};
+ ASSERT_EQ(0, __riscv_hwprobe(probes, 1, 0, nullptr, 0));
+ EXPECT_EQ(probes[0].value, g_hwprobes[0].value);
#endif
}