dso, stdlib: __cxa_atexit(), __dso_handle, atexit() (TEST)

This commit is contained in:
Lephenixnoir 2022-09-07 21:03:53 +02:00
parent 547a52737d
commit 4358a16b92
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
6 changed files with 81 additions and 2 deletions

View File

@ -70,6 +70,8 @@ set(SOURCES
3rdparty/grisu2b_59_56/grisu2b_59_56.c
3rdparty/tinymt32/rand.c
3rdparty/tinymt32/tinymt32.c
# C++ API details
src/dso.c
# assert
src/assert/assert.c
# ctype
@ -157,6 +159,7 @@ set(SOURCES
# stdlib
src/stdlib/abort.c
src/stdlib/abs.c
src/stdlib/atexit.c
src/stdlib/atof.c
src/stdlib/atoi.c
src/stdlib/atol.c

4
STATUS
View File

@ -162,7 +162,7 @@ TEST: Function/symbol/macro needs to be tested
7.20.3.3 malloc - (gint)
7.20.3.4 realloc - (gint)
7.20.4.1 abort - (stream flushing/closing/etc?)
7.20.4.2 atexit TODO
7.20.4.2 atexit TEST
7.20.4.3 exit - (stream flushing/closing/etc?)
7.20.4.4 _Exit - (gint)
7.20.4.5 getenv TODO
@ -173,6 +173,8 @@ TEST: Function/symbol/macro needs to be tested
7.20.6.2 div, ldiv, lldiv -
7.20.7 Multibyte/wide char conv TODO
7.20.8 Multibyte/wide string conv TODO
(EXT) __cxa_atexit TEST
(EXT) __cxa_finalize TEST
7.21 <string.h>
7.21.2.1 memcpy -

View File

@ -38,6 +38,7 @@ extern void free(void *__ptr);
__attribute__((noreturn))
extern void abort(void);
/* Register a function to be called at program exit. */
extern int atexit(void (*__func)(void));
/* Exit; calls handlers, flushes and closes streams and temporary files. */

62
src/dso.c Normal file
View File

@ -0,0 +1,62 @@
#include <stddef.h>
/* We don't support shared object loading, so provide a single handle */
__attribute__((visibility("hidden")))
void *__dso_handle = (void *)&__dso_handle;
/* Number of atexit() calls supported, must be at least 32 (7.20.4.2§3).*/
#define ATEXIT_MAX 32
struct dtor {
void (*f)(void *);
void *p;
void *d;
};
static struct dtor _dtors[ATEXIT_MAX];
static int _dtor_count = 0;
int __cxa_atexit(void (*f)(void *), void *p, void *d)
{
if(_dtor_count >= ATEXIT_MAX)
return 1;
_dtors[_dtor_count++] = (struct dtor){ f, p, d };
return 0;
}
/* We walk the destructor list in reverse order. Destructors may themselves
call __cxa_atexit(), causing new destructors to be added. When that
happens, we must call the new ones first before resuming (7.20.4.3§3). We
track changes in _dtor_count to detect this situation.
This function calls destructs in the interval [low..high) that match DSO
handle d, plus any other destructors registered as a consequence.
_dtor_count may increase. */
static void call_dtors_in_interval(void *d, int low, int high)
{
int end = _dtor_count;
for(int i = high - 1; i >= low; i--) {
if(d == NULL || _dtors[i].d == d)
_dtors[i].f(_dtors[i].p);
if(_dtor_count > end) {
call_dtors_in_interval(d, end, _dtor_count);
end = _dtor_count;
}
}
}
void __cxa_finalize(void *d)
{
call_dtors_in_interval(d, 0, _dtor_count);
/* Re-compact the array to keep only destructors we didn't call. */
int j = 0;
for(int i = 0; i < _dtor_count; i++) {
if(d == NULL || _dtors[i].d == d)
continue;
_dtors[j++] = _dtors[i];
}
_dtor_count = j;
}

8
src/stdlib/atexit.c Normal file
View File

@ -0,0 +1,8 @@
#include <stdlib.h>
extern int __cxa_atexit(void (*f)(void *), void *p, void *d);
int atexit(void (*f)(void))
{
return __cxa_atexit((void (*)(void *))f, NULL, NULL);
}

View File

@ -1,8 +1,11 @@
#include <stdlib.h>
extern void __cxa_finalize(void *d);
void exit(int rc)
{
/* TODO: invoke atexit callbacks */
__cxa_finalize(NULL);
/* TODO: exit: Flush all streams */
/* TODO: exit: Close all streams */
/* TODO: exit: Remove temporary files */