1 /* $NetBSD: t_ifunc.c,v 1.8 2018/03/09 20:15:03 joerg 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 defined( __arm__) || defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || defined(__sparc__) 39 #define LINKER_SUPPORT 1 40 #else 41 #define LINKER_SUPPORT 0 42 #endif 43 44 ATF_TC(rtld_ifunc); 45 46 ATF_TC_HEAD(rtld_ifunc, tc) 47 { 48 atf_tc_set_md_var(tc, "descr", "ifunc functions are resolved"); 49 } 50 51 ATF_TC_BODY(rtld_ifunc, tc) 52 { 53 const char *envstr[] = { 54 "0", "1" 55 }; 56 long long expected_result[] = { 57 0xdeadbeefll, 0xbeefdeadll 58 }; 59 void *handle; 60 long long (*sym)(void); 61 long long result; 62 const char *error; 63 size_t i; 64 65 if (!LINKER_SUPPORT) 66 atf_tc_skip("Missing linker support for ifunc relocations"); 67 68 for (i = 0; i < __arraycount(envstr); ++i) { 69 setenv("USE_IFUNC2", envstr[i], 1); 70 71 handle = dlopen("libh_helper_ifunc_dso.so", RTLD_LAZY); 72 error = dlerror(); 73 ATF_CHECK(error == NULL); 74 ATF_CHECK(handle != NULL); 75 76 sym = dlsym(handle, "ifunc"); 77 error = dlerror(); 78 ATF_CHECK(error == NULL); 79 ATF_CHECK(sym != NULL); 80 81 result = (*sym)(); 82 ATF_CHECK(result == expected_result[i]); 83 84 dlclose(handle); 85 error = dlerror(); 86 ATF_CHECK(error == NULL); 87 88 char *command; 89 easprintf(&command, "%s/h_ifunc %lld", 90 atf_tc_get_config_var(tc, "srcdir"), expected_result[i]); 91 if (system(command) != EXIT_SUCCESS) 92 atf_tc_fail("Test failed; see output for details"); 93 free(command); 94 } 95 } 96 97 ATF_TC(rtld_hidden_ifunc); 98 99 ATF_TC_HEAD(rtld_hidden_ifunc, tc) 100 { 101 atf_tc_set_md_var(tc, "descr", "hidden ifunc functions are resolved"); 102 } 103 104 ATF_TC_BODY(rtld_hidden_ifunc, tc) 105 { 106 const char *envstr[] = { 107 "0", "1" 108 }; 109 long long expected_result[] = { 110 0xdeadbeefll, 0xbeefdeadll 111 }; 112 void *handle; 113 long long (*sym)(void); 114 long long (*(*sym2)(void))(void); 115 long long result; 116 const char *error; 117 size_t i; 118 119 if (!LINKER_SUPPORT) 120 atf_tc_skip("Missing linker support for ifunc relocations"); 121 122 for (i = 0; i < __arraycount(envstr); ++i) { 123 setenv("USE_IFUNC2", envstr[i], 1); 124 125 handle = dlopen("libh_helper_ifunc_dso.so", RTLD_LAZY); 126 error = dlerror(); 127 ATF_CHECK(error == NULL); 128 ATF_CHECK(handle != NULL); 129 130 sym = dlsym(handle, "ifunc_plt"); 131 error = dlerror(); 132 ATF_CHECK(error == NULL); 133 ATF_CHECK(sym != NULL); 134 135 result = (*sym)(); 136 ATF_CHECK(result == expected_result[!i]); 137 138 sym2 = dlsym(handle, "ifunc_indirect"); 139 error = dlerror(); 140 ATF_CHECK(error == NULL); 141 ATF_CHECK(sym2 != NULL); 142 143 sym = (*sym2)(); 144 result = (*sym)(); 145 ATF_CHECK(result == expected_result[!i]); 146 147 dlclose(handle); 148 error = dlerror(); 149 ATF_CHECK(error == NULL); 150 151 char *command; 152 easprintf(&command, "%s/h_ifunc %lld", 153 atf_tc_get_config_var(tc, "srcdir"), expected_result[i]); 154 if (system(command) != EXIT_SUCCESS) 155 atf_tc_fail("Test failed; see output for details"); 156 free(command); 157 } 158 } 159 160 ATF_TC(rtld_main_ifunc); 161 ATF_TC_HEAD(rtld_main_ifunc, tc) 162 { 163 atf_tc_set_md_var(tc, "descr", 164 "ifunc functions are resolved in the executable"); 165 } 166 167 #if LINKER_SUPPORT 168 static long long 169 ifunc_helper(void) 170 { 171 return 0xdeadbeefll; 172 } 173 174 static __attribute__((used)) 175 long long (*resolve_ifunc(void))(void) 176 { 177 return ifunc_helper; 178 } 179 __hidden_ifunc(ifunc, resolve_ifunc); 180 #endif 181 long long ifunc(void); 182 183 ATF_TC_BODY(rtld_main_ifunc, tc) 184 { 185 if (!LINKER_SUPPORT) 186 atf_tc_skip("Missing linker support for ifunc relocations"); 187 ATF_CHECK(ifunc() == 0xdeadbeefll); 188 } 189 190 ATF_TP_ADD_TCS(tp) 191 { 192 ATF_TP_ADD_TC(tp, rtld_ifunc); 193 ATF_TP_ADD_TC(tp, rtld_hidden_ifunc); 194 ATF_TP_ADD_TC(tp, rtld_main_ifunc); 195 return 0; 196 } 197