1 /* $NetBSD: t_ifunc.c,v 1.13 2022/06/21 16:24:37 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 32 #include <atf-c.h> 33 #include <dlfcn.h> 34 #include <util.h> 35 36 #include "h_macros.h" 37 38 #if \ 39 defined(__aarch64__) || \ 40 defined(__arm__) || \ 41 defined(__i386__) || \ 42 defined(__powerpc__) || \ 43 defined(__sparc__) || \ 44 defined(__x86_64__) 45 #define LINKER_SUPPORT 1 46 #else 47 #define LINKER_SUPPORT 0 48 #endif 49 50 ATF_TC(rtld_ifunc); 51 52 ATF_TC_HEAD(rtld_ifunc, tc) 53 { 54 atf_tc_set_md_var(tc, "descr", "ifunc functions are resolved"); 55 } 56 57 ATF_TC_BODY(rtld_ifunc, tc) 58 { 59 const char *envstr[] = { 60 "0", "1" 61 }; 62 long long expected_result[] = { 63 0xdeadbeefll, 0xbeefdeadll 64 }; 65 void *handle; 66 long long (*sym)(void); 67 long long result; 68 const char *error; 69 size_t i; 70 71 if (!LINKER_SUPPORT) 72 atf_tc_skip("Missing linker support for ifunc relocations"); 73 74 for (i = 0; i < __arraycount(envstr); ++i) { 75 setenv("USE_IFUNC2", envstr[i], 1); 76 77 handle = dlopen("libh_helper_ifunc_dso.so", RTLD_LAZY); 78 error = dlerror(); 79 ATF_CHECK(error == NULL); 80 ATF_CHECK(handle != NULL); 81 82 sym = dlsym(handle, "ifunc"); 83 error = dlerror(); 84 ATF_CHECK(error == NULL); 85 ATF_CHECK(sym != NULL); 86 87 result = (*sym)(); 88 ATF_CHECK(result == expected_result[i]); 89 90 dlclose(handle); 91 error = dlerror(); 92 ATF_CHECK(error == NULL); 93 94 char *command; 95 easprintf(&command, "%s/h_ifunc %lld", 96 atf_tc_get_config_var(tc, "srcdir"), expected_result[i]); 97 if (system(command) != EXIT_SUCCESS) 98 atf_tc_fail("Test failed; see output for details"); 99 free(command); 100 } 101 } 102 103 ATF_TC(rtld_hidden_ifunc); 104 105 ATF_TC_HEAD(rtld_hidden_ifunc, tc) 106 { 107 atf_tc_set_md_var(tc, "descr", "hidden ifunc functions are resolved"); 108 } 109 110 ATF_TC_BODY(rtld_hidden_ifunc, tc) 111 { 112 const char *envstr[] = { 113 "0", "1" 114 }; 115 long long expected_result[] = { 116 0xdeadbeefll, 0xbeefdeadll 117 }; 118 void *handle; 119 long long (*sym)(void); 120 long long (*(*sym2)(void))(void); 121 long long result; 122 const char *error; 123 size_t i; 124 125 if (!LINKER_SUPPORT) 126 atf_tc_skip("Missing linker support for ifunc relocations"); 127 128 for (i = 0; i < __arraycount(envstr); ++i) { 129 setenv("USE_IFUNC2", envstr[i], 1); 130 131 handle = dlopen("libh_helper_ifunc_dso.so", RTLD_LAZY); 132 error = dlerror(); 133 ATF_CHECK(error == NULL); 134 ATF_CHECK(handle != NULL); 135 136 sym = dlsym(handle, "ifunc_plt"); 137 error = dlerror(); 138 ATF_CHECK(error == NULL); 139 ATF_CHECK(sym != NULL); 140 141 result = (*sym)(); 142 ATF_CHECK(result == expected_result[!i]); 143 144 sym2 = dlsym(handle, "ifunc_indirect"); 145 error = dlerror(); 146 ATF_CHECK(error == NULL); 147 ATF_CHECK(sym2 != NULL); 148 149 sym = (*sym2)(); 150 result = (*sym)(); 151 ATF_CHECK(result == expected_result[!i]); 152 153 dlclose(handle); 154 error = dlerror(); 155 ATF_CHECK(error == NULL); 156 157 char *command; 158 easprintf(&command, "%s/h_ifunc %lld", 159 atf_tc_get_config_var(tc, "srcdir"), expected_result[i]); 160 if (system(command) != EXIT_SUCCESS) 161 atf_tc_fail("Test failed; see output for details"); 162 free(command); 163 } 164 } 165 166 ATF_TC(rtld_main_ifunc); 167 ATF_TC_HEAD(rtld_main_ifunc, tc) 168 { 169 atf_tc_set_md_var(tc, "descr", 170 "ifunc functions are resolved in the executable"); 171 } 172 173 #if LINKER_SUPPORT 174 static long long 175 ifunc_helper(void) 176 { 177 return 0xdeadbeefll; 178 } 179 180 static __attribute__((used)) 181 long long (*resolve_ifunc(void))(void) 182 { 183 return ifunc_helper; 184 } 185 __hidden_ifunc(ifunc, resolve_ifunc); 186 #endif 187 long long ifunc(void); 188 189 ATF_TC_BODY(rtld_main_ifunc, tc) 190 { 191 if (!LINKER_SUPPORT) 192 atf_tc_skip("Missing linker support for ifunc relocations"); 193 ATF_CHECK(ifunc() == 0xdeadbeefll); 194 } 195 196 ATF_TP_ADD_TCS(tp) 197 { 198 ATF_TP_ADD_TC(tp, rtld_ifunc); 199 ATF_TP_ADD_TC(tp, rtld_hidden_ifunc); 200 ATF_TP_ADD_TC(tp, rtld_main_ifunc); 201 return atf_no_error(); 202 } 203