OSDN Git Service

MIPS LDSO: pass sym_ref parameter to _dl_find_hash() to support PROTECTED symbols
[uclinux-h8/uClibc.git] / ldso / ldso / ldso.c
index 37247cd..7ee9257 100644 (file)
 
 #define ALLOW_ZERO_PLTGOT
 
+#if defined(USE_TLS) && USE_TLS
+#include "dl-tls.c"
+#endif
+
 /* Pull in the value of _dl_progname */
 #include LDSO_ELFINTERP
 
 /* Global variables used within the shared library loader */
 char *_dl_library_path         = NULL; /* Where we look for libraries */
+#ifdef __LDSO_PRELOAD_ENV_SUPPORT__
 char *_dl_preload              = NULL; /* Things to be loaded before the libs */
+#endif
 char *_dl_ldsopath             = NULL; /* Location of the shared lib loader */
 int _dl_errno                  = 0;    /* We can't use the real errno in ldso */
 size_t _dl_pagesize            = 0;    /* Store the page size for use later */
@@ -187,7 +193,7 @@ void *_dl_malloc(size_t size)
 
                _dl_debug_early("mmapping more memory\n");
                _dl_mmap_zero = _dl_malloc_addr = _dl_mmap((void *) 0, rounded_size,
-                               PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+                               PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZE, -1, 0);
                if (_dl_mmap_check_error(_dl_mmap_zero)) {
                        _dl_dprintf(_dl_debug_file, "%s: mmap of a spare page failed!\n", _dl_progname);
                        _dl_exit(20);
@@ -213,12 +219,38 @@ static void *_dl_zalloc(size_t size)
        return p;
 }
 
-void _dl_free (void *p)
+void _dl_free(void *p)
 {
        if (_dl_free_function)
                (*_dl_free_function) (p);
 }
 
+#if defined(USE_TLS) && USE_TLS
+void *_dl_memalign(size_t __boundary, size_t __size)
+{
+       void *result;
+       int i = 0;
+       size_t delta;
+       size_t rounded = 0;
+
+       if (_dl_memalign_function)
+               return (*_dl_memalign_function) (__boundary, __size);
+
+       while (rounded < __boundary) {
+               rounded = (1 << i++);
+       }
+
+       delta = (((size_t) _dl_malloc_addr + __size) & (rounded - 1));
+
+       if ((result = _dl_malloc(rounded - delta)) == NULL)
+               return result;
+
+       result = _dl_malloc(__size);
+
+       return result;
+}
+#endif
+
 static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void)
 {
        unsigned int i;
@@ -262,6 +294,9 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
        ElfW(Addr) relro_addr = 0;
        size_t relro_size = 0;
        struct stat st;
+#if defined(USE_TLS) && USE_TLS
+       void *tcbp = NULL;
+#endif
 
        /* Wahoo!!! We managed to make a function call!  Get malloc
         * setup so we can use _dl_dprintf() to print debug noise
@@ -313,7 +348,9 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
             auxvt[AT_UID].a_un.a_val == auxvt[AT_EUID].a_un.a_val &&
             auxvt[AT_GID].a_un.a_val == auxvt[AT_EGID].a_un.a_val)) {
                _dl_secure = 0;
+#ifdef __LDSO_PRELOAD_ENV_SUPPORT__
                _dl_preload = _dl_getenv("LD_PRELOAD", envp);
+#endif
                _dl_library_path = _dl_getenv("LD_LIBRARY_PATH", envp);
        } else {
                static const char unsecure_envvars[] =
@@ -330,24 +367,17 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
                        /* We could use rawmemchr but this need not be fast.  */
                        nextp = _dl_strchr(nextp, '\0') + 1;
                } while (*nextp != '\0');
+#ifdef __LDSO_PRELOAD_ENV_SUPPORT__
                _dl_preload = NULL;
+#endif
                _dl_library_path = NULL;
                /* SUID binaries can be exploited if they do LAZY relocation. */
                unlazy = RTLD_NOW;
        }
 
