Skip to content
Draft
66 changes: 49 additions & 17 deletions src/crt/crt0.S
Original file line number Diff line number Diff line change
Expand Up @@ -320,36 +320,51 @@ ___libload_libs_ret:
call _main
#endif
.equ __start._main, $ - 3

;-------------------------------------------------------------------------------
; call atexit/on_exit and fini functions
;-------------------------------------------------------------------------------

.global ___exithl
___exithl:
#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT
push hl
push de

#if HAS_ATEXIT || HAS_FINI_ARRAY
push hl ; preserve exit status
#endif
#if HAS_EXIT
; jr .L.exit_function_start
db 0x3E ; ld a, *
.global _exit
.type _exit, @function
_exit:
; exit status is currently at (sp + 3), so we need to fix that
pop bc ; destroy return address
#endif
#if HAS_ATEXIT
; input: (sp + 0) = exit status
jr .L.exit_function_start
.L.exit_function_loop:
ld hl, (ix + 1 + 0 * 3)
ld (__atexit_functions), hl
pop hl
ld de, (ix + 1 + 2 * 3)
push hl
push de
push hl
ld hl, (ix + 1 + 1 * 3)
push hl
pop hl ; exit status
push hl ; exit status
ld de, (ix + 1 + 2 * 3) ; arg
push de ; arg
push hl ; exit status
ld hl, (ix + 1 + 1 * 3) ; func
push hl ; func
pea ix + 1
call _free
pop bc
pop hl
pop bc ; reset SP
pop hl ; func
; atexit : void (*func)(void)
; on_exit : void (*func)(int status, void *arg)
call __indcallhl
pop bc
pop bc
pop bc ; reset SP
pop bc ; reset SP
.L.exit_function_start:
ld ix, (__atexit_functions)
; NULL indicates no more atexit functions
ld bc, -1
add ix, bc
jr c, .L.exit_function_loop
Expand All @@ -375,10 +390,27 @@ _exit:
.extern __fini_array_start
.extern __fini_array_end
#endif
#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT
pop de
pop hl

#if HAS_C99__EXIT
; jr .L.skip.__Exit
db 0x3E ; ld a, *
.global __Exit
.type __Exit, @function
__Exit:
; exit status is currently at (sp + 3), so we need to fix that
pop bc ; destroy return address
.L.skip.__Exit:
#endif

#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_EXIT || HAS_C99__EXIT
pop hl ; restore exit status
#endif

;-------------------------------------------------------------------------------
; We have now called all atexit/on_exit and fini functions
; HL = exit status
;-------------------------------------------------------------------------------

#if HAS_ABORT
jr .L.skip._abort
.global _abort
Expand Down
21 changes: 13 additions & 8 deletions src/libc/atexit.src
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,36 @@
.type _on_exit, @function
_atexit:
_on_exit:
ld hl, 3*3
ld hl, 3 * 3
push hl
call _malloc
pop bc
ex de, hl
scf
sbc hl, hl
add hl, de
ret nc
ret nc ; malloc returned NULL, return non-zero value
ld hl, (__atexit_functions)
ex de, hl
ld (__atexit_functions), hl
ld (hl), de
pop de
.rept 2
pop iy ; return address
inc hl
inc hl
inc hl
pop bc
pop bc ; func pointer
ld (hl), bc
inc hl
inc hl
inc hl
pop bc ; arg pointer (on_exit)
ld (hl), bc
.endr
push bc
push bc
ex de, hl
jp (hl)
; return zero on success
or a, a
sbc hl, hl
jp (iy)

