From 72bfdff02528fb27422c5d5d6cf4a565eb007efd Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 12:37:23 -0700 Subject: [PATCH 01/11] added documentation for atexit/on_exit --- src/libc/atexit.src | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libc/atexit.src b/src/libc/atexit.src index 99be5f152..a827d64f3 100644 --- a/src/libc/atexit.src +++ b/src/libc/atexit.src @@ -8,7 +8,7 @@ .type _on_exit, @function _atexit: _on_exit: - ld hl, 3*3 + ld hl, 3 * 3 push hl call _malloc pop bc @@ -16,19 +16,22 @@ _on_exit: 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 de ; 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 From a505cab51c7018e6d3661a4efb100f5a7c1d56f5 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 13:11:23 -0700 Subject: [PATCH 02/11] fixed atexit/on_exit return value --- src/libc/atexit.src | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libc/atexit.src b/src/libc/atexit.src index a827d64f3..af4f0f12e 100644 --- a/src/libc/atexit.src +++ b/src/libc/atexit.src @@ -21,7 +21,7 @@ _on_exit: ex de, hl ld (__atexit_functions), hl ld (hl), de - pop de ; return address + pop iy ; return address inc hl inc hl inc hl @@ -34,8 +34,10 @@ _on_exit: ld (hl), bc 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 From fe3e331bbec8b1faf6bf5d4657025aa95189449b Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:16:05 -0700 Subject: [PATCH 03/11] fixed exit-status in exit/atexit/on_exit --- src/crt/crt0.S | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/crt/crt0.S b/src/crt/crt0.S index 3a7112997..b05b8653a 100644 --- a/src/crt/crt0.S +++ b/src/crt/crt0.S @@ -320,36 +320,49 @@ ___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 + push hl ; preserve exit status #endif + ; 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 #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 @@ -376,9 +389,14 @@ _exit: .extern __fini_array_end #endif #if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT - pop de - pop hl + 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 From 1f6253355d10122a9948a18b9a673efde1abb8d8 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:05:17 -0700 Subject: [PATCH 04/11] add tests for on_exit/atexit --- test/standalone/on_exit/autotest.json | 61 +++++++++++++++++++++++++++ test/standalone/on_exit/makefile | 19 +++++++++ test/standalone/on_exit/src/main.c | 59 ++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 test/standalone/on_exit/autotest.json create mode 100644 test/standalone/on_exit/makefile create mode 100644 test/standalone/on_exit/src/main.c diff --git a/test/standalone/on_exit/autotest.json b/test/standalone/on_exit/autotest.json new file mode 100644 index 000000000..234c87b80 --- /dev/null +++ b/test/standalone/on_exit/autotest.json @@ -0,0 +1,61 @@ +{ + "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", + "key|enter", + "delay|300", + "hashWait|4" + ], + "hashes": { + "1": { + "description": "test for errors from atexit/on_exit", + "start": "vram_start", + "size": "vram_8_size", + "expected_CRCs": [ + "0A3F477E" + ] + }, + "2": { + "description": "is the correct return status present", + "start": "vram_start", + "size": "vram_8_size", + "expected_CRCs": [ + "FEF6F9F4" + ] + }, + "3": { + "description": "check that gfx_End() was called", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "4BD20C6F" + ] + }, + "4": { + "description": "Exit", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "FFAF89BA", + "101734A5", + "9DA19F44", + "A32840C8", + "349F4775" + ] + } + } +} diff --git a/test/standalone/on_exit/makefile b/test/standalone/on_exit/makefile new file mode 100644 index 000000000..2b7b27349 --- /dev/null +++ b/test/standalone/on_exit/makefile @@ -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) diff --git a/test/standalone/on_exit/src/main.c b/test/standalone/on_exit/src/main.c new file mode 100644 index 000000000..141d18c31 --- /dev/null +++ b/test/standalone/on_exit/src/main.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +void cleanup(int status, void *arg) { + const char *message = (char*)arg; + + gfx_PrintStringXY(message, 10, 30); + + gfx_PrintStringXY("Exit status: ", 10, 50); + gfx_PrintInt(status, 1); + + while (!os_GetCSC()); +} + +void final_func(void) { + os_ClrHome(); + puts("Finished tests"); + while (!os_GetCSC()); +} + +int main(void) { + errno = 0; + os_ClrHome(); + const char *msg = "cleanup func"; + if (atexit(final_func) != 0) { + perror("Failed atexit(final_func)"); + while (!os_GetCSC()); + return 0; + } + if (atexit(gfx_End) != 0) { + perror("Failed atexit(gfx_End)"); + while (!os_GetCSC()); + return 0; + } + if (on_exit(cleanup, (void*)msg) != 0) { + perror("Failed on_exit(cleanup, msg)"); + while (!os_GetCSC()); + return 0; + } + + gfx_Begin(); + + gfx_PrintStringXY("errno: ", 10, 10); + gfx_PrintInt(errno, 1); + + while (!os_GetCSC()); + + return 7184; +} From 95042e5a81c57cc90522840f1de045fb59ae9dd7 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:17:11 -0700 Subject: [PATCH 05/11] test returning via exit() --- test/standalone/exit/autotest.json | 50 ++++++++++++++++++++++++++++++ test/standalone/exit/makefile | 19 ++++++++++++ test/standalone/exit/src/main.c | 34 ++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 test/standalone/exit/autotest.json create mode 100644 test/standalone/exit/makefile create mode 100644 test/standalone/exit/src/main.c diff --git a/test/standalone/exit/autotest.json b/test/standalone/exit/autotest.json new file mode 100644 index 000000000..f38453114 --- /dev/null +++ b/test/standalone/exit/autotest.json @@ -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" + ] + } + } +} diff --git a/test/standalone/exit/makefile b/test/standalone/exit/makefile new file mode 100644 index 000000000..2b7b27349 --- /dev/null +++ b/test/standalone/exit/makefile @@ -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) diff --git a/test/standalone/exit/src/main.c b/test/standalone/exit/src/main.c new file mode 100644 index 000000000..d0e7fba83 --- /dev/null +++ b/test/standalone/exit/src/main.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +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); +} From 5168b90e363baa7ed176ff5668690db5b34656f5 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:38:36 -0700 Subject: [PATCH 06/11] reimplemented C99 _Exit --- src/crt/crt0.S | 10 +++++++ test/standalone/_Exit/autotest.json | 39 +++++++++++++++++++++++++++ test/standalone/_Exit/makefile | 19 +++++++++++++ test/standalone/_Exit/src/main.c | 41 +++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 test/standalone/_Exit/autotest.json create mode 100644 test/standalone/_Exit/makefile create mode 100644 test/standalone/_Exit/src/main.c diff --git a/src/crt/crt0.S b/src/crt/crt0.S index b05b8653a..bf3d17cef 100644 --- a/src/crt/crt0.S +++ b/src/crt/crt0.S @@ -388,6 +388,16 @@ _exit: .extern __fini_array_start .extern __fini_array_end #endif + + ; 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: + #if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT pop hl ; restore exit status #endif diff --git a/test/standalone/_Exit/autotest.json b/test/standalone/_Exit/autotest.json new file mode 100644 index 000000000..42ba741c1 --- /dev/null +++ b/test/standalone/_Exit/autotest.json @@ -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" + ] + } + } +} diff --git a/test/standalone/_Exit/makefile b/test/standalone/_Exit/makefile new file mode 100644 index 000000000..2b7b27349 --- /dev/null +++ b/test/standalone/_Exit/makefile @@ -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) diff --git a/test/standalone/_Exit/src/main.c b/test/standalone/_Exit/src/main.c new file mode 100644 index 000000000..ac6be1e62 --- /dev/null +++ b/test/standalone/_Exit/src/main.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +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); +} From 2e3dd358685281c0a0c6524d85e2955617897294 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:44:05 -0700 Subject: [PATCH 07/11] fixed exit status restoration logic --- src/crt/crt0.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crt/crt0.S b/src/crt/crt0.S index bf3d17cef..f20fc4d06 100644 --- a/src/crt/crt0.S +++ b/src/crt/crt0.S @@ -328,7 +328,7 @@ ___libload_libs_ret: .global ___exithl ___exithl: -#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT +#if HAS_ATEXIT || HAS_FINI_ARRAY push hl ; preserve exit status #endif ; jr .L.exit_function_start @@ -398,7 +398,7 @@ __Exit: pop bc ; destroy return address .L.skip.__Exit: -#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_ABORT +#if HAS_ATEXIT || HAS_FINI_ARRAY pop hl ; restore exit status #endif From 685a3adc88e6c463638a0cba713214853edd50fb Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:12:42 -0700 Subject: [PATCH 08/11] cedev-obj: add detection for exit() and _Exit() --- tools/cedev-obj/src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/cedev-obj/src/main.c b/tools/cedev-obj/src/main.c index 5f72c6b1e..716004bcf 100644 --- a/tools/cedev-obj/src/main.c +++ b/tools/cedev-obj/src/main.c @@ -123,6 +123,8 @@ static void write_header_defines(FILE *out, const char *elf_file, struct elf_fil fprintf(out, "#define HAS_FINI_ARRAY %d\n", elf_has_section(elf, ".fini_array") ? 1 : 0); fprintf(out, "#define HAS_CLOCK %d\n", elf_has_symbol(elf, "_clock") ? 1 : 0); fprintf(out, "#define HAS_ABORT %d\n", elf_has_symbol(elf, "_abort") ? 1 : 0); + fprintf(out, "#define HAS_EXIT %d\n", elf_has_symbol(elf, "_exit") ? 1 : 0); + fprintf(out, "#define HAS_C99__EXIT %d\n", elf_has_symbol(elf, "__Exit") ? 1 : 0); fprintf(out, "#define HAS_RUN_PRGM %d\n", elf_has_symbol(elf, "_os_RunPrgm") ? 1 : 0); fprintf(out, "#define HAS_MAIN_ARGC_ARGV %d\n", elf_has_defined_symbol(elf, "___main_argc_argv") ? 1 : 0); fprintf(out, "#define HAS_ATEXIT %d\n", elf_has_symbol(elf, "__atexit_functions") ? 1 : 0); From 3e94499b7b068e5bc456990d1cb81b47cded9478 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:19:19 -0700 Subject: [PATCH 09/11] make the inclusion of exit() and _Exit() in crt0.S conditional --- src/crt/crt0.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/crt/crt0.S b/src/crt/crt0.S index f20fc4d06..564f2d686 100644 --- a/src/crt/crt0.S +++ b/src/crt/crt0.S @@ -331,6 +331,7 @@ ___exithl: #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 @@ -338,6 +339,7 @@ ___exithl: _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 @@ -389,6 +391,7 @@ _exit: .extern __fini_array_end #endif +#if HAS_C99__EXIT ; jr .L.skip.__Exit db 0x3E ; ld a, * .global __Exit @@ -397,6 +400,7 @@ __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 pop hl ; restore exit status From 73dd2b87b18d7b031d6c60c266be6a20127e5b1f Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 17:52:41 -0700 Subject: [PATCH 10/11] corrected exit status restore code --- src/crt/crt0.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crt/crt0.S b/src/crt/crt0.S index 564f2d686..2f4804905 100644 --- a/src/crt/crt0.S +++ b/src/crt/crt0.S @@ -402,7 +402,7 @@ __Exit: .L.skip.__Exit: #endif -#if HAS_ATEXIT || HAS_FINI_ARRAY +#if HAS_ATEXIT || HAS_FINI_ARRAY || HAS_EXIT || HAS_C99__EXIT pop hl ; restore exit status #endif From 8aad51450dd55ecb0cb19da3435e57d880f2a36a Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Thu, 5 Mar 2026 19:36:03 -0700 Subject: [PATCH 11/11] always emit _abort and _exit for now --- tools/cedev-obj/src/main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/cedev-obj/src/main.c b/tools/cedev-obj/src/main.c index 716004bcf..8b83bc120 100644 --- a/tools/cedev-obj/src/main.c +++ b/tools/cedev-obj/src/main.c @@ -122,8 +122,14 @@ static void write_header_defines(FILE *out, const char *elf_file, struct elf_fil fprintf(out, "#define HAS_INIT_ARRAY %d\n", elf_has_section(elf, ".init_array") ? 1 : 0); fprintf(out, "#define HAS_FINI_ARRAY %d\n", elf_has_section(elf, ".fini_array") ? 1 : 0); fprintf(out, "#define HAS_CLOCK %d\n", elf_has_symbol(elf, "_clock") ? 1 : 0); - fprintf(out, "#define HAS_ABORT %d\n", elf_has_symbol(elf, "_abort") ? 1 : 0); - fprintf(out, "#define HAS_EXIT %d\n", elf_has_symbol(elf, "_exit") ? 1 : 0); + #if 0 + fprintf(out, "#define HAS_ABORT %d\n", elf_has_symbol(elf, "_abort") ? 1 : 0); + fprintf(out, "#define HAS_EXIT %d\n", elf_has_symbol(elf, "_exit") ? 1 : 0); + #else + // elf_has_symbol has some false negatives, so always emit these functions for now. + fprintf(out, "#define HAS_ABORT %d\n", /* _abort */ 1); + fprintf(out, "#define HAS_EXIT %d\n", /* _exit */ 1); + #endif fprintf(out, "#define HAS_C99__EXIT %d\n", elf_has_symbol(elf, "__Exit") ? 1 : 0); fprintf(out, "#define HAS_RUN_PRGM %d\n", elf_has_symbol(elf, "_os_RunPrgm") ? 1 : 0); fprintf(out, "#define HAS_MAIN_ARGC_ARGV %d\n", elf_has_defined_symbol(elf, "___main_argc_argv") ? 1 : 0);