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.html Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> Acked-by: Willy Tarreau <w@1wt.eu> Link: https://lore.kernel.org/lkml/20231007-nolibc-constructors-v2-1-ef84693efbc1@weissschuh.net/
This commit is contained in:
parent
eddfc3c742
commit
63aa531716
@ -13,12 +13,23 @@ const unsigned long *_auxv __attribute__((weak));
|
||||
static void __stack_chk_init(void);
|
||||
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))
|
||||
void _start_c(long *sp)
|
||||
{
|
||||
long argc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
int exitcode;
|
||||
void (* const *func)(void);
|
||||
const unsigned long *auxv;
|
||||
/* silence potential warning: conflicting types for 'main' */
|
||||
int _nolibc_main(int, char **, char **) __asm__ ("main");
|
||||
@ -55,8 +66,18 @@ void _start_c(long *sp)
|
||||
;
|
||||
_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 */
|
||||
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 */
|
||||
|
@ -57,6 +57,9 @@ static int test_argc;
|
||||
/* will be used by some test cases as readable file, please don't write it */
|
||||
static const char *argv0;
|
||||
|
||||
/* will be used by constructor tests */
|
||||
static int constructor_test_value;
|
||||
|
||||
/* definition of a series of tests */
|
||||
struct test {
|
||||
const char *name; /* test name */
|
||||
@ -594,6 +597,19 @@ int expect_strne(const char *expr, int llen, const char *cmp)
|
||||
#define CASE_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 test;
|
||||
@ -630,6 +646,7 @@ int run_startup(int min, int max)
|
||||
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_AT_UID); EXPECT_EQ(1, getauxval(AT_UID), getuid()); break;
|
||||
CASE_TEST(constructor); EXPECT_EQ(1, constructor_test_value, 2); break;
|
||||
case __LINE__:
|
||||
return ret; /* must be last */
|
||||
/* note: do not set any defaults so as to permit holes above */
|
||||
|
Loading…
Reference in New Issue
Block a user