/* Do some minimal initialization which has to be done during the startup of the C library. */ void __pthread_initialize_minimal(void) { #ifdef USE_TLS pthread_descr self; /* First of all init __pthread_handles[0] and [1] if needed. */ # if __LT_SPINLOCK_INIT != 0 __pthread_handles[0].h_lock = __LOCK_INITIALIZER; __pthread_handles[1].h_lock = __LOCK_INITIALIZER; # endif # ifndef SHARED /* Unlike in the dynamically linked case the dynamic linker has not taken care of initializing the TLS data structures. */ __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN); # elif !USE___THREAD if (__builtin_expect (GL(dl_tls_dtv_slotinfo_list) == NULL, 0)) { tcbhead_t *tcbp; /* There is no actual TLS being used, so the thread register was not initialized in the dynamic linker. */ /* We need to install special hooks so that the malloc and memalign calls in _dl_tls_setup and _dl_allocate_tls won't cause full malloc initialization that will try to set up its thread state. */ extern void __libc_malloc_pthread_startup (bool first_time); __libc_malloc_pthread_startup (true); if (__builtin_expect (_dl_tls_setup (), 0) || __builtin_expect ((tcbp = _dl_allocate_tls (NULL)) == NULL, 0)) { static const char msg[] = "\ cannot allocate TLS data structures for initial thread\n"; TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, msg, sizeof msg - 1)); abort (); } const char *lossage = TLS_INIT_TP (tcbp, 0); if (__builtin_expect (lossage != NULL, 0)) { static const char msg[] = "cannot set up thread-local storage: "; const char nl = '\n'; TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, msg, sizeof msg - 1)); TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, lossage, strlen (lossage))); TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, &nl, 1)); } /* Though it was allocated with libc's malloc, that was done without the user's __malloc_hook installed. A later realloc that uses the hooks might not work with that block from the plain malloc. So we record this block as unfreeable just as the dynamic linker does when it allocates the DTV before the libc malloc exists. */ GL(dl_initial_dtv) = GET_DTV (tcbp); __libc_malloc_pthread_startup (false); }
internal_function init_tls (void) { /* Number of elements in the static TLS block. */ _dl_tls_static_nelem = _dl_tls_max_dtv_idx; /* Do not do this twice. The audit interface might have required the DTV interfaces to be set up early. */ if (_dl_initial_dtv != NULL) return NULL; /* Allocate the array which contains the information about the dtv slots. We allocate a few entries more than needed to avoid the need for reallocation. */ size_t nelem = _dl_tls_max_dtv_idx + 1 + TLS_SLOTINFO_SURPLUS; /* Allocate. */ _dl_assert (_dl_tls_dtv_slotinfo_list == NULL); _dl_tls_dtv_slotinfo_list = (struct dtv_slotinfo_list *) _dl_calloc (sizeof (struct dtv_slotinfo_list) + nelem * sizeof (struct dtv_slotinfo), 1); /* No need to check the return value. If memory allocation failed the program would have been terminated. */ struct dtv_slotinfo *slotinfo = _dl_tls_dtv_slotinfo_list->slotinfo; _dl_tls_dtv_slotinfo_list->len = nelem; _dl_tls_dtv_slotinfo_list->next = NULL; /* Fill in the information from the loaded modules. No namespace but the base one can be filled at this time. */ int i = 0; struct link_map *l; for (l = (struct link_map *) _dl_loaded_modules; l != NULL; l = l->l_next) if (l->l_tls_blocksize != 0) { /* This is a module with TLS data. Store the map reference. The generation counter is zero. */ /* Skeep slot[0]: it will be never used */ slotinfo[++i].map = l; } _dl_assert (i == _dl_tls_max_dtv_idx); /* Compute the TLS offsets for the various blocks. */ _dl_determine_tlsoffset (); /* Construct the static TLS block and the dtv for the initial thread. For some platforms this will include allocating memory for the thread descriptor. The memory for the TLS block will never be freed. It should be allocated accordingly. The dtv array can be changed if dynamic loading requires it. */ void *tcbp = _dl_allocate_tls_storage (); if (tcbp == NULL) { _dl_debug_early("\ncannot allocate TLS data structures for initial thread"); _dl_exit(30); } /* Store for detection of the special case by __tls_get_addr so it knows not to pass this dtv to the normal realloc. */ _dl_initial_dtv = GET_DTV (tcbp); /* And finally install it for the main thread. If ld.so itself uses TLS we know the thread pointer was initialized earlier. */ const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD); if(__builtin_expect (lossage != NULL, 0)) { _dl_debug_early("cannot set up thread-local storage: %s\n", lossage); _dl_exit(30); } tls_init_tp_called = true; return tcbp; }
void _start(void) { // WARNING: __hart_self_on_entry must be read before // anything is register-allocated! int id = __hart_self_on_entry; static int init = 0; // For dynamically-linked programs, the first time through, // __hart_self_on_entry could be clobbered (on x86), because // the linker will have overwritten eax. Happily, the first // time through, we know we are vcore 0. Subsequent entries // into this routine do not have this problem. if(init == 0) id = 0; // threads besides thread 0 must acquire a TCB. if(id != 0) { TLS_INIT_TP(__hart_thread_control_blocks[id],0); hart_entry(); hart_yield(); failmsg("why did hart_yield() return?"); goto diediedie; } if(init) { failmsg("why did thread 0 re-enter _start?"); goto diediedie; } init = 1; extern int main(int,char**,char**); extern void __libc_csu_init(int,char**,char**); extern void __libc_csu_fini(void); extern void __libc_start_main(typeof(&main),int,char**, typeof(&__libc_csu_init), typeof(&__libc_csu_fini), void*,void*); char** argv = (char**)alloca(sizeof(__procinfo.argp)); memcpy(argv,__procinfo.argp,sizeof(__procinfo.argp)); char* argbuf = (char*)alloca(sizeof(__procinfo.argbuf)); memcpy(argbuf,__procinfo.argbuf,sizeof(__procinfo.argbuf)); for(int i = 0; i < PROCINFO_MAX_ARGP; i++) if(argv[i]) argv[i] += argbuf - __procinfo.argbuf; int argc = 0; while(argv[argc]) argc++; extern char** _environ; _environ = argv+argc+1; __libc_start_main(&main,argc,argv,&__libc_csu_init,&__libc_csu_fini,0,0); failmsg("why did main() return?"); diediedie: abort(); #ifdef ABORT_INSTRUCTION ABORT_INSTRUCTION; #endif while(1); }