-       /* sjhill: your TLS init should go before this */
-#ifdef __UCLIBC_HAS_SSP__
-       /* Set up the stack checker's canary.  */
-       stack_chk_guard = _dl_setup_stack_chk_guard ();
-# ifdef THREAD_SET_STACK_GUARD
-       THREAD_SET_STACK_GUARD (stack_chk_guard);
-# else
-       __stack_chk_guard = stack_chk_guard;
-# endif
-# ifdef __UCLIBC_HAS_SSP_COMPAT__
-       __guard = stack_chk_guard;
-# endif
+#if defined(USE_TLS) && USE_TLS
+       _dl_error_catch_tsd = &_dl_initial_error_catch_tsd;
+       _dl_init_static_tls = &_dl_nothread_init_static_tls;
 #endif
 
        /* At this point we are now free to examine the user application,
@@ -406,7 +436,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
                                for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) {
                                        if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
                                                _dl_mprotect((void *) (DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr) & PAGE_ALIGN),
-                                                            ((ppnt->p_vaddr + app_tpnt->loadaddr) & ADDR_ALIGN) +
+                                                            (DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr) & ADDR_ALIGN) +
                                                             (unsigned long) ppnt->p_filesz,
                                                             PROT_READ | PROT_WRITE | PROT_EXEC);
                                }
@@ -447,24 +477,65 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 
                /* OK, fill this in - we did not have this before */
                if (ppnt->p_type == PT_INTERP) {
-                       char *ptmp;
-
                        tpnt->libname = (char *) DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr);
+#ifdef __LDSO_SEARCH_INTERP_PATH__
+                       {
+                               char *ptmp;
+                               /* Store the path where the shared lib loader was found
+                                * for later use
+                                */
+                               _dl_ldsopath = _dl_strdup(tpnt->libname);
+                               ptmp = _dl_strrchr(_dl_ldsopath, '/');
+                               if (ptmp != _dl_ldsopath)
+                                       *ptmp = '\0';
+                       }
+                       _dl_debug_early("Lib Loader: (%x) %s\n", (unsigned) DL_LOADADDR_BASE(tpnt->loadaddr), tpnt->libname);
+#endif
+               }
 
-                       /* Store the path where the shared lib loader was found
-                        * for later use
-                        */
-                       _dl_ldsopath = _dl_strdup(tpnt->libname);
-                       ptmp = _dl_strrchr(_dl_ldsopath, '/');
-                       if (ptmp != _dl_ldsopath)
-                               *ptmp = '\0';
+               /* Discover any TLS sections if the target supports them. */
+               if (ppnt->p_type == PT_TLS) {
+#if defined(USE_TLS) && USE_TLS
+                       if (ppnt->p_memsz > 0) {
+                               app_tpnt->l_tls_blocksize = ppnt->p_memsz;
+                               app_tpnt->l_tls_align = ppnt->p_align;
+                               if (ppnt->p_align == 0)
+                                       app_tpnt->l_tls_firstbyte_offset = 0;
+                               else
+                                       app_tpnt->l_tls_firstbyte_offset =
+                                               (ppnt->p_vaddr & (ppnt->p_align - 1));
+                               app_tpnt->l_tls_initimage_size = ppnt->p_filesz;
+                               app_tpnt->l_tls_initimage = (void *) ppnt->p_vaddr;
 
-                       _dl_debug_early("Lib Loader: (%x) %s\n", (unsigned) DL_LOADADDR_BASE(tpnt->loadaddr), tpnt->libname);
+                               /* This image gets the ID one.  */
+                               _dl_tls_max_dtv_idx = app_tpnt->l_tls_modid = 1;
+
+                       }
+                       _dl_debug_early("Found TLS header for appplication program\n");
+                       break;
+#else
+                       _dl_dprintf(_dl_debug_file, "Program uses unsupported TLS data!\n");
+                       _dl_exit(1);
+#endif
                }
        }
        app_tpnt->relro_addr = relro_addr;
        app_tpnt->relro_size = relro_size;
 
