Skip to content

Commit 23b9b46

Browse files
authored
Fix atexit/on_exit/_Exit (#735)
- Fixed return values from `on_exit`/`atexit` - Fixed the exit-status passed to `on_exit` functions via returning from `main` and via `exit` - Re-implemented C99 `_Exit` - Adds `HAS_EXIT` and `HAS_C99__EXIT` which will only include `exit()` and `_Exit()` in `crt0.S` if the functions are needed (similar to `HAS_ABORT`) Fixes #734 and #736
1 parent 8711c6f commit 23b9b46

15 files changed

Lines changed: 555 additions & 26 deletions

File tree

src/crt/crt0.S

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -322,37 +322,52 @@ ___libload_libs_ret:
322322
call _main
323323
#endif
324324
.equ __start._main, $ - 3
325+
326+
;-------------------------------------------------------------------------------
327+
; call atexit/on_exit and fini functions
328+
;-------------------------------------------------------------------------------
329+
325330
.global ___exithl
326331
.type ___exithl, @function
327332
___exithl:
328-
#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT
329-
push hl
330-
push de
333+
334+
#if HAS_ATEXIT || HAS_FINI_ARRAY
335+
push hl ; preserve exit status
331336
#endif
337+
#if HAS_EXIT
338+
; jr .L.exit_function_start
339+
db 0x3E ; ld a, *
332340
.global _exit
333341
.type _exit, @function
334342
_exit:
343+
; exit status is currently at (sp + 3), so we need to fix that
344+
pop bc ; destroy return address
345+
#endif
335346
#if HAS_ATEXIT
347+
; input: (sp + 0) = exit status
336348
jr .L.exit_function_start
337349
.L.exit_function_loop:
338350
ld hl, (ix + 1 + 0 * 3)
339351
ld (__atexit_functions), hl
340-
pop hl
341-
ld de, (ix + 1 + 2 * 3)
342-
push hl
343-
push de
344-
push hl
345-
ld hl, (ix + 1 + 1 * 3)
346-
push hl
352+
pop hl ; exit status
353+
push hl ; exit status
354+
ld de, (ix + 1 + 2 * 3) ; arg
355+
push de ; arg
356+
push hl ; exit status
357+
ld hl, (ix + 1 + 1 * 3) ; func
358+
push hl ; func
347359
pea ix + 1
348360
call _free
349-
pop bc
350-
pop hl
361+
pop bc ; reset SP
362+
pop hl ; func
363+
; atexit : void (*func)(void)
364+
; on_exit : void (*func)(int status, void *arg)
351365
call __indcallhl
352-
pop bc
353-
pop bc
366+
pop bc ; reset SP
367+
pop bc ; reset SP
354368
.L.exit_function_start:
355369
ld ix, (__atexit_functions)
370+
; NULL indicates no more atexit functions
356371
ld bc, -1
357372
add ix, bc
358373
jr c, .L.exit_function_loop
@@ -378,10 +393,27 @@ _exit:
378393
.extern __fini_array_start
379394
.extern __fini_array_end
380395
#endif
381-
#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT
382-
pop de
383-
pop hl
396+
397+
#if HAS_C99__EXIT
398+
; jr .L.skip.__Exit
399+
db 0x3E ; ld a, *
400+
.global __Exit
401+
.type __Exit, @function
402+
__Exit:
403+
; exit status is currently at (sp + 3), so we need to fix that
404+
pop bc ; destroy return address
405+
.L.skip.__Exit:
406+
#endif
407+
408+
#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_EXIT || HAS_C99__EXIT
409+
pop hl ; restore exit status
384410
#endif
411+
412+
;-------------------------------------------------------------------------------
413+
; We have now called all atexit/on_exit and fini functions
414+
; HL = exit status
415+
;-------------------------------------------------------------------------------
416+
385417
#if HAS_ABORT
386418
jr .L.skip._abort
387419
.global _abort

src/libc/atexit.src

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,36 @@
88
.type _on_exit, @function
99
_atexit:
1010
_on_exit:
11-
ld hl, 3*3
11+
ld hl, 3 * 3
1212
push hl
1313
call _malloc
1414
pop bc
1515
ex de, hl
1616
scf
1717
sbc hl, hl
1818
add hl, de
19-
ret nc
19+
ret nc ; malloc returned NULL, return non-zero value
2020
ld hl, (__atexit_functions)
2121
ex de, hl
2222
ld (__atexit_functions), hl
2323
ld (hl), de
24-
pop de
25-
.rept 2
24+
pop iy ; return address
2625
inc hl
2726
inc hl
2827
inc hl
29-
pop bc
28+
pop bc ; func pointer
29+
ld (hl), bc
30+
inc hl
31+
inc hl
32+
inc hl
33+
pop bc ; arg pointer (on_exit)
3034
ld (hl), bc
31-
.endr
3235
push bc
3336
push bc
34-
ex de, hl
35-
jp (hl)
37+
; return zero on success
38+
or a, a
39+
sbc hl, hl
40+
jp (iy)
3641

3742
.section .bss
3843
.global __atexit_functions

test/crt/_Exit/autotest.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"transfer_files": [
3+
"bin/DEMO.8xp"
4+
],
5+
"target": {
6+
"name": "DEMO",
7+
"isASM": true
8+
},
9+
"sequence": [
10+
"action|launch",
11+
"delay|1000",
12+
"hashWait|1",
13+
"key|enter",
14+
"delay|300",
15+
"hashWait|2"
16+
],
17+
"hashes": {
18+
"1": {
19+
"description": "test for errors from on_exit/atexit",
20+
"start": "vram_start",
21+
"size": "vram_16_size",
22+
"expected_CRCs": [
23+
"A1280E53"
24+
]
25+
},
26+
"2": {
27+
"description": "test _Exit()",
28+
"start": "vram_start",
29+
"size": "vram_16_size",
30+
"expected_CRCs": [
31+
"FFAF89BA",
32+
"101734A5",
33+
"9DA19F44",
34+
"A32840C8",
35+
"349F4775"
36+
]
37+
}
38+
}
39+
}

