int old_atexit(aefuncp func) #endif { /* * glibc casts aefuncp to cxaefuncp. * This seems dodgy, but I guess callling a function with more * parameters than it needs will work everywhere? */ #ifdef ARCH_HAS_MMU return __cxa_atexit((cxaefuncp)func, NULL, &__dso_handle == NULL ? NULL : __dso_handle); #else return __cxa_atexit((cxaefuncp)func, NULL, NULL); #endif }
/* is called by crt0 immediately before calling __main() */ void crt0_construction(void) { static_construction(); __cxa_atexit((void (*)(void*))&static_destruction, 0, &__dso_handle == 0 ? 0 : __dso_handle); }
int atexit (void (*fn) (void)) { extern int __cxa_atexit(void (*)(void*), void*, void*); extern void *__dso_handle; extern void *__ImageBase; void *fixed_dso_handle = &__dso_handle; /* Check for being called from inside the executable. If so, use NULL as __dso_handle. This allows to link executables with GCC versions not providing __dso_handle in crtbegin{S}.o. In this case our own __dso_handle defined in lib/dso_handle.c is used. However, our __dso_handle always points to &__ImageBase, while the __dso_handle for executables provided by crtbegin.o usually points to NULL. That's what we remodel here. */ if (&__ImageBase == (void **) GetModuleHandleW (NULL)) fixed_dso_handle = NULL; /* With recent Cygwin versions starting with API version 0.280 we call __cxa_atexit (which is actually the cygwin__cxa_atexit wrapper in dcrt0.cc) with the address of __dso_handle since that's how g++ generates calls to __cxa_atexit as well. However, when running an application built with this atexit under an older Cygwin version, the __cxa_atexit entry point is the one from newlib, which expects the *value* of __dso_handle. So, check for the Cygwin version we're running under. Older version prior to 0.280 don't know CW_FIXED_ATEXIT and return -1. 0.280 and later return 0. */ else if (cygwin_internal (CW_FIXED_ATEXIT) != 0) fixed_dso_handle = __dso_handle; return __cxa_atexit ((void (*)(void*))fn, NULL, fixed_dso_handle); }
__noreturn void __libc_init(void* raw_args, void (*onexit)(void), int (*slingshot)(int, char**, char**), structors_array_t const * const structors) { KernelArgumentBlock args(raw_args); __libc_init_tls(args); __libc_init_common(args); apply_gnu_relro(); // Several Linux ABIs don't pass the onexit pointer, and the ones that // do never use it. Therefore, we ignore it. call_array(structors->preinit_array); call_array(structors->init_array); // The executable may have its own destructors listed in its .fini_array // so we need to ensure that these are called when the program exits // normally. if (structors->fini_array != NULL) { __cxa_atexit(__libc_fini,structors->fini_array,NULL); } exit(slingshot(args.argc, args.argv, args.envp)); }
void bar (void *p) { extern void *__dso_handle; printf ("This is %s\n", __FUNCTION__); __cxa_atexit (fluffy, p, __dso_handle); }
// address: 8049e90 void proc2() { __size32 eax; // r24 if (eax != 0) { } __cxa_atexit(); return; }
int main(int argc, char *argv[]) { exiting_state = 5; ASSERT(0 == atexit(normal_handler_0)); ASSERT(0 == atexit(normal_handler_1)); ASSERT(0 == __cxa_atexit(cxa_handler_4, &arg_1, &dso_handle_1)); ASSERT(0 == __cxa_atexit(cxa_handler_5, &arg_1, &dso_handle_1)); ASSERT(0 == __cxa_atexit(cxa_handler_3, &arg_2, &dso_handle_2)); ASSERT(0 == __cxa_atexit(cxa_handler_2, &arg_3, &dso_handle_3)); __cxa_finalize(&dso_handle_1); __cxa_finalize(&dso_handle_2); exit(0); }
// address: 8048904 void atexit() { __size32 edx; // r26 if (edx != 0) { } __cxa_atexit(); return; }
int __libc_start_main (void) { /* Store the lowest stack address. */ __libc_stack_end = __libc_start_data.stack; /* Used by setenv */ __environ = __libc_start_data.envp; #ifndef SHARED /* Clear errno. */ errno = 0; /* Some security at this point. Prevent starting a SUID binary where the standard file descriptors are not opened. We have to do this only for statically linked applications since otherwise the dynamic loader did the work already. */ if (__builtin_expect (__libc_enable_secure, 0)) __libc_check_standard_fds (); #endif /* Register the destructor of the dynamic linker if there is any. */ if (__builtin_expect (__libc_start_data.rtld_fini != NULL, 1)) __cxa_atexit ((void (*) (void *)) __libc_start_data.rtld_fini, NULL, NULL); /* Call the initializer of the libc. This is only needed here if we are compiling for the static library in which case we haven't run the constructors in `_dl_start_user'. */ #ifndef SHARED __libc_init_first (__libc_start_data.argc, __libc_start_data.argv, __libc_start_data.envp); #endif /* Register the destructor of the program, if any. */ if (__libc_start_data.fini) __cxa_atexit ((void (*) (void *)) __libc_start_data.fini, NULL, NULL); /* Call the initializer of the program, if any. */ if (__libc_start_data.init) (*__libc_start_data.init) (); exit ((*__libc_start_data.main) (__libc_start_data.argc, __libc_start_data.argv, __libc_start_data.envp)); }
/* Register FUNC to be executed by `exit'. */ int #ifndef atexit attribute_hidden #endif atexit (void (*func) (void)) { return __cxa_atexit ((void (*) (void *)) func, NULL, &__dso_handle == NULL ? NULL : __dso_handle); }
int main() { std::ios::sync_with_stdio(false); extern void* __dso_handle __attribute__ ((__weak__)); __cxa_atexit((void (*) (void *)) __libc_freeres, NULL, &__dso_handle ? __dso_handle : NULL); do_something(); return 0; }
/* This function is called from the executable's _start entry point * (see arch-$ARCH/bionic/crtbegin_dynamic.S), which is itself * called by the dynamic linker after it has loaded all shared * libraries the executable depends on. * * Note that the dynamic linker has also run all constructors in the * executable at this point. */ __noreturn void __libc_init(uintptr_t *elfdata, void (*onexit)(void), int (*slingshot)(int, char**, char**), structors_array_t const * const structors) { int argc = (int)*elfdata; char** argv = (char**)(elfdata + 1); char** envp = argv + argc + 1; /* Several Linux ABIs don't pass the onexit pointer, and the ones that * do never use it. Therefore, we ignore it. */ /* The executable may have its own destructors listed in its .fini_array * so we need to ensure that these are called when the program exits * normally. */ if (structors->fini_array) __cxa_atexit(__libc_fini,structors->fini_array,NULL); exit(slingshot(argc, argv, envp)); }
__noreturn void __libc_init(uintptr_t *elfdata, void (*onexit)(void), int (*slingshot)(int, char**, char**), structors_array_t const * const structors) { int argc; char **argv, **envp; __libc_init_tls(NULL); /* Initialize the C runtime environment */ __libc_init_common(elfdata); /* Several Linux ABIs don't pass the onexit pointer, and the ones that * do never use it. Therefore, we ignore it. */ /* pre-init array. */ call_array(structors->preinit_array); // call static constructors call_array(structors->init_array); argc = (int) *elfdata; argv = (char**)(elfdata + 1); envp = argv + argc + 1; /* The executable may have its own destructors listed in its .fini_array * so we need to ensure that these are called when the program exits * normally. */ if (structors->fini_array) __cxa_atexit(__libc_fini,structors->fini_array,NULL); apply_gnu_relro(); exit(slingshot(argc, argv, envp)); }
int atexit (void (*func) ()) { return __cxa_atexit ((void (*)(void*))func, 0, 0); }
int __aeabi_atexit (void *arg, void (*func) (void *), void *d) { //printf("__aeabi_atexit(%X, %X, %X)\n", arg, func, d); return __cxa_atexit (func, arg, d); }
/* * Copy of atexit() used by libc and anything staticly linked into the * executable. This passes NULL for the dso, so the callbacks are only * invoked by exit() and not dlclose() */ int atexit(void (*fn)(void)) { return (__cxa_atexit((void (*)(void *))fn, NULL, NULL)); }
// Initializes memory allocation framework once per process. static void malloc_init_impl(libc_globals* globals) { char value[PROP_VALUE_MAX]; // If DEBUG_MALLOC_ENV_OPTIONS is set then it overrides the system properties. const char* options = getenv(DEBUG_MALLOC_ENV_OPTIONS); if (options == nullptr || options[0] == '\0') { if (__system_property_get(DEBUG_MALLOC_PROPERTY_OPTIONS, value) == 0 || value[0] == '\0') { return; } options = value; // Check to see if only a specific program should have debug malloc enabled. char program[PROP_VALUE_MAX]; if (__system_property_get(DEBUG_MALLOC_PROPERTY_PROGRAM, program) != 0 && strstr(getprogname(), program) == nullptr) { return; } } // Load the debug malloc shared library. void* malloc_impl_handle = dlopen(DEBUG_SHARED_LIB, RTLD_NOW | RTLD_LOCAL); if (malloc_impl_handle == nullptr) { error_log("%s: Unable to open debug malloc shared library %s: %s", getprogname(), DEBUG_SHARED_LIB, dlerror()); return; } // Initialize malloc debugging in the loaded module. auto init_func = reinterpret_cast<bool (*)(const MallocDispatch*, int*, const char*)>( dlsym(malloc_impl_handle, "debug_initialize")); if (init_func == nullptr) { error_log("%s: debug_initialize routine not found in %s", getprogname(), DEBUG_SHARED_LIB); dlclose(malloc_impl_handle); return; } // Get the syms for the external functions. void* finalize_sym = dlsym(malloc_impl_handle, "debug_finalize"); if (finalize_sym == nullptr) { error_log("%s: debug_finalize routine not found in %s", getprogname(), DEBUG_SHARED_LIB); dlclose(malloc_impl_handle); return; } void* get_leak_info_sym = dlsym(malloc_impl_handle, "debug_get_malloc_leak_info"); if (get_leak_info_sym == nullptr) { error_log("%s: debug_get_malloc_leak_info routine not found in %s", getprogname(), DEBUG_SHARED_LIB); dlclose(malloc_impl_handle); return; } void* free_leak_info_sym = dlsym(malloc_impl_handle, "debug_free_malloc_leak_info"); if (free_leak_info_sym == nullptr) { error_log("%s: debug_free_malloc_leak_info routine not found in %s", getprogname(), DEBUG_SHARED_LIB); dlclose(malloc_impl_handle); return; } void* malloc_backtrace_sym = dlsym(malloc_impl_handle, "debug_malloc_backtrace"); if (malloc_backtrace_sym == nullptr) { error_log("%s: debug_malloc_backtrace routine not found in %s", getprogname(), DEBUG_SHARED_LIB); dlclose(malloc_impl_handle); return; } if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options)) { dlclose(malloc_impl_handle); return; } MallocDispatch malloc_dispatch_table; if (!InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "debug")) { auto finalize_func = reinterpret_cast<void (*)()>(finalize_sym); finalize_func(); dlclose(malloc_impl_handle); return; } g_debug_finalize_func = reinterpret_cast<void (*)()>(finalize_sym); g_debug_get_malloc_leak_info_func = reinterpret_cast<void (*)( uint8_t**, size_t*, size_t*, size_t*, size_t*)>(get_leak_info_sym); g_debug_free_malloc_leak_info_func = reinterpret_cast<void (*)(uint8_t*)>(free_leak_info_sym); g_debug_malloc_backtrace_func = reinterpret_cast<ssize_t (*)( void*, uintptr_t*, size_t)>(malloc_backtrace_sym); globals->malloc_dispatch = malloc_dispatch_table; libc_malloc_impl_handle = malloc_impl_handle; info_log("%s: malloc debug enabled", getprogname()); // Use atexit to trigger the cleanup function. This avoids a problem // where another atexit function is used to cleanup allocated memory, // but the finalize function was already called. This particular error // seems to be triggered by a zygote spawned process calling exit. int ret_value = __cxa_atexit(malloc_fini_impl, nullptr, nullptr); if (ret_value != 0) { error_log("failed to set atexit cleanup function: %d", ret_value); } }
int __aeabi_atexit(void *object, void (*func)(void*), void *dso) { return __cxa_atexit(func, object, dso); }
static void pthread_initialize(void) { struct sigaction sa; sigset_t mask; /* If already done (e.g. by a constructor called earlier!), bail out */ if (__pthread_initial_thread_bos != NULL) return; #ifdef TEST_FOR_COMPARE_AND_SWAP /* Test if compare-and-swap is available */ __pthread_has_cas = compare_and_swap_is_available(); #endif #ifdef FLOATING_STACKS /* We don't need to know the bottom of the stack. Give the pointer some value to signal that initialization happened. */ __pthread_initial_thread_bos = (void *) -1l; #else /* Determine stack size limits . */ __pthread_init_max_stacksize (); # ifdef _STACK_GROWS_UP /* The initial thread already has all the stack it needs */ __pthread_initial_thread_bos = (char *) ((long)CURRENT_STACK_FRAME &~ (STACK_SIZE - 1)); # else /* For the initial stack, reserve at least STACK_SIZE bytes of stack below the current stack address, and align that on a STACK_SIZE boundary. */ __pthread_initial_thread_bos = (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); # endif #endif /* Update the descriptor for the initial thread. */ __pthread_initial_thread.p_pid = __getpid(); /* Likewise for the resolver state _res. */ __pthread_initial_thread.p_resp = &_res; #ifdef __SIGRTMIN /* Initialize real-time signals. */ init_rtsigs (); #endif /* Setup signal handlers for the initial thread. Since signal handlers are shared between threads, these settings will be inherited by all other threads. */ sa.sa_handler = pthread_handle_sigrestart; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; __libc_sigaction(__pthread_sig_restart, &sa, NULL); sa.sa_handler = pthread_handle_sigcancel; // sa.sa_flags = 0; __libc_sigaction(__pthread_sig_cancel, &sa, NULL); if (__pthread_sig_debug > 0) { sa.sa_handler = pthread_handle_sigdebug; sigemptyset(&sa.sa_mask); // sa.sa_flags = 0; __libc_sigaction(__pthread_sig_debug, &sa, NULL); } /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ sigemptyset(&mask); sigaddset(&mask, __pthread_sig_restart); sigprocmask(SIG_BLOCK, &mask, NULL); /* Register an exit function to kill all other threads. */ /* Do it early so that user-registered atexit functions are called before pthread_*exit_process. */ #ifndef HAVE_Z_NODELETE if (__builtin_expect (&__dso_handle != NULL, 1)) __cxa_atexit ((void (*) (void *)) pthread_atexit_process, NULL, __dso_handle); else #endif on_exit (pthread_onexit_process, NULL); /* How many processors. */ __pthread_smp_kernel = is_smp_system (); }
/* Register FUNC to be executed by `exit'. */ int atexit (void (*func) (void)) { int __cxa_atexit (void (*func) (void *), void *arg, void *d); return __cxa_atexit ((void (*) (void *)) func, 0, 0); }
int atexit(void (*func)(void)) { return __cxa_atexit(call, (void *)(uintptr_t)func, 0); }
int atexit(void (*fn)(void)) { return (__cxa_atexit((void (*)(void *))fn, NULL, &__dso_handle)); }
__attribute__((weak)) int atexit(void (*func)(void)) { return __cxa_atexit(caller, func, NULL); }
int __pthread_initialize_manager(void) { int manager_pipe[2]; int pid; struct pthread_request request; #ifndef HAVE_Z_NODELETE if (__builtin_expect (&__dso_handle != NULL, 1)) __cxa_atexit ((void (*) (void *)) pthread_atexit_retcode, NULL, __dso_handle); #endif if (__pthread_max_stacksize == 0) __pthread_init_max_stacksize (); /* If basic initialization not done yet (e.g. we're called from a constructor run before our constructor), do it now */ if (__pthread_initial_thread_bos == NULL) pthread_initialize(); /* Setup stack for thread manager */ __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE); if (__pthread_manager_thread_bos == NULL) return -1; __pthread_manager_thread_tos = __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE; /* Setup pipe to communicate with thread manager */ if (__libc_pipe(manager_pipe) == -1) { free(__pthread_manager_thread_bos); return -1; } /* Start the thread manager */ pid = 0; if (__builtin_expect (__pthread_initial_thread.p_report_events, 0)) { /* It's a bit more complicated. We have to report the creation of the manager thread. */ int idx = __td_eventword (TD_CREATE); uint32_t mask = __td_eventmask (TD_CREATE); if ((mask & (__pthread_threads_events.event_bits[idx] | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx])) != 0) { __pthread_lock(__pthread_manager_thread.p_lock, NULL); #ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager_event, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #elif _STACK_GROWS_UP pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_bos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #else pid = __clone(__pthread_manager_event, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #endif if (pid != -1) { /* Now fill in the information about the new thread in the newly created thread's data structure. We cannot let the new thread do this since we don't know whether it was already scheduled when we send the event. */ __pthread_manager_thread.p_eventbuf.eventdata = &__pthread_manager_thread; __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE; __pthread_last_event = &__pthread_manager_thread; __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Now call the function which signals the event. */ __linuxthreads_create_event (); } /* Now restart the thread. */ __pthread_unlock(__pthread_manager_thread.p_lock); } } if (__builtin_expect (pid, 0) == 0) { #ifdef NEED_SEPARATE_REGISTER_STACK pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos, THREAD_MANAGER_STACK_SIZE, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #elif _STACK_GROWS_UP pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #else pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, (void *)(long)manager_pipe[0]); #endif } if (__builtin_expect (pid, 0) == -1) { free(__pthread_manager_thread_bos); __libc_close(manager_pipe[0]); __libc_close(manager_pipe[1]); return -1; } __pthread_manager_request = manager_pipe[1]; /* writing end */ __pthread_manager_reader = manager_pipe[0]; /* reading end */ __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; __pthread_manager_thread.p_pid = pid; /* Make gdb aware of new thread manager */ if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0) { raise(__pthread_sig_debug); /* We suspend ourself and gdb will wake us up when it is ready to handle us. */ __pthread_wait_for_restart_signal(thread_self()); } /* Synchronize debugging of the thread manager */ request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); return 0; }
int atexit(void (*func)(void)) { return __cxa_atexit((void (*)(void *))func, NULL, NULL); }
int __aeabi_atexit (void *obj, void (*func) (void *), void *d) { return __cxa_atexit (func, obj, d); }
/* Register a function to be called by exit or when a shared library is unloaded. This routine is like __cxa_atexit, but uses the calling sequence required by the ARM EABI. */ int __aeabi_atexit (void *arg, void (*func) (void *), void *d) { return __cxa_atexit (func, arg, d); }
int atexit( _In_ void (*Function)(void)) { return __cxa_atexit((void (*)(void*))Function, NULL, __dso_handle); }