1 1.1 mrg /* __cxa_atexit backwards-compatibility support for Darwin. 2 1.10 mrg Copyright (C) 2006-2022 Free Software Foundation, Inc. 3 1.1 mrg 4 1.1 mrg This file is part of GCC. 5 1.1 mrg 6 1.1 mrg GCC is free software; you can redistribute it and/or modify it under 7 1.1 mrg the terms of the GNU General Public License as published by the Free 8 1.1 mrg Software Foundation; either version 3, or (at your option) any later 9 1.1 mrg version. 10 1.1 mrg 11 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 1.1 mrg for more details. 15 1.1 mrg 16 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 17 1.1 mrg permissions described in the GCC Runtime Library Exception, version 18 1.1 mrg 3.1, as published by the Free Software Foundation. 19 1.1 mrg 20 1.1 mrg You should have received a copy of the GNU General Public License and 21 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 22 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 1.1 mrg <http://www.gnu.org/licenses/>. */ 24 1.1 mrg 25 1.1 mrg /* Don't do anything if we are compiling for a kext multilib. */ 26 1.1 mrg #ifdef __PIC__ 27 1.1 mrg 28 1.1 mrg #include "tconfig.h" 29 1.1 mrg #include "tsystem.h" 30 1.1 mrg 31 1.1 mrg #include <dlfcn.h> 32 1.1 mrg #include <stdbool.h> 33 1.1 mrg #include <stdlib.h> 34 1.1 mrg #include <string.h> 35 1.1 mrg 36 1.1 mrg /* This file works around two different problems. 37 1.1 mrg 38 1.1 mrg The first problem is that there is no __cxa_atexit on Mac OS versions 39 1.1 mrg before 10.4. It fixes this by providing a complete atexit and 40 1.1 mrg __cxa_atexit emulation called from the regular atexit. 41 1.1 mrg 42 1.1 mrg The second problem is that on all shipping versions of Mac OS, 43 1.1 mrg __cxa_finalize and exit() don't work right: they don't run routines 44 1.1 mrg that were registered while other atexit routines are running. This 45 1.1 mrg is worked around by wrapping each atexit/__cxa_atexit routine with 46 1.1 mrg our own routine which ensures that any __cxa_atexit calls while it 47 1.1 mrg is running are honoured. 48 1.1 mrg 49 1.1 mrg There are still problems which this does not solve. Before 10.4, 50 1.1 mrg shared objects linked with previous compilers won't have their 51 1.1 mrg atexit calls properly interleaved with code compiled with newer 52 1.1 mrg compilers. Also, atexit routines registered from shared objects 53 1.1 mrg linked with previous compilers won't get the bug fix. */ 54 1.1 mrg 55 1.1 mrg typedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, const void* dso); 56 1.1 mrg typedef void (*cxa_finalize_p)(const void *dso); 57 1.1 mrg typedef int (*atexit_p)(void (*func)(void)); 58 1.1 mrg 59 1.1 mrg /* These are from "keymgr.h". */ 60 1.1 mrg extern void *_keymgr_get_and_lock_processwide_ptr (unsigned key); 61 1.1 mrg extern int _keymgr_get_and_lock_processwide_ptr_2 (unsigned, void **); 62 1.1 mrg extern int _keymgr_set_and_unlock_processwide_ptr (unsigned key, void *ptr); 63 1.1 mrg 64 1.1 mrg extern void *__keymgr_global[]; 65 1.1 mrg typedef struct _Sinfo_Node { 66 1.1 mrg unsigned int size ; /*size of this node*/ 67 1.1 mrg unsigned short major_version ; /*API major version.*/ 68 1.1 mrg unsigned short minor_version ; /*API minor version.*/ 69 1.1 mrg } _Tinfo_Node ; 70 1.1 mrg 71 1.1 mrg #ifdef __ppc__ 72 1.1 mrg #define CHECK_KEYMGR_ERROR(e) \ 73 1.1 mrg (((_Tinfo_Node *)__keymgr_global[2])->major_version >= 4 ? (e) : 0) 74 1.1 mrg #else 75 1.1 mrg #define CHECK_KEYMGR_ERROR(e) (e) 76 1.1 mrg #endif 77 1.1 mrg 78 1.1 mrg /* Our globals are stored under this keymgr index. */ 79 1.1 mrg #define KEYMGR_ATEXIT_LIST 14 80 1.1 mrg 81 1.1 mrg /* The different kinds of callback routines. */ 82 1.1 mrg typedef void (*atexit_callback)(void); 83 1.1 mrg typedef void (*cxa_atexit_callback)(void *); 84 1.1 mrg 85 1.1 mrg /* This structure holds a routine to call. There may be extra fields 86 1.1 mrg at the end of the structure that this code doesn't know about. */ 87 1.1 mrg struct one_atexit_routine 88 1.1 mrg { 89 1.1 mrg union { 90 1.1 mrg atexit_callback ac; 91 1.1 mrg cxa_atexit_callback cac; 92 1.1 mrg } callback; 93 1.1 mrg /* has_arg is 0/2/4 if 'ac' is live, 1/3/5 if 'cac' is live. 94 1.1 mrg Higher numbers indicate a later version of the structure that this 95 1.1 mrg code doesn't understand and will ignore. */ 96 1.1 mrg int has_arg; 97 1.1 mrg void * arg; 98 1.1 mrg }; 99 1.1 mrg 100 1.1 mrg struct atexit_routine_list 101 1.1 mrg { 102 1.1 mrg struct atexit_routine_list * next; 103 1.1 mrg struct one_atexit_routine r; 104 1.1 mrg }; 105 1.1 mrg 106 1.1 mrg /* The various possibilities for status of atexit(). */ 107 1.1 mrg enum atexit_status { 108 1.1 mrg atexit_status_unknown = 0, 109 1.1 mrg atexit_status_missing = 1, 110 1.1 mrg atexit_status_broken = 2, 111 1.1 mrg atexit_status_working = 16 112 1.1 mrg }; 113 1.1 mrg 114 1.1 mrg struct keymgr_atexit_list 115 1.1 mrg { 116 1.1 mrg /* Version of this list. This code knows only about version 0. 117 1.1 mrg If the version is higher than 0, this code may add new atexit routines 118 1.1 mrg but should not attempt to run the list. */ 119 1.1 mrg short version; 120 1.1 mrg /* 1 if an atexit routine is currently being run by this code, 0 121 1.1 mrg otherwise. */ 122 1.1 mrg char running_routines; 123 1.1 mrg /* Holds a value from 'enum atexit_status'. */ 124 1.1 mrg unsigned char atexit_status; 125 1.1 mrg /* The list of atexit and cxa_atexit routines registered. If 126 1.1 mrg atexit_status_missing it contains all routines registered while 127 1.1 mrg linked with this code. If atexit_status_broken it contains all 128 1.1 mrg routines registered during cxa_finalize while linked with this 129 1.1 mrg code. */ 130 1.1 mrg struct atexit_routine_list *l; 131 1.1 mrg /* &__cxa_atexit; set if atexit_status >= atexit_status_broken. */ 132 1.1 mrg cxa_atexit_p cxa_atexit_f; 133 1.1 mrg /* &__cxa_finalize; set if atexit_status >= atexit_status_broken. */ 134 1.1 mrg cxa_finalize_p cxa_finalize_f; 135 1.1 mrg /* &atexit; set if atexit_status >= atexit_status_working 136 1.1 mrg or atexit_status == atexit_status_missing. */ 137 1.1 mrg atexit_p atexit_f; 138 1.1 mrg }; 139 1.1 mrg 140 1.1 mrg /* Return 0 if __cxa_atexit has the bug it has in Mac OS 10.4: it 141 1.1 mrg fails to call routines registered while an atexit routine is 142 1.1 mrg running. Return 1 if it works properly, and -1 if an error occurred. */ 143 1.1 mrg 144 1.1 mrg struct atexit_data 145 1.1 mrg { 146 1.1 mrg int result; 147 1.1 mrg cxa_atexit_p cxa_atexit; 148 1.1 mrg }; 149 1.1 mrg 150 1.1 mrg static void cxa_atexit_check_2 (void *arg) 151 1.1 mrg { 152 1.1 mrg ((struct atexit_data *)arg)->result = 1; 153 1.1 mrg } 154 1.1 mrg 155 1.1 mrg static void cxa_atexit_check_1 (void *arg) 156 1.1 mrg { 157 1.1 mrg struct atexit_data * aed = arg; 158 1.1 mrg if (aed->cxa_atexit (cxa_atexit_check_2, arg, arg) != 0) 159 1.1 mrg aed->result = -1; 160 1.1 mrg } 161 1.1 mrg 162 1.1 mrg static int 163 1.1 mrg check_cxa_atexit (cxa_atexit_p cxa_atexit, cxa_finalize_p cxa_finalize) 164 1.1 mrg { 165 1.1 mrg struct atexit_data aed = { 0, cxa_atexit }; 166 1.1 mrg 167 1.1 mrg /* We re-use &aed as the 'dso' parameter, since it's a unique address. */ 168 1.1 mrg if (cxa_atexit (cxa_atexit_check_1, &aed, &aed) != 0) 169 1.1 mrg return -1; 170 1.1 mrg cxa_finalize (&aed); 171 1.1 mrg if (aed.result == 0) 172 1.1 mrg { 173 1.1 mrg /* Call __cxa_finalize again to make sure that cxa_atexit_check_2 174 1.1 mrg is removed from the list before AED goes out of scope. */ 175 1.1 mrg cxa_finalize (&aed); 176 1.1 mrg aed.result = 0; 177 1.1 mrg } 178 1.1 mrg return aed.result; 179 1.1 mrg } 180 1.1 mrg 181 1.1 mrg #ifdef __ppc__ 182 1.1 mrg /* This comes from Csu. It works only before 10.4. The prototype has 183 1.1 mrg been altered a bit to avoid casting. */ 184 1.1 mrg extern int _dyld_func_lookup(const char *dyld_func_name, 185 1.1 mrg void *address) __attribute__((visibility("hidden"))); 186 1.1 mrg 187 1.1 mrg static void our_atexit (void); 188 1.1 mrg 189 1.1 mrg /* We're running on 10.3.9. Find the address of the system atexit() 190 1.1 mrg function. So easy to say, so hard to do. */ 191 1.1 mrg static atexit_p 192 1.1 mrg find_atexit_10_3 (void) 193 1.1 mrg { 194 1.1 mrg unsigned int (*dyld_image_count_fn)(void); 195 1.1 mrg const char *(*dyld_get_image_name_fn)(unsigned int image_index); 196 1.1 mrg const void *(*dyld_get_image_header_fn)(unsigned int image_index); 197 1.1 mrg const void *(*NSLookupSymbolInImage_fn)(const void *image, 198 1.1 mrg const char *symbolName, 199 1.1 mrg unsigned int options); 200 1.1 mrg void *(*NSAddressOfSymbol_fn)(const void *symbol); 201 1.1 mrg unsigned i, count; 202 1.1 mrg 203 1.1 mrg /* Find some dyld functions. */ 204 1.1 mrg _dyld_func_lookup("__dyld_image_count", &dyld_image_count_fn); 205 1.1 mrg _dyld_func_lookup("__dyld_get_image_name", &dyld_get_image_name_fn); 206 1.1 mrg _dyld_func_lookup("__dyld_get_image_header", &dyld_get_image_header_fn); 207 1.1 mrg _dyld_func_lookup("__dyld_NSLookupSymbolInImage", &NSLookupSymbolInImage_fn); 208 1.1 mrg _dyld_func_lookup("__dyld_NSAddressOfSymbol", &NSAddressOfSymbol_fn); 209 1.1 mrg 210 1.1 mrg /* If any of these don't exist, that's an error. */ 211 1.1 mrg if (! dyld_image_count_fn || ! dyld_get_image_name_fn 212 1.1 mrg || ! dyld_get_image_header_fn || ! NSLookupSymbolInImage_fn 213 1.1 mrg || ! NSAddressOfSymbol_fn) 214 1.1 mrg return NULL; 215 1.1 mrg 216 1.1 mrg count = dyld_image_count_fn (); 217 1.1 mrg for (i = 0; i < count; i++) 218 1.1 mrg { 219 1.1 mrg const char * path = dyld_get_image_name_fn (i); 220 1.1 mrg const void * image; 221 1.1 mrg const void * symbol; 222 1.1 mrg 223 1.1 mrg if (strcmp (path, "/usr/lib/libSystem.B.dylib") != 0) 224 1.1 mrg continue; 225 1.1 mrg image = dyld_get_image_header_fn (i); 226 1.1 mrg if (! image) 227 1.1 mrg return NULL; 228 1.1 mrg /* '4' is NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR. */ 229 1.1 mrg symbol = NSLookupSymbolInImage_fn (image, "_atexit", 4); 230 1.1 mrg if (! symbol) 231 1.1 mrg return NULL; 232 1.1 mrg return NSAddressOfSymbol_fn (symbol); 233 1.1 mrg } 234 1.1 mrg return NULL; 235 1.1 mrg } 236 1.1 mrg #endif 237 1.1 mrg 238 1.1 mrg /* Create (if necessary), find, lock, fill in, and return our globals. 239 1.1 mrg Return NULL on error, in which case the globals will not be locked. 240 1.1 mrg The caller should call keymgr_set_and_unlock. */ 241 1.1 mrg static struct keymgr_atexit_list * 242 1.1 mrg get_globals (void) 243 1.1 mrg { 244 1.1 mrg struct keymgr_atexit_list * r; 245 1.1 mrg 246 1.1 mrg #ifdef __ppc__ 247 1.1 mrg /* 10.3.9 doesn't have _keymgr_get_and_lock_processwide_ptr_2 so the 248 1.1 mrg PPC side can't use it. On 10.4 this just means the error gets 249 1.1 mrg reported a little later when 250 1.1 mrg _keymgr_set_and_unlock_processwide_ptr finds that the key was 251 1.1 mrg never locked. */ 252 1.1 mrg r = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); 253 1.1 mrg #else 254 1.1 mrg void * rr; 255 1.1 mrg if (_keymgr_get_and_lock_processwide_ptr_2 (KEYMGR_ATEXIT_LIST, &rr)) 256 1.1 mrg return NULL; 257 1.1 mrg r = rr; 258 1.1 mrg #endif 259 1.1 mrg 260 1.1 mrg if (r == NULL) 261 1.1 mrg { 262 1.1 mrg r = calloc (sizeof (struct keymgr_atexit_list), 1); 263 1.1 mrg if (! r) 264 1.1 mrg return NULL; 265 1.1 mrg } 266 1.1 mrg 267 1.1 mrg if (r->atexit_status == atexit_status_unknown) 268 1.1 mrg { 269 1.1 mrg void *handle; 270 1.1 mrg 271 1.1 mrg handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD); 272 1.1 mrg if (!handle) 273 1.1 mrg { 274 1.1 mrg #ifdef __ppc__ 275 1.1 mrg r->atexit_status = atexit_status_missing; 276 1.1 mrg r->atexit_f = find_atexit_10_3 (); 277 1.1 mrg if (! r->atexit_f) 278 1.1 mrg goto error; 279 1.1 mrg if (r->atexit_f (our_atexit)) 280 1.1 mrg goto error; 281 1.1 mrg #else 282 1.1 mrg goto error; 283 1.1 mrg #endif 284 1.1 mrg } 285 1.1 mrg else 286 1.1 mrg { 287 1.1 mrg int chk_result; 288 1.1 mrg 289 1.1 mrg r->cxa_atexit_f = (cxa_atexit_p)dlsym (handle, "__cxa_atexit"); 290 1.1 mrg r->cxa_finalize_f = (cxa_finalize_p)dlsym (handle, "__cxa_finalize"); 291 1.1 mrg if (! r->cxa_atexit_f || ! r->cxa_finalize_f) 292 1.1 mrg goto error; 293 1.1 mrg 294 1.1 mrg chk_result = check_cxa_atexit (r->cxa_atexit_f, r->cxa_finalize_f); 295 1.1 mrg if (chk_result == -1) 296 1.1 mrg goto error; 297 1.1 mrg else if (chk_result == 0) 298 1.1 mrg r->atexit_status = atexit_status_broken; 299 1.1 mrg else 300 1.1 mrg { 301 1.1 mrg r->atexit_f = (atexit_p)dlsym (handle, "atexit"); 302 1.1 mrg if (! r->atexit_f) 303 1.1 mrg goto error; 304 1.1 mrg r->atexit_status = atexit_status_working; 305 1.1 mrg } 306 1.1 mrg } 307 1.1 mrg } 308 1.1 mrg 309 1.1 mrg return r; 310 1.1 mrg 311 1.1 mrg error: 312 1.1 mrg _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, r); 313 1.1 mrg return NULL; 314 1.1 mrg } 315 1.1 mrg 316 1.1 mrg /* Add TO_ADD to ATEXIT_LIST. ATEXIT_LIST may be NULL but is 317 1.1 mrg always the result of calling _keymgr_get_and_lock_processwide_ptr and 318 1.1 mrg so KEYMGR_ATEXIT_LIST is known to be locked; this routine is responsible 319 1.1 mrg for unlocking it. */ 320 1.1 mrg 321 1.1 mrg static int 322 1.1 mrg add_routine (struct keymgr_atexit_list * g, 323 1.1 mrg const struct one_atexit_routine * to_add) 324 1.1 mrg { 325 1.1 mrg struct atexit_routine_list * s 326 1.1 mrg = malloc (sizeof (struct atexit_routine_list)); 327 1.1 mrg int result; 328 1.1 mrg 329 1.1 mrg if (!s) 330 1.1 mrg { 331 1.1 mrg _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); 332 1.1 mrg return -1; 333 1.1 mrg } 334 1.1 mrg s->r = *to_add; 335 1.1 mrg s->next = g->l; 336 1.1 mrg g->l = s; 337 1.1 mrg result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); 338 1.1 mrg return CHECK_KEYMGR_ERROR (result) == 0 ? 0 : -1; 339 1.1 mrg } 340 1.1 mrg 341 1.1 mrg /* This runs the routines in G->L up to STOP. */ 342 1.1 mrg static struct keymgr_atexit_list * 343 1.1 mrg run_routines (struct keymgr_atexit_list *g, 344 1.1 mrg struct atexit_routine_list *stop) 345 1.1 mrg { 346 1.1 mrg for (;;) 347 1.1 mrg { 348 1.1 mrg struct atexit_routine_list * cur = g->l; 349 1.1 mrg if (! cur || cur == stop) 350 1.1 mrg break; 351 1.1 mrg g->l = cur->next; 352 1.1 mrg _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); 353 1.1 mrg 354 1.1 mrg switch (cur->r.has_arg) { 355 1.1 mrg case 0: case 2: case 4: 356 1.1 mrg cur->r.callback.ac (); 357 1.1 mrg break; 358 1.1 mrg case 1: case 3: case 5: 359 1.1 mrg cur->r.callback.cac (cur->r.arg); 360 1.1 mrg break; 361 1.1 mrg default: 362 1.1 mrg /* Don't understand, so don't call it. */ 363 1.1 mrg break; 364 1.1 mrg } 365 1.1 mrg free (cur); 366 1.1 mrg 367 1.1 mrg g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); 368 1.1 mrg if (! g) 369 1.1 mrg break; 370 1.1 mrg } 371 1.1 mrg return g; 372 1.1 mrg } 373 1.1 mrg 374 1.1 mrg /* Call the routine described by ROUTINE_PARAM and then call any 375 1.1 mrg routines added to KEYMGR_ATEXIT_LIST while that routine was 376 1.1 mrg running, all with in_cxa_finalize set. */ 377 1.1 mrg 378 1.1 mrg static void 379 1.1 mrg cxa_atexit_wrapper (void* routine_param) 380 1.1 mrg { 381 1.1 mrg struct one_atexit_routine * routine = routine_param; 382 1.1 mrg struct keymgr_atexit_list *g; 383 1.1 mrg struct atexit_routine_list * base = NULL; 384 1.1 mrg char prev_running = 0; 385 1.1 mrg 386 1.1 mrg g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); 387 1.1 mrg if (g) 388 1.1 mrg { 389 1.1 mrg prev_running = g->running_routines; 390 1.1 mrg g->running_routines = 1; 391 1.1 mrg base = g->l; 392 1.1 mrg _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); 393 1.1 mrg } 394 1.1 mrg 395 1.1 mrg if (routine->has_arg) 396 1.1 mrg routine->callback.cac (routine->arg); 397 1.1 mrg else 398 1.1 mrg routine->callback.ac (); 399 1.1 mrg 400 1.1 mrg if (g) 401 1.1 mrg g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); 402 1.1 mrg if (g) 403 1.1 mrg g = run_routines (g, base); 404 1.1 mrg if (g) 405 1.1 mrg { 406 1.1 mrg g->running_routines = prev_running; 407 1.1 mrg _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); 408 1.1 mrg } 409 1.1 mrg } 410 1.1 mrg 411 1.1 mrg #ifdef __ppc__ 412 1.1 mrg /* This code is used while running on 10.3.9, when __cxa_atexit doesn't 413 1.1 mrg exist in the system library. 10.3.9 only supported regular PowerPC, 414 1.1 mrg so this code isn't necessary on x86 or ppc64. */ 415 1.1 mrg 416 1.1 mrg /* This routine is called from the system atexit(); it runs everything 417 1.1 mrg registered on the KEYMGR_ATEXIT_LIST. */ 418 1.1 mrg 419 1.1 mrg static void 420 1.1 mrg our_atexit (void) 421 1.1 mrg { 422 1.1 mrg struct keymgr_atexit_list *g; 423 1.1 mrg char prev_running; 424 1.1 mrg 425 1.1 mrg g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST); 426 1.1 mrg if (! g || g->version != 0 || g->atexit_status != atexit_status_missing) 427 1.1 mrg return; 428 1.1 mrg 429 1.1 mrg prev_running = g->running_routines; 430 1.1 mrg g->running_routines = 1; 431 1.1 mrg g = run_routines (g, NULL); 432 1.1 mrg if (! g) 433 1.1 mrg return; 434 1.1 mrg g->running_routines = prev_running; 435 1.1 mrg _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); 436 1.1 mrg } 437 1.1 mrg #endif 438 1.1 mrg 439 1.1 mrg /* This is our wrapper around atexit and __cxa_atexit. It will return 440 1.1 mrg nonzero if an error occurs, and otherwise: 441 1.1 mrg - if in_cxa_finalize is set, or running on 10.3.9, add R to 442 1.1 mrg KEYMGR_ATEXIT_LIST; or 443 1.1 mrg - call the system __cxa_atexit to add cxa_atexit_wrapper with an argument 444 1.1 mrg that indicates how cxa_atexit_wrapper should call R. */ 445 1.1 mrg 446 1.1 mrg static int 447 1.1 mrg atexit_common (const struct one_atexit_routine *r, const void *dso) 448 1.1 mrg { 449 1.1 mrg struct keymgr_atexit_list *g = get_globals (); 450 1.1 mrg 451 1.1 mrg if (! g) 452 1.1 mrg return -1; 453 1.1 mrg 454 1.1 mrg if (g->running_routines || g->atexit_status == atexit_status_missing) 455 1.1 mrg return add_routine (g, r); 456 1.1 mrg 457 1.1 mrg if (g->atexit_status >= atexit_status_working) 458 1.1 mrg { 459 1.1 mrg int result; 460 1.1 mrg if (r->has_arg) 461 1.1 mrg { 462 1.1 mrg cxa_atexit_p cxa_atexit = g->cxa_atexit_f; 463 1.1 mrg result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, 464 1.1 mrg g); 465 1.1 mrg if (CHECK_KEYMGR_ERROR (result)) 466 1.1 mrg return -1; 467 1.1 mrg return cxa_atexit (r->callback.cac, r->arg, dso); 468 1.1 mrg } 469 1.1 mrg else 470 1.1 mrg { 471 1.1 mrg atexit_p atexit_f = g->atexit_f; 472 1.1 mrg result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, 473 1.1 mrg g); 474 1.1 mrg if (CHECK_KEYMGR_ERROR (result)) 475 1.1 mrg return -1; 476 1.1 mrg return atexit_f (r->callback.ac); 477 1.1 mrg } 478 1.1 mrg } 479 1.1 mrg else 480 1.1 mrg { 481 1.1 mrg cxa_atexit_p cxa_atexit = g->cxa_atexit_f; 482 1.1 mrg struct one_atexit_routine *alloced; 483 1.1 mrg int result; 484 1.1 mrg 485 1.1 mrg result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g); 486 1.1 mrg if (CHECK_KEYMGR_ERROR (result)) 487 1.1 mrg return -1; 488 1.1 mrg 489 1.1 mrg alloced = malloc (sizeof (struct one_atexit_routine)); 490 1.1 mrg if (! alloced) 491 1.1 mrg return -1; 492 1.1 mrg *alloced = *r; 493 1.1 mrg return cxa_atexit (cxa_atexit_wrapper, alloced, dso); 494 1.1 mrg } 495 1.1 mrg } 496 1.1 mrg 497 1.1 mrg /* These are the actual replacement routines; they just funnel into 498 1.1 mrg atexit_common. */ 499 1.1 mrg 500 1.1 mrg int __cxa_atexit (cxa_atexit_callback func, void* arg, 501 1.1 mrg const void* dso) __attribute__((visibility("hidden"))); 502 1.1 mrg 503 1.1 mrg int 504 1.1 mrg __cxa_atexit (cxa_atexit_callback func, void* arg, const void* dso) 505 1.1 mrg { 506 1.1 mrg struct one_atexit_routine r; 507 1.1 mrg r.callback.cac = func; 508 1.1 mrg r.has_arg = 1; 509 1.1 mrg r.arg = arg; 510 1.1 mrg return atexit_common (&r, dso); 511 1.1 mrg } 512 1.1 mrg 513 1.1 mrg int atexit (atexit_callback func) __attribute__((visibility("hidden"))); 514 1.1 mrg 515 1.1 mrg /* Use __dso_handle to allow even bundles that call atexit() to be unloaded 516 1.1 mrg on 10.4. */ 517 1.1 mrg extern void __dso_handle; 518 1.1 mrg 519 1.1 mrg int 520 1.1 mrg atexit (atexit_callback func) 521 1.1 mrg { 522 1.1 mrg struct one_atexit_routine r; 523 1.1 mrg r.callback.ac = func; 524 1.1 mrg r.has_arg = 0; 525 1.1 mrg return atexit_common (&r, &__dso_handle); 526 1.1 mrg } 527 1.1 mrg 528 1.1 mrg #endif /* __PIC__ */ 529