diff options
Diffstat (limited to 'libc/misc/internals')
-rw-r--r-- | libc/misc/internals/__uClibc_main.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index d80565e2c..d8286f20b 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -48,6 +48,39 @@ int _pe_secure = 0; libc_hidden_data_def(_pe_secure) +#if !defined(SHARED) && defined(__FDPIC__) +struct funcdesc_value +{ + void *entry_point; + void *got_value; +} __attribute__((__aligned__(8))); + + +/* Prevent compiler optimization that removes GOT assignment. + + Due to optimization passes (block split and move), in the rare case + where use r9 is the single instruction in a block we can have the + following behaviour: + - this block is marked as a forward block since use is not + considered as an active instruction after reload pass. + + - In this case a jump in this block can be moved to the start of the + next one and so remove use in this flow of instructions which can + lead to a removal of r9 restoration after a call. */ +#define _dl_stabilize_funcdesc(val) \ + ({ __asm__ ("" : "+m" (*(val))); (val); }) + +static void fdpic_init_array_jump(void *addr) +{ + struct funcdesc_value *fm = (struct funcdesc_value *) fdpic_init_array_jump; + struct funcdesc_value fd = {addr, fm->got_value}; + + void (*pf)(void) = (void*) _dl_stabilize_funcdesc(&fd); + + (*pf)(); +} +#endif + #ifndef SHARED void *__libc_stack_end = NULL; @@ -307,7 +340,11 @@ void __uClibc_fini(void) # elif !defined (__UCLIBC_FORMAT_SHARED_FLAT__) size_t i = __fini_array_end - __fini_array_start; while (i-- > 0) +#if !defined(SHARED) && defined(__FDPIC__) + fdpic_init_array_jump(__fini_array_start[i]); +#else (*__fini_array_start [i]) (); +#endif # endif if (__app_fini != NULL) (__app_fini)(); @@ -436,7 +473,11 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc, const size_t size = __preinit_array_end - __preinit_array_start; size_t i; for (i = 0; i < size; i++) +#if !defined(SHARED) && defined(__FDPIC__) + fdpic_init_array_jump(__preinit_array_start[i]); +#else (*__preinit_array_start [i]) (); +#endif } # endif /* Run all the application's ctors now. */ @@ -452,7 +493,11 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc, const size_t size = __init_array_end - __init_array_start; size_t i; for (i = 0; i < size; i++) +#if !defined(SHARED) && defined(__FDPIC__) + fdpic_init_array_jump(__init_array_start[i]); +#else (*__init_array_start [i]) (); +#endif } # endif #endif |