test/crt/_Exit/makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# ----------------------------
2+
# Makefile Options
3+
# ----------------------------
4+
5+
NAME = DEMO
6+
ICON = icon.png
7+
DESCRIPTION = "CE C Toolchain Demo"
8+
COMPRESSED = NO
9+
ARCHIVED = NO
10+
11+
CFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz
12+
CXXFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz
13+
14+
PREFER_OS_LIBC = NO
15+
PREFER_OS_CRT = NO
16+
17+
# ----------------------------
18+
19+
include $(shell cedev-config --makefile)

test/crt/_Exit/src/main.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <ti/screen.h>
2+
#include <ti/getcsc.h>
3+
#include <sys/util.h>
4+
5+
#include <errno.h>
6+
#include <limits.h>
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
11+
void atexit_func(void) {
12+
printf("atexit_func called\n");
13+
while (!os_GetCSC());
14+
}
15+
16+
void on_exit_func(int status, void *arg) {
17+
printf("on_exit_func called\n");
18+
printf("status: %d\narg: %p\n", status, arg);
19+
while (!os_GetCSC());
20+
}
21+
22+
int main(void) {
23+
errno = 0;
24+
os_ClrHome();
25+
if (on_exit(on_exit_func, NULL) != 0) {
26+
perror("Failed on_exit(on_exit_func, NULL)");
27+
while (!os_GetCSC());
28+
return 0;
29+
}
30+
if (atexit(atexit_func) != 0) {
31+
perror("Failed on_exit(on_exit_func, NULL)");
32+
while (!os_GetCSC());
33+
return 0;
34+
}
35+
36+
printf("errno: %d\n", errno);
37+
38+
while (!os_GetCSC());
39+
40+
_Exit(EXIT_SUCCESS);
41+
}

test/crt/exit/autotest.json

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"transfer_files": [
3+
"bin/DEMO.8xp"
4+
],
5+
"target": {
6+
"name": "DEMO",
7+
"isASM": true
8+
},
9+
"sequence": [
10+
"action|launch",
11+
"delay|1000",
12+
"hashWait|1",
13+
"key|enter",
14+
"delay|300",
15+
"hashWait|2",
16+
"key|enter",
17+
"delay|300",
18+
"hashWait|3"
19+
],
20+
"hashes": {
21+
"1": {
22+
"description": "test for errors from on_exit",
23+
"start": "vram_start",
24+
"size": "vram_16_size",
25+
"expected_CRCs": [
26+
"A1280E53"
27+
]
28+
},
29+
"2": {
30+
"description": "is the correct return status present",
31+
"start": "vram_start",
32+
"size": "vram_16_size",
33+
"expected_CRCs": [
34+
"15EB5BAA"
35+
]
36+
},
37+
"3": {
38+
"description": "Exit",
39+
"start": "vram_start",
40+
"size": "vram_16_size",
41+
"expected_CRCs": [
42+
"FFAF89BA",
43+
"101734A5",
44+
"9DA19F44",
45+
"A32840C8",
46+
"349F4775"
47+
]
48+
}
49+
}
50+
}

test/crt/exit/makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# ----------------------------
2+
# Makefile Options
3+
# ----------------------------
4+
5+
NAME = DEMO
6+
ICON = icon.png
7+
DESCRIPTION = "CE C Toolchain Demo"
8+
COMPRESSED = NO
9+
ARCHIVED = NO
10+
11+
CFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz
12+
CXXFLAGS = -ffreestanding -Wall -Wextra -Wshadow -Oz
13+
14+
PREFER_OS_LIBC = NO
15+
PREFER_OS_CRT = NO
16+
17+
# ----------------------------
18+
19+
include $(shell cedev-config --makefile)

test/crt/exit/src/main.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <ti/screen.h>
2+
#include <ti/getcsc.h>
3+
#include <sys/util.h>
4+
5+
#include <errno.h>
6+
#include <limits.h>
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
11+
void cleanup(int status, void *arg) {
12+
if (arg != NULL) {
13+
printf("expected NULL: %p\n", arg);
14+
}
15+
printf("Exit status: %d\n", status);
16+
17+
while (!os_GetCSC());
18+
}
19+
20+
int main(void) {
21+
errno = 0;
22+
os_ClrHome();
23+
if (on_exit(cleanup, NULL) != 0) {
24+
perror("Failed on_exit(cleanup, NULL)");
25+
while (!os_GetCSC());
26+
return 0;
27+
}
28+
29+
printf("errno: %d\n", errno);
30+
31+
while (!os_GetCSC());
32+
33+
exit(42);
34+
}

0 commit comments

Comments
 (0)