Commit 63aa5317 authored by Thomas Weißschuh's avatar Thomas Weißschuh

tools/nolibc: add support for constructors and destructors

With the startup code moved to C, implementing support for
constructors and deconstructors is fairly easy to implement.

Examples for code size impact:

   text	   data	    bss	    dec	    hex	filename
  21837	    104	     88	  22029	   560d	nolibc-test.before
  22135	    120	     88	  22343	   5747	nolibc-test.after
  21970	    104	     88	  22162	   5692 nolibc-test.after-only-crt.h-changes

The sections are defined by [0].

[0] https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.dynamic.htmlSigned-off-by: default avatarThomas Weißschuh <linux@weissschuh.net>
Acked-by: default avatarWilly Tarreau <w@1wt.eu>
Link: https://lore.kernel.org/lkml/20231007-nolibc-constructors-v2-1-ef84693efbc1@weissschuh.net/
parent eddfc3c7
...@@ -13,12 +13,23 @@ const unsigned long *_auxv __attribute__((weak)); ...@@ -13,12 +13,23 @@ const unsigned long *_auxv __attribute__((weak));
static void __stack_chk_init(void); static void __stack_chk_init(void);
static void exit(int); static void exit(int);
extern void (*const __preinit_array_start[])(void) __attribute__((weak));
extern void (*const __preinit_array_end[])(void) __attribute__((weak));
extern void (*const __init_array_start[])(void) __attribute__((weak));
extern void (*const __init_array_end[])(void) __attribute__((weak));
extern void (*const __fini_array_start[])(void) __attribute__((weak));
extern void (*const __fini_array_end[])(void) __attribute__((weak));
__attribute__((weak)) __attribute__((weak))
void _start_c(long *sp) void _start_c(long *sp)
{ {
long argc; long argc;
char **argv; char **argv;
char **envp; char **envp;
int exitcode;
void (* const *func)(void);
const unsigned long *auxv; const unsigned long *auxv;
/* silence potential warning: conflicting types for 'main' */ /* silence potential warning: conflicting types for 'main' */
int _nolibc_main(int, char **, char **) __asm__ ("main"); int _nolibc_main(int, char **, char **) __asm__ ("main");
...@@ -55,8 +66,18 @@ void _start_c(long *sp) ...@@ -55,8 +66,18 @@ void _start_c(long *sp)
; ;
_auxv = auxv; _auxv = auxv;
for (func = __preinit_array_start; func < __preinit_array_end; func++)
(*func)();
for (func = __init_array_start; func < __init_array_end; func++)
(*func)();
/* go to application */ /* go to application */
exit(_nolibc_main(argc, argv, envp)); exitcode = _nolibc_main(argc, argv, envp);
for (func = __fini_array_end; func > __fini_array_start;)
(*--func)();
exit(exitcode);
} }
#endif /* _NOLIBC_CRT_H */ #endif /* _NOLIBC_CRT_H */
...@@ -57,6 +57,9 @@ static int test_argc; ...@@ -57,6 +57,9 @@ static int test_argc;
/* will be used by some test cases as readable file, please don't write it */ /* will be used by some test cases as readable file, please don't write it */
static const char *argv0; static const char *argv0;
/* will be used by constructor tests */
static int constructor_test_value;
/* definition of a series of tests */ /* definition of a series of tests */
struct test { struct test {
const char *name; /* test name */ const char *name; /* test name */
...@@ -594,6 +597,19 @@ int expect_strne(const char *expr, int llen, const char *cmp) ...@@ -594,6 +597,19 @@ int expect_strne(const char *expr, int llen, const char *cmp)
#define CASE_TEST(name) \ #define CASE_TEST(name) \
case __LINE__: llen += printf("%d %s", test, #name); case __LINE__: llen += printf("%d %s", test, #name);
/* constructors validate that they are executed in definition order */
__attribute__((constructor))
static void constructor1(void)
{
constructor_test_value = 1;
}
__attribute__((constructor))
static void constructor2(void)
{
constructor_test_value *= 2;
}
int run_startup(int min, int max) int run_startup(int min, int max)
{ {
int test; int test;
...@@ -630,6 +646,7 @@ int run_startup(int min, int max) ...@@ -630,6 +646,7 @@ int run_startup(int min, int max)
CASE_TEST(environ_HOME); EXPECT_PTRNZ(1, getenv("HOME")); break; CASE_TEST(environ_HOME); EXPECT_PTRNZ(1, getenv("HOME")); break;
CASE_TEST(auxv_addr); EXPECT_PTRGT(test_auxv != (void *)-1, test_auxv, brk); break; CASE_TEST(auxv_addr); EXPECT_PTRGT(test_auxv != (void *)-1, test_auxv, brk); break;
CASE_TEST(auxv_AT_UID); EXPECT_EQ(1, getauxval(AT_UID), getuid()); break; CASE_TEST(auxv_AT_UID); EXPECT_EQ(1, getauxval(AT_UID), getuid()); break;
CASE_TEST(constructor); EXPECT_EQ(1, constructor_test_value, 2); break;
case __LINE__: case __LINE__:
return ret; /* must be last */ return ret; /* must be last */
/* note: do not set any defaults so as to permit holes above */ /* note: do not set any defaults so as to permit holes above */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment