]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat(ulibc): add __libc_init_array/__libc_fini_array and update crt0.S
authorTulio A M Mendes <[email protected]>
Fri, 3 Apr 2026 19:52:58 +0000 (16:52 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 3 Apr 2026 19:52:58 +0000 (16:52 -0300)
Add constructor/destructor support to ulibc:
- New file init_fini.c: implements __libc_init_array() to run .preinit_array
  and .init_array global constructors, and __libc_fini_array() to run
  .fini_array global destructors.
- Updated crt0.S: calls __libc_init_array before main and __libc_fini_array
  after main returns (matching Newlib crt0 behavior). Also uses 'environ'
  symbol (POSIX) and adds .note.GNU-stack for NX compatibility.

user/ulibc/src/crt0.S
user/ulibc/src/init_fini.c [new file with mode: 0644]

index 8e33b023a25b29d4d66cea05b405c14a86b4752d..cadc2028b3a2c05e77e9abcef416b85e6a01fd24 100644 (file)
@@ -21,7 +21,9 @@
 .global _start
 .extern main
 .extern exit
-.extern __environ
+.extern environ
+.extern __libc_init_array
+.extern __libc_fini_array
 
 _start:
     /* Set up user data segments */
@@ -41,16 +43,33 @@ _start:
     shl $2, %edx
     add %ecx, %edx          /* edx = envp */
 
-    /* Store envp in __environ global (weak, may not exist) */
-    mov %edx, __environ
+    /* Store envp in environ global */
+    mov %edx, environ
+
+    /* Save argc/argv/envp across init_array call */
+    push %edx               /* envp */
+    push %ecx               /* argv */
+    push %eax               /* argc */
+
+    /* Run global constructors / init_array */
+    call __libc_init_array
+
+    /* Restore argc/argv/envp and call main */
+    pop %eax                /* argc */
+    pop %ecx                /* argv */
+    pop %edx                /* envp */
 
-    /* Call main(argc, argv, envp) */
     push %edx               /* envp */
     push %ecx               /* argv */
     push %eax               /* argc */
     call main
     add $12, %esp
 
+    /* Run global destructors / fini_array */
+    push %eax               /* save main return value */
+    call __libc_fini_array
+    pop %eax
+
     /* exit(main return value) */
     push %eax
     call exit
diff --git a/user/ulibc/src/init_fini.c b/user/ulibc/src/init_fini.c
new file mode 100644 (file)
index 0000000..d409d04
--- /dev/null
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2018, Tulio A M Mendes <[email protected]>
+ * All rights reserved.
+ * See LICENSE for details.
+ *
+ * Source: https://github.com/tadryanom/AdrOS
+ */
+
+/*
+ * __libc_init_array / __libc_fini_array — run global constructors/destructors
+ *
+ * These iterate over .preinit_array, .init_array, and .fini_array sections
+ * created by the linker.  Required for __attribute__((constructor)),
+ * __attribute__((destructor)), and C++ static initializers.
+ *
+ * The symbols __preinit_array_start, __init_array_start, __init_array_end,
+ * __fini_array_start, __fini_array_end are defined by the linker script.
+ * _init() and _fini() come from crti.o/crtn.o (GCC CRT files).
+ */
+
+#include <stddef.h>
+
+typedef void (*init_func)(void);
+
+extern init_func __preinit_array_start[];
+extern init_func __preinit_array_end[];
+extern init_func __init_array_start[];
+extern init_func __init_array_end[];
+extern init_func __fini_array_start[];
+extern init_func __fini_array_end[];
+
+extern void _init(void);
+extern void _fini(void);
+
+void __libc_init_array(void) {
+    size_t count, i;
+
+    count = (size_t)(__preinit_array_end - __preinit_array_start);
+    for (i = 0; i < count; i++)
+        __preinit_array_start[i]();
+
+    _init();
+
+    count = (size_t)(__init_array_end - __init_array_start);
+    for (i = 0; i < count; i++)
+        __init_array_start[i]();
+}
+
+void __libc_fini_array(void) {
+    size_t count;
+
+    count = (size_t)(__fini_array_end - __fini_array_start);
+    while (count-- > 0)
+        __fini_array_start[count]();
+
+    _fini();
+}