+#if defined(USE_TLS) && USE_TLS
+       /*
+        * Adjust the address of the TLS initialization image in
+        * case the executable is actually an ET_DYN object.
+        */
+       if (app_tpnt->l_tls_initimage != NULL) {
+               app_tpnt->l_tls_initimage =
+                       (char *) app_tpnt->l_tls_initimage + app_tpnt->loadaddr;
+               _dl_debug_early("Relocated TLS initial image from %x to %x (size = %x)\n",
+                       (unsigned int)app_tpnt->l_tls_initimage,
+                       app_tpnt->l_tls_initimage, app_tpnt->l_tls_initimage_size);
+       }
+#endif
+
 #ifdef __SUPPORT_LD_DEBUG__
        _dl_debug = _dl_getenv("LD_DEBUG", envp);
        if (_dl_debug) {
@@ -531,7 +602,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
         */
        debug_addr->r_map = (struct link_map *) _dl_loaded_modules;
        debug_addr->r_version = 1;
-       debug_addr->r_ldbase = DL_LOADADDR_BASE(load_addr);
+       debug_addr->r_ldbase = (ElfW(Addr)) DL_LOADADDR_BASE(load_addr);
        debug_addr->r_brk = (unsigned long) &_dl_debug_state;
        _dl_debug_addr = debug_addr;
 
@@ -545,6 +616,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 
        _dl_map_cache();
 
+#ifdef __LDSO_PRELOAD_ENV_SUPPORT__
        if (_dl_preload) {
                char c, *str, *str2;
 
@@ -600,6 +672,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
                                str++;
                }
        }
