From 950eca3efbdbc9b7512f40da97ed3af140e4ceba Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:30:58 -0600 Subject: [PATCH 1/4] added test for std::terminate --- test/crt/terminate/autotest.json | 39 ++++++++++++++++++++++++++++++++ test/crt/terminate/makefile | 19 ++++++++++++++++ test/crt/terminate/src/main.cpp | 11 +++++++++ 3 files changed, 69 insertions(+) create mode 100644 test/crt/terminate/autotest.json create mode 100644 test/crt/terminate/makefile create mode 100644 test/crt/terminate/src/main.cpp diff --git a/test/crt/terminate/autotest.json b/test/crt/terminate/autotest.json new file mode 100644 index 000000000..4fb40486f --- /dev/null +++ b/test/crt/terminate/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": "before std::terminate", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "0F1A678D" + ] + }, + "2": { + "description": "after std::terminate", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "FFAF89BA", + "101734A5", + "9DA19F44", + "A32840C8", + "349F4775" + ] + } + } +} diff --git a/test/crt/terminate/makefile b/test/crt/terminate/makefile new file mode 100644 index 000000000..c7301f1e3 --- /dev/null +++ b/test/crt/terminate/makefile @@ -0,0 +1,19 @@ +# ---------------------------- +# Makefile Options +# ---------------------------- + +NAME = DEMO +ICON = icon.png +DESCRIPTION = "CE C Toolchain Demo" +COMPRESSED = NO +ARCHIVED = NO + +CFLAGS = -Wall -Wextra -Wshadow -Oz +CXXFLAGS = -Wall -Wextra -Wshadow -Oz + +PREFER_OS_LIBC = NO +PREFER_OS_CRT = NO + +# ---------------------------- + +include $(shell cedev-config --makefile) diff --git a/test/crt/terminate/src/main.cpp b/test/crt/terminate/src/main.cpp new file mode 100644 index 000000000..c93e3b92d --- /dev/null +++ b/test/crt/terminate/src/main.cpp @@ -0,0 +1,11 @@ +#include +#include +#include + +int main(void) { + os_ClrHome(); + os_PutStrFull("before std::terminate"); + while (!os_GetCSC()); + + std::terminate(); +} From 4f8f97d25d5837a931ddab0a32433d41f86ddd41 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:40:33 -0600 Subject: [PATCH 2/4] maybe fix library linking order by putting LIB_* in --start-group/--end-group to enable the linker to resolve circular dependencies. --- src/makefile.mk | 19 +++++++++++-------- tools/cedev-obj/src/main.c | 10 ++-------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/makefile.mk b/src/makefile.mk index 3e64c5867..6db9b829a 100644 --- a/src/makefile.mk +++ b/src/makefile.mk @@ -391,14 +391,15 @@ $(BINDIR)/$(TARGETOBJ): $(CRT0_OBJ) $(OBJDIR)/$(TARGETTMP) $(MAKEFILE_LIST) $(DE $(EXTRA_LDFLAGS) \ $(OBJDIR)/$(TARGETTMP) \ $(CRT0_OBJ) \ - $(LIB_ALLOCATOR) \ --start-group \ - $(LIB_SOFTFLOAT) \ + $(LIB_ALLOCATOR) \ + $(LIB_PRINTF) \ $(LIB_CRT) \ - --end-group \ + $(LIB_CE) \ + $(LIB_SOFTFLOAT) \ $(LIB_C) \ $(LIB_CXX) \ - $(LIB_CE) \ + --end-group \ -o $(call QUOTE_ARG,$@) ifneq ($(ICON_SRC),) @@ -496,14 +497,16 @@ $(OBJDIR)/$(TARGETTMP): $(OBJECTS) $(LIB_ALLOCATOR) $(LIB_PRINTF) $(LIB_CXX) $(L $(EXTRA_PRE_LDFLAGS) \ $(OBJECTS) \ $(ICON_OBJ) \ + $(EXTRA_LIBS) \ + --start-group \ $(LIB_ALLOCATOR) \ $(LIB_PRINTF) \ - $(LIB_CXX) \ - $(LIB_CE) \ $(LIB_CRT) \ - $(LIB_C) \ + $(LIB_CE) \ $(LIB_SOFTFLOAT) \ - $(EXTRA_LIBS) \ + $(LIB_C) \ + $(LIB_CXX) \ + --end-group \ -o $(call QUOTE_ARG,$@) $(Q)$(STRIP_CMD) $(call QUOTE_ARG,$@) diff --git a/tools/cedev-obj/src/main.c b/tools/cedev-obj/src/main.c index 8b83bc120..716004bcf 100644 --- a/tools/cedev-obj/src/main.c +++ b/tools/cedev-obj/src/main.c @@ -122,14 +122,8 @@ 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); - #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_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); From bb35a84d65272c18e0932ed5ebf56a43deb478cc Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Sat, 4 Apr 2026 12:06:52 -0600 Subject: [PATCH 3/4] fixed linking of LIB_PRINTF and added custom printf test --- src/makefile.mk | 3 +- test/standalone/custom_printf/autotest.json | 39 +++++++++++++++++++ test/standalone/custom_printf/makefile | 20 ++++++++++ .../custom_printf/src/custom_sprintf.c | 34 ++++++++++++++++ test/standalone/custom_printf/src/main.c | 20 ++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 test/standalone/custom_printf/autotest.json create mode 100644 test/standalone/custom_printf/makefile create mode 100644 test/standalone/custom_printf/src/custom_sprintf.c create mode 100644 test/standalone/custom_printf/src/main.c diff --git a/src/makefile.mk b/src/makefile.mk index 6db9b829a..3acbe3d69 100644 --- a/src/makefile.mk +++ b/src/makefile.mk @@ -393,7 +393,6 @@ $(BINDIR)/$(TARGETOBJ): $(CRT0_OBJ) $(OBJDIR)/$(TARGETTMP) $(MAKEFILE_LIST) $(DE $(CRT0_OBJ) \ --start-group \ $(LIB_ALLOCATOR) \ - $(LIB_PRINTF) \ $(LIB_CRT) \ $(LIB_CE) \ $(LIB_SOFTFLOAT) \ @@ -498,9 +497,9 @@ $(OBJDIR)/$(TARGETTMP): $(OBJECTS) $(LIB_ALLOCATOR) $(LIB_PRINTF) $(LIB_CXX) $(L $(OBJECTS) \ $(ICON_OBJ) \ $(EXTRA_LIBS) \ + --whole-archive $(LIB_PRINTF) --no-whole-archive \ --start-group \ $(LIB_ALLOCATOR) \ - $(LIB_PRINTF) \ $(LIB_CRT) \ $(LIB_CE) \ $(LIB_SOFTFLOAT) \ diff --git a/test/standalone/custom_printf/autotest.json b/test/standalone/custom_printf/autotest.json new file mode 100644 index 000000000..13677b2e9 --- /dev/null +++ b/test/standalone/custom_printf/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|400", + "hashWait|2" + ], + "hashes": { + "1": { + "description": "%s should print ALL CAPS with the custom printf", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "F449EF83" + ] + }, + "2": { + "description": "Exit", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "FFAF89BA", + "101734A5", + "9DA19F44", + "A32840C8", + "349F4775" + ] + } + } +} diff --git a/test/standalone/custom_printf/makefile b/test/standalone/custom_printf/makefile new file mode 100644 index 000000000..b025630d4 --- /dev/null +++ b/test/standalone/custom_printf/makefile @@ -0,0 +1,20 @@ +# ---------------------------- +# Makefile Options +# ---------------------------- + +NAME = DEMO +ICON = icon.png +DESCRIPTION = "CE C Toolchain Demo" +COMPRESSED = NO +ARCHIVED = NO + +CFLAGS = -Wall -Wextra -Wshadow -Oz +CXXFLAGS = -Wall -Wextra -Wshadow -Oz + +PREFER_OS_LIBC = NO +PREFER_OS_CRT = NO +HAS_PRINTF = NO + +# ---------------------------- + +include $(shell cedev-config --makefile) diff --git a/test/standalone/custom_printf/src/custom_sprintf.c b/test/standalone/custom_printf/src/custom_sprintf.c new file mode 100644 index 000000000..c022aa283 --- /dev/null +++ b/test/standalone/custom_printf/src/custom_sprintf.c @@ -0,0 +1,34 @@ +#include +#include +#include + +// custom version of sprintf where %s is all uppercase +int sprintf(char *buffer, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + + int count = 0; + const char *ptr = format; + while (*ptr != '\0') { + if (*ptr == '%' && *(ptr + 1) == 's') { + const char *str = va_arg(args, const char*); + while (*str != '\0') { + *buffer = toupper(*str); + buffer++; + str++; + count++; + } + // consume %s + ptr += 2; + continue; + } + *buffer = *ptr; + buffer++; + ptr++; + count++; + } + *buffer++ = '\0'; + + va_end(args); + return count; +} diff --git a/test/standalone/custom_printf/src/main.c b/test/standalone/custom_printf/src/main.c new file mode 100644 index 000000000..a90a4aca2 --- /dev/null +++ b/test/standalone/custom_printf/src/main.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +int main(void) { + char buf[50]; + os_ClrHome(); + + // test that we are using a custom printf and not the real one + const char *str = "printf"; + int result = sprintf(buf, "custom %s!", str); + puts(buf); + boot_sprintf(buf, "returned %d", result); + puts(buf); + + while (!os_GetCSC()); + + return 0; +} From 6daa4f65d3dd03c0774478c38fda9e9cd55c3f39 Mon Sep 17 00:00:00 2001 From: zerico <71151164+ZERICO2005@users.noreply.github.com> Date: Sat, 4 Apr 2026 15:40:17 -0600 Subject: [PATCH 4/4] fixed LIB_ALLOCATOR and added custom allocator tests --- src/libc/allocator/allocator_simple.src | 2 +- src/makefile.mk | 17 +++-- .../standalone/custom_allocator/autotest.json | 61 ++++++++++++++++++ test/standalone/custom_allocator/makefile | 21 +++++++ .../custom_allocator/src/custom_free.s | 23 +++++++ .../custom_allocator/src/custom_malloc.c | 19 ++++++ test/standalone/custom_allocator/src/main.c | 62 +++++++++++++++++++ 7 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 test/standalone/custom_allocator/autotest.json create mode 100644 test/standalone/custom_allocator/makefile create mode 100644 test/standalone/custom_allocator/src/custom_free.s create mode 100644 test/standalone/custom_allocator/src/custom_malloc.c create mode 100644 test/standalone/custom_allocator/src/main.c diff --git a/src/libc/allocator/allocator_simple.src b/src/libc/allocator/allocator_simple.src index 5d3af2710..61eaa5922 100644 --- a/src/libc/allocator/allocator_simple.src +++ b/src/libc/allocator/allocator_simple.src @@ -1,6 +1,6 @@ .assume adl=1 - .section .text._malloc + .section .text .global _malloc .type _malloc, @function diff --git a/src/makefile.mk b/src/makefile.mk index 3acbe3d69..739e0cb91 100644 --- a/src/makefile.mk +++ b/src/makefile.mk @@ -130,9 +130,18 @@ LINKER_SCRIPT ?= $(call FORWARD_PATH,$(CEDEV_TOOLCHAIN)/meta/linker_script.ld) # allocator (malloc/realloc/free) ifeq ($(ALLOCATOR),STANDARD) LIB_ALLOCATOR = $(call FORWARD_PATH,$(CEDEV_TOOLCHAIN)/lib/libc/allocator_standard.a) -endif -ifeq ($(ALLOCATOR),SIMPLE) +else ifeq ($(ALLOCATOR),SIMPLE) LIB_ALLOCATOR = $(call FORWARD_PATH,$(CEDEV_TOOLCHAIN)/lib/libc/allocator_simple.a) +else ifeq ($(ALLOCATOR),CUSTOM) +LIB_ALLOCATOR = +else +$(error ALLOCATOR must be one of STANDARD, SIMPLE, or CUSTOM) +endif + +ifeq ($(ALLOCATOR),CUSTOM) +CUSTOM_ALLOCATOR_SYMBOLS = --undefined _malloc --undefined _free --undefined _realloc +else +CUSTOM_ALLOCATOR_SYMBOLS = endif # ensure always a hexadecimal value @@ -481,7 +490,7 @@ $(OBJDIR)/%.$(CPP_EXTENSION).bc: $$(call UPDIR_RM,$$*).$(CPP_EXTENSION) $(EXTRA_ $(Q)$(CC) -MD -c -emit-llvm $(EZCXXFLAGS) $(call QUOTE_ARG,$<) -o $(call QUOTE_ARG,$@) # crt -$(OBJDIR)/$(TARGETTMP): $(OBJECTS) $(LIB_ALLOCATOR) $(LIB_PRINTF) $(LIB_CXX) $(LIB_CE) $(LIB_SOFTFLOAT) $(LIB_CRT) $(LIB_C) $(ICON_OBJ) $(EXTRA_LIBS) $(MAKEFILE_LIST) $(DEPS) +$(OBJDIR)/$(TARGETTMP): $(OBJECTS) $(LIB_PRINTF) $(LIB_CXX) $(LIB_CE) $(LIB_SOFTFLOAT) $(LIB_CRT) $(LIB_C) $(ICON_OBJ) $(EXTRA_LIBS) $(MAKEFILE_LIST) $(DEPS) $(Q)$(call MKDIR,$(@D)) $(Q)$(LD) \ -i \ @@ -491,6 +500,7 @@ $(OBJDIR)/$(TARGETTMP): $(OBJECTS) $(LIB_ALLOCATOR) $(LIB_PRINTF) $(LIB_CXX) $(L --gc-sections \ --omagic \ --defsym __TICE__=1 \ + $(CUSTOM_ALLOCATOR_SYMBOLS) \ $(SPRINTF_SYMBOL) \ $(LD_DEBUG) \ $(EXTRA_PRE_LDFLAGS) \ @@ -499,7 +509,6 @@ $(OBJDIR)/$(TARGETTMP): $(OBJECTS) $(LIB_ALLOCATOR) $(LIB_PRINTF) $(LIB_CXX) $(L $(EXTRA_LIBS) \ --whole-archive $(LIB_PRINTF) --no-whole-archive \ --start-group \ - $(LIB_ALLOCATOR) \ $(LIB_CRT) \ $(LIB_CE) \ $(LIB_SOFTFLOAT) \ diff --git a/test/standalone/custom_allocator/autotest.json b/test/standalone/custom_allocator/autotest.json new file mode 100644 index 000000000..976317a35 --- /dev/null +++ b/test/standalone/custom_allocator/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|400", + "hashWait|2", + "key|enter", + "delay|400", + "hashWait|3", + "key|enter", + "delay|400", + "hashWait|4" + ], + "hashes": { + "1": { + "description": "calloc should clear the memory from custom malloc", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "8CC9FD0C" + ] + }, + "2": { + "description": "we expect malloc to be called twice (for calloc and atexit)", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "C1BC5A5C" + ] + }, + "3": { + "description": "custom free should print a custom message", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "BD82EEA3" + ] + }, + "4": { + "description": "Exit", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ + "FFAF89BA", + "101734A5", + "9DA19F44", + "A32840C8", + "349F4775" + ] + } + } +} diff --git a/test/standalone/custom_allocator/makefile b/test/standalone/custom_allocator/makefile new file mode 100644 index 000000000..3e7405ed8 --- /dev/null +++ b/test/standalone/custom_allocator/makefile @@ -0,0 +1,21 @@ +# ---------------------------- +# Makefile Options +# ---------------------------- + +NAME = DEMO +ICON = icon.png +DESCRIPTION = "CE C Toolchain Demo" +COMPRESSED = NO +ARCHIVED = NO + +CFLAGS = -Wall -Wextra -Wshadow -Oz +CXXFLAGS = -Wall -Wextra -Wshadow -Oz + +PREFER_OS_LIBC = NO +PREFER_OS_CRT = NO +HAS_PRINTF = NO +ALLOCATOR = CUSTOM + +# ---------------------------- + +include $(shell cedev-config --makefile) diff --git a/test/standalone/custom_allocator/src/custom_free.s b/test/standalone/custom_allocator/src/custom_free.s new file mode 100644 index 000000000..c8792c9d3 --- /dev/null +++ b/test/standalone/custom_allocator/src/custom_free.s @@ -0,0 +1,23 @@ + .assume adl=1 + + .section .rodata._free_string + .local _free_string +_free_string: + .asciz "called free" + + .section .text._free + .global _free + .type _free, @function +_free: + ld hl, _free_string + push hl + call _puts + pop hl +.L.wait_loop: + call _os_GetCSC + or a, a + jr z, .L.wait_loop + ret + + .extern _puts + .extern _os_GetCSC diff --git a/test/standalone/custom_allocator/src/custom_malloc.c b/test/standalone/custom_allocator/src/custom_malloc.c new file mode 100644 index 000000000..748245577 --- /dev/null +++ b/test/standalone/custom_allocator/src/custom_malloc.c @@ -0,0 +1,19 @@ +#include +#include + +static unsigned char arr[4096]; + +static unsigned char *arr_ptr = &arr[0]; + +int malloc_calls = 0; + +void *malloc(size_t size) { + if (size >= sizeof(arr)) { + return NULL; + } + unsigned char *ret = arr_ptr; + arr_ptr += size; + memset(ret, 0xAA, size); + malloc_calls++; + return ret; +} diff --git a/test/standalone/custom_allocator/src/main.c b/test/standalone/custom_allocator/src/main.c new file mode 100644 index 000000000..94796efa1 --- /dev/null +++ b/test/standalone/custom_allocator/src/main.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + +extern int malloc_calls; + +void atexit_func(void) { + /* + * The custom free function is supposed to print a string if it is called, + * however, it is unspecified if atexit_func or free will be called first. + * This means that we cannot print anything in this function since we + * cannot guarantee the order. However, this function must be non-empty so + * Clang does not optimize away the call to atexit. Now some of this could + * be fixed with -ffreestanding, but that may also hide the assumptions + * that Clang makes. + */ + if (*(const char*)-1 != 0) { + puts("0xFFFFFF should be zero"); + while (!os_GetCSC()); + } +} + +int main(void) { + char buf[50]; + os_ClrHome(); + + // CRT0 may use malloc/free so we cannot assume this is zero + int malloc_calls_before = malloc_calls; + + // calloc should call the custom malloc + int *ptr = calloc(1, sizeof(int[3])); + + if (ptr == NULL) { + puts("calloc failed"); + while (!os_GetCSC()); + return 0; + } + + for (int n = 0; n < 3; ++n) { + boot_sprintf(buf, "ptr(%d) == %d", n, ptr[n]); + puts(buf); + } + + while (!os_GetCSC()); + + if (atexit(atexit_func) != 0) { + puts("atexit(atexit_func) failed"); + while (!os_GetCSC()); + return 0; + } + + // we expect malloc to be called twice (for calloc and atexit) + int malloc_call_count = malloc_calls - malloc_calls_before; + boot_sprintf(buf, "malloc calls: %d", malloc_call_count); + puts(buf); + + while (!os_GetCSC()); + + exit(EXIT_SUCCESS); +}