typedef void* (*cxa_atexit_func_t)(void*);

struct cxa_atexit_entry
{
    cxa_atexit_func_t function;
    void* argument;
    void* dso_handle;
};

#define CXA_ATEXIT_MAX 64

int cxa_atexit_entry_count = 0;

cxa_atexit_entry cxa_atexit_entries[CXA_ATEXIT_MAX];

__attribute__((visibility("hidden"))) void* __dso_handle = 0;

extern "C"
{
    int __cxa_atexit(cxa_atexit_func_t func, void* arg, void* dso)
    {
        if (cxa_atexit_entry_count >= CXA_ATEXIT_MAX) return -1;
        cxa_atexit_entries[cxa_atexit_entry_count].function = func;
        cxa_atexit_entries[cxa_atexit_entry_count].argument = arg;
        cxa_atexit_entries[cxa_atexit_entry_count].dso_handle = dso;
        cxa_atexit_entry_count++;
        return 0;
    }

    void __cxa_finalize(void* f)
    {
        int i = cxa_atexit_entry_count;
        if (!f)
        {
            while (i--)
            {
                if (cxa_atexit_entries[i].function) { cxa_atexit_entries[i].function(cxa_atexit_entries[i].argument); }
            }
        }
        else
        {
            while (i--)
            {
                if (cxa_atexit_entries[i].function == (cxa_atexit_func_t)f)
                {
                    cxa_atexit_entries[i].function(cxa_atexit_entries[i].argument);
                    cxa_atexit_entries[i].function = 0;
                }
            }
        }
    }
}