+#endif /* __LDSO_PRELOAD_ENV_SUPPORT__ */
 
 #ifdef __LDSO_PRELOAD_FILE_SUPPORT__
        do {
@@ -654,11 +727,11 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 
                        tpnt1 = _dl_load_shared_library(0, &rpnt, NULL, cp2, trace_loaded_objects);
                        if (!tpnt1) {
-#ifdef __LDSO_LDD_SUPPORT__
+# ifdef __LDSO_LDD_SUPPORT__
                                if (trace_loaded_objects)
                                        _dl_dprintf(1, "\t%s => not found\n", cp2);
                                else
-#endif
+# endif
                                {
                                        _dl_dprintf(_dl_debug_file, "%s: can't load library '%s'\n", _dl_progname, cp2);
                                        _dl_exit(15);
@@ -668,14 +741,14 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 
                                _dl_debug_early("Loading: (%x) %s\n", DL_LOADADDR_BASE(tpnt1->loadaddr), tpnt1->libname);
 
-#ifdef __LDSO_LDD_SUPPORT__
+# ifdef __LDSO_LDD_SUPPORT__
                                if (trace_loaded_objects &&
                                    tpnt1->usage_count == 1) {
                                        _dl_dprintf(1, "\t%s => %s (%x)\n",
                                                    cp2, tpnt1->libname,
                                                    DL_LOADADDR_BASE(tpnt1->loadaddr));
                                }
-#endif
+# endif
                        }
 
                        /* find start of next library */
@@ -795,7 +868,16 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
                ElfW(Ehdr) *epnt = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val;
                ElfW(Phdr) *myppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(load_addr, epnt->e_phoff);
                int j;
-
+#ifdef __DSBT__
+               struct elf_resolve *ref = _dl_loaded_modules;
+               _dl_if_debug_dprint("ref is %x, dsbt %x, ref-dsbt %x size %x\n",
+                                   ref, tpnt->loadaddr.map->dsbt_table,
+                                   ref->loadaddr.map->dsbt_table,
+                                   tpnt->loadaddr.map->dsbt_size);
+
+               _dl_memcpy(tpnt->loadaddr.map->dsbt_table, ref->loadaddr.map->dsbt_table,
+                          tpnt->loadaddr.map->dsbt_size * sizeof(unsigned *));
+#endif
                tpnt = _dl_add_elf_hash_table(tpnt->libname, load_addr,
                                              tpnt->dynamic_info,
                                              (unsigned long)tpnt->dynamic_addr,
@@ -850,6 +932,34 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
        }
 #endif
 
+#if defined(USE_TLS) && USE_TLS
+       /* We do not initialize any of the TLS functionality unless any of the
+        * initial modules uses TLS.  This makes dynamic loading of modules with
+        * TLS impossible, but to support it requires either eagerly doing setup
+        * now or lazily doing it later.  Doing it now makes us incompatible with
+        * an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
+        * used.  Trying to do it lazily is too hairy to try when there could be
+        * multiple threads (from a non-TLS-using libpthread).  */
+       bool was_tls_init_tp_called = tls_init_tp_called;
+       if (tcbp == NULL) {
+               _dl_debug_early("Calling init_tls()!\n");
+               tcbp = init_tls ();
+       }
+#endif
+#ifdef __UCLIBC_HAS_SSP__
+       /* Set up the stack checker's canary.  */
+       stack_chk_guard = _dl_setup_stack_chk_guard ();
+# ifdef THREAD_SET_STACK_GUARD
+       THREAD_SET_STACK_GUARD (stack_chk_guard);
+# else
+       __stack_chk_guard = stack_chk_guard;
+# endif
+# ifdef __UCLIBC_HAS_SSP_COMPAT__
+       __guard = stack_chk_guard;
+# endif
+#endif
+
+
        _dl_debug_early("Beginning relocation fixups\n");
 
 #ifdef __mips__
@@ -875,6 +985,28 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
                        _dl_protect_relro (tpnt);
        }
 
+#if defined(USE_TLS) && USE_TLS
+       if (!was_tls_init_tp_called && _dl_tls_max_dtv_idx > 0)
+               ++_dl_tls_generation;
+
+       _dl_debug_early("Calling _dl_allocate_tls_init()!\n");
+
+       /* Now that we have completed relocation, the initializer data
+          for the TLS blocks has its final values and we can copy them
+          into the main thread's TLS area, which we allocated above.  */
+       _dl_allocate_tls_init (tcbp);
+
+       /* And finally install it for the main thread.  If ld.so itself uses
+          TLS we know the thread pointer was initialized earlier.  */
+       if (! tls_init_tp_called) {
+               const char *lossage = (char *) 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);
+               }
+       }
+#endif /* USE_TLS */
+
        /* OK, at this point things are pretty much ready to run.  Now we need
         * to touch up a few items that are required, and then we can let the
         * user application have at it.  Note that the dynamic linker itself
@@ -882,7 +1014,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
         * ld.so.1, so we have to look up each symbol individually.
         */
 
-       _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", _dl_symbol_tables, NULL, 0);
+       _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", _dl_symbol_tables, NULL, 0, NULL);
        if (_dl_envp)
                *_dl_envp = (unsigned long) envp;
 
@@ -938,7 +1070,23 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 
        /* Find the real malloc function and make ldso functions use that from now on */
        _dl_malloc_function = (void* (*)(size_t)) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "malloc",
-                       _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
+                       _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
+#if defined(USE_TLS) && USE_TLS
+       /* Find the real functions and make ldso functions use them from now on */
+       _dl_calloc_function = (void* (*)(size_t, size_t)) (intptr_t)
+               _dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
+       _dl_realloc_function = (void* (*)(void *, size_t)) (intptr_t)
+               _dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
+       _dl_free_function = (void (*)(void *)) (intptr_t)
+               _dl_find_hash(__C_SYMBOL_PREFIX__ "free", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
+       _dl_memalign_function = (void* (*)(size_t, size_t)) (intptr_t)
+               _dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+
+#endif
 
        /* Notify the debugger that all objects are now mapped in.  */
        _dl_debug_addr->r_state = RT_CONSISTENT;