1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker *
4*8d67ca89SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*8d67ca89SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*8d67ca89SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*8d67ca89SAndroid Build Coastguard Worker *
8*8d67ca89SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*8d67ca89SAndroid Build Coastguard Worker *
10*8d67ca89SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*8d67ca89SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*8d67ca89SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8d67ca89SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*8d67ca89SAndroid Build Coastguard Worker * limitations under the License.
15*8d67ca89SAndroid Build Coastguard Worker */
16*8d67ca89SAndroid Build Coastguard Worker
17*8d67ca89SAndroid Build Coastguard Worker #include <gtest/gtest.h>
18*8d67ca89SAndroid Build Coastguard Worker
19*8d67ca89SAndroid Build Coastguard Worker #include <sys/auxv.h>
20*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
21*8d67ca89SAndroid Build Coastguard Worker #include <sys/ifunc.h>
22*8d67ca89SAndroid Build Coastguard Worker #endif
23*8d67ca89SAndroid Build Coastguard Worker
24*8d67ca89SAndroid Build Coastguard Worker typedef int (*fn_ptr_t)();
25*8d67ca89SAndroid Build Coastguard Worker
ret42()26*8d67ca89SAndroid Build Coastguard Worker int ret42() {
27*8d67ca89SAndroid Build Coastguard Worker return 42;
28*8d67ca89SAndroid Build Coastguard Worker }
29*8d67ca89SAndroid Build Coastguard Worker
resolver()30*8d67ca89SAndroid Build Coastguard Worker extern "C" fn_ptr_t resolver() {
31*8d67ca89SAndroid Build Coastguard Worker return ret42;
32*8d67ca89SAndroid Build Coastguard Worker }
33*8d67ca89SAndroid Build Coastguard Worker
34*8d67ca89SAndroid Build Coastguard Worker int ifunc() __attribute__((ifunc("resolver")));
35*8d67ca89SAndroid Build Coastguard Worker
TEST(ifunc,function)36*8d67ca89SAndroid Build Coastguard Worker TEST(ifunc, function) {
37*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(42, ifunc());
38*8d67ca89SAndroid Build Coastguard Worker }
39*8d67ca89SAndroid Build Coastguard Worker
40*8d67ca89SAndroid Build Coastguard Worker #if defined(__BIONIC__)
41*8d67ca89SAndroid Build Coastguard Worker
42*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
43*8d67ca89SAndroid Build Coastguard Worker
44*8d67ca89SAndroid Build Coastguard Worker static uint64_t g_hwcap;
45*8d67ca89SAndroid Build Coastguard Worker static __ifunc_arg_t g_arg;
46*8d67ca89SAndroid Build Coastguard Worker
hwcap_resolver(uint64_t hwcap,__ifunc_arg_t * arg)47*8d67ca89SAndroid Build Coastguard Worker extern "C" fn_ptr_t hwcap_resolver(uint64_t hwcap, __ifunc_arg_t* arg)
48*8d67ca89SAndroid Build Coastguard Worker __attribute__((no_sanitize("hwaddress"))) {
49*8d67ca89SAndroid Build Coastguard Worker g_hwcap = hwcap;
50*8d67ca89SAndroid Build Coastguard Worker g_arg = *arg;
51*8d67ca89SAndroid Build Coastguard Worker return ret42;
52*8d67ca89SAndroid Build Coastguard Worker }
53*8d67ca89SAndroid Build Coastguard Worker
54*8d67ca89SAndroid Build Coastguard Worker #elif defined(__arm__)
55*8d67ca89SAndroid Build Coastguard Worker
56*8d67ca89SAndroid Build Coastguard Worker static unsigned long g_hwcap;
57*8d67ca89SAndroid Build Coastguard Worker
hwcap_resolver(unsigned long hwcap)58*8d67ca89SAndroid Build Coastguard Worker extern "C" fn_ptr_t hwcap_resolver(unsigned long hwcap) {
59*8d67ca89SAndroid Build Coastguard Worker g_hwcap = hwcap;
60*8d67ca89SAndroid Build Coastguard Worker return ret42;
61*8d67ca89SAndroid Build Coastguard Worker }
62*8d67ca89SAndroid Build Coastguard Worker
63*8d67ca89SAndroid Build Coastguard Worker #elif defined(__riscv)
64*8d67ca89SAndroid Build Coastguard Worker
65*8d67ca89SAndroid Build Coastguard Worker #include <sys/hwprobe.h>
66*8d67ca89SAndroid Build Coastguard Worker
67*8d67ca89SAndroid Build Coastguard Worker static uint64_t g_hwcap;
68*8d67ca89SAndroid Build Coastguard Worker static __riscv_hwprobe_t g_hwprobe_ptr;
69*8d67ca89SAndroid Build Coastguard Worker static void* g_null;
70*8d67ca89SAndroid Build Coastguard Worker
71*8d67ca89SAndroid Build Coastguard Worker static riscv_hwprobe g_hwprobes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0}};
72*8d67ca89SAndroid Build Coastguard Worker
hwcap_resolver(uint64_t hwcap,__riscv_hwprobe_t hwprobe_ptr,void * null)73*8d67ca89SAndroid Build Coastguard Worker extern "C" fn_ptr_t hwcap_resolver(uint64_t hwcap, __riscv_hwprobe_t hwprobe_ptr, void* null) {
74*8d67ca89SAndroid Build Coastguard Worker g_hwcap = hwcap;
75*8d67ca89SAndroid Build Coastguard Worker g_hwprobe_ptr = hwprobe_ptr;
76*8d67ca89SAndroid Build Coastguard Worker g_null = null;
77*8d67ca89SAndroid Build Coastguard Worker
78*8d67ca89SAndroid Build Coastguard Worker // Ensure that __riscv_hwprobe() can be called from an ifunc.
79*8d67ca89SAndroid Build Coastguard Worker if ((*hwprobe_ptr)(g_hwprobes, 1, 0, nullptr, 0) != 0) return nullptr;
80*8d67ca89SAndroid Build Coastguard Worker return ret42;
81*8d67ca89SAndroid Build Coastguard Worker }
82*8d67ca89SAndroid Build Coastguard Worker
83*8d67ca89SAndroid Build Coastguard Worker #else
84*8d67ca89SAndroid Build Coastguard Worker
hwcap_resolver()85*8d67ca89SAndroid Build Coastguard Worker extern "C" fn_ptr_t hwcap_resolver() {
86*8d67ca89SAndroid Build Coastguard Worker return ret42;
87*8d67ca89SAndroid Build Coastguard Worker }
88*8d67ca89SAndroid Build Coastguard Worker
89*8d67ca89SAndroid Build Coastguard Worker #endif
90*8d67ca89SAndroid Build Coastguard Worker
91*8d67ca89SAndroid Build Coastguard Worker int hwcap() __attribute__((ifunc("hwcap_resolver")));
92*8d67ca89SAndroid Build Coastguard Worker
TEST(ifunc,hwcap)93*8d67ca89SAndroid Build Coastguard Worker TEST(ifunc, hwcap) {
94*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(42, hwcap());
95*8d67ca89SAndroid Build Coastguard Worker
96*8d67ca89SAndroid Build Coastguard Worker #if defined(__aarch64__)
97*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(getauxval(AT_HWCAP) | _IFUNC_ARG_HWCAP, g_hwcap);
98*8d67ca89SAndroid Build Coastguard Worker
99*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(__ifunc_arg_t), g_arg._size);
100*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(getauxval(AT_HWCAP), g_arg._hwcap);
101*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(getauxval(AT_HWCAP2), g_arg._hwcap2);
102*8d67ca89SAndroid Build Coastguard Worker #elif defined(__arm__)
103*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(getauxval(AT_HWCAP), g_hwcap);
104*8d67ca89SAndroid Build Coastguard Worker #elif defined(__riscv)
105*8d67ca89SAndroid Build Coastguard Worker printf("hwcap=%lx hwprobe_ptr=%p (__riscv_hwprobe=%p) null=%p\n", g_hwcap, g_hwprobe_ptr,
106*8d67ca89SAndroid Build Coastguard Worker __riscv_hwprobe, g_null);
107*8d67ca89SAndroid Build Coastguard Worker
108*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(getauxval(AT_HWCAP), g_hwcap);
109*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(nullptr, g_null);
110*8d67ca89SAndroid Build Coastguard Worker
111*8d67ca89SAndroid Build Coastguard Worker riscv_hwprobe probes[] = {{.key = RISCV_HWPROBE_KEY_IMA_EXT_0}};
112*8d67ca89SAndroid Build Coastguard Worker ASSERT_EQ(0, __riscv_hwprobe(probes, 1, 0, nullptr, 0));
113*8d67ca89SAndroid Build Coastguard Worker EXPECT_EQ(probes[0].value, g_hwprobes[0].value);
114*8d67ca89SAndroid Build Coastguard Worker #endif
115*8d67ca89SAndroid Build Coastguard Worker }
116*8d67ca89SAndroid Build Coastguard Worker
117*8d67ca89SAndroid Build Coastguard Worker #endif // defined(__BIONIC__)
118