.section .bss
.global __atexit_functions
Expand Down
39 changes: 39 additions & 0 deletions test/standalone/_Exit/autotest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"transfer_files": [
"bin/DEMO.8xp"
],
"target": {
"name": "DEMO",
"isASM": true
},
"sequence": [
"action|launch",
"delay|1000",
"hashWait|1",
"key|enter",
"delay|300",
"hashWait|2"
],
"hashes": {
"1": {
"description": "test for errors from on_exit/atexit",
"start": "vram_start",
"size": "vram_16_size",
"expected_CRCs": [
"A1280E53"
]
},
"2": {
"description": "test _Exit()",
"start": "vram_start",
"size": "vram_16_size",
"expected_CRCs": [
"FFAF89BA",
"101734A5",
"9DA19F44",
"A32840C8",
"349F4775"
]
}
}
}
19 changes: 19 additions & 0 deletions test/standalone/_Exit/makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# ----------------------------
# Makefile Options
# ----------------------------

NAME = DEMO
ICON = icon.png
DESCRIPTION = "CE C Toolchain Demo"
COMPRESSED = NO
ARCHIVED = NO

CFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz
CXXFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz

PREFER_OS_LIBC = NO
PREFER_OS_CRT = NO

# ----------------------------

include $(shell cedev-config --makefile)
41 changes: 41 additions & 0 deletions test/standalone/_Exit/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <ti/screen.h>
#include <ti/getcsc.h>
#include <sys/util.h>

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void atexit_func(void) {
printf("atexit_func called\n");
while (!os_GetCSC());
}

void on_exit_func(int status, void *arg) {
printf("on_exit_func called\n");
printf("status: %d\narg: %p\n", status, arg);
while (!os_GetCSC());
}

int main(void) {
errno = 0;
os_ClrHome();
if (on_exit(on_exit_func, NULL) != 0) {
perror("Failed on_exit(on_exit_func, NULL)");
while (!os_GetCSC());
return 0;
}
if (atexit(atexit_func) != 0) {
perror("Failed on_exit(on_exit_func, NULL)");
while (!os_GetCSC());
return 0;
}

printf("errno: %d\n", errno);

while (!os_GetCSC());

_Exit(EXIT_SUCCESS);
}
50 changes: 50 additions & 0 deletions test/standalone/exit/autotest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"transfer_files": [
"bin/DEMO.8xp"
],
"target": {
"name": "DEMO",
"isASM": true
},
"sequence": [
"action|launch",
"delay|1000",
"hashWait|1",
"key|enter",
"delay|300",
"hashWait|2",
"key|enter",
"delay|300",
"hashWait|3"
],
"hashes": {
"1": {
"description": "test for errors from on_exit",
"start": "vram_start",
"size": "vram_16_size",
"expected_CRCs": [
"A1280E53"
]
},
"2": {
"description": "is the correct return status present",
"start": "vram_start",
"size": "vram_16_size",
"expected_CRCs": [
"15EB5BAA"
]
},
"3": {
"description": "Exit",
"start": "vram_start",
"size": "vram_16_size",
"expected_CRCs": [
"FFAF89BA",
"101734A5",
"9DA19F44",
"A32840C8",
"349F4775"
]
}
}
}
19 changes: 19 additions & 0 deletions test/standalone/exit/makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# ----------------------------
# Makefile Options
# ----------------------------

NAME = DEMO
ICON = icon.png
DESCRIPTION = "CE C Toolchain Demo"
COMPRESSED = NO
ARCHIVED = NO

CFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz
CXXFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz

PREFER_OS_LIBC = NO
PREFER_OS_CRT = NO

# ----------------------------

include $(shell cedev-config --makefile)
34 changes: 34 additions & 0 deletions test/standalone/exit/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <ti/screen.h>
#include <ti/getcsc.h>
#include <sys/util.h>

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void cleanup(int status, void *arg) {
if (arg != NULL) {
printf("expected NULL: %p\n", arg);
}
printf("Exit status: %d\n", status);

while (!os_GetCSC());
}

int main(void) {
errno = 0;
os_ClrHome();
if (on_exit(cleanup, NULL) != 0) {
perror("Failed on_exit(cleanup, NULL)");
while (!os_GetCSC());
return 0;
}

printf("errno: %d\n", errno);

while (!os_GetCSC());

exit(42);
}
Loading
Loading