--- libc/elf/rtld.c 2004/10/06 03:17:28 1.333 +++ libc/elf/rtld.c 2004/10/14 02:07:44 1.334 @@ -269,6 +269,7 @@ GL(dl_rtld_map).l_mach = info->l.l_mach; #endif _dl_setup_hash (&GL(dl_rtld_map)); + GL(dl_rtld_map).l_real = &GL(dl_rtld_map); GL(dl_rtld_map).l_opencount = 1; GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin; GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end; @@ -585,14 +586,16 @@ { struct map_args *args = (struct map_args *) a; args->map = _dl_map_object (args->loader, args->str, - args->is_preloaded, lt_library, 0, args->mode); + args->is_preloaded, lt_library, 0, args->mode, + LM_ID_BASE); } static void version_check_doit (void *a) { struct version_check_args *args = (struct version_check_args *) a; - if (_dl_check_all_versions (GL(dl_loaded), 1, args->dotrace) && args->doexit) + if (_dl_check_all_versions (GL(dl_ns)[LM_ID_BASE]._ns_loaded, 1, + args->dotrace) && args->doexit) /* We cannot start the application. Abort now. */ _exit (1); } @@ -601,11 +604,12 @@ static inline struct link_map * find_needed (const char *name) { - unsigned int n = GL(dl_loaded)->l_searchlist.r_nlist; + struct r_scope_elem *scope = &GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_searchlist; + unsigned int n = scope->r_nlist; while (n-- > 0) - if (_dl_name_match_p (name, GL(dl_loaded)->l_searchlist.r_list[n])) - return GL(dl_loaded)->l_searchlist.r_list[n]; + if (_dl_name_match_p (name, scope->r_list[n])) + return scope->r_list[n]; /* Should never happen. */ return NULL; @@ -685,6 +689,7 @@ enum mode mode; struct link_map **preloads; unsigned int npreloads; + struct link_map *main_map; size_t file_size; char *file; bool has_interp = false; @@ -860,31 +865,35 @@ { HP_TIMING_NOW (start); _dl_map_object (NULL, rtld_progname, 0, lt_library, 0, - __RTLD_OPENEXEC); + __RTLD_OPENEXEC, LM_ID_BASE); HP_TIMING_NOW (stop); HP_TIMING_DIFF (load_time, start, stop); } - phdr = GL(dl_loaded)->l_phdr; - phnum = GL(dl_loaded)->l_phnum; + /* Now the map for the main executable is available. */ + main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + + phdr = main_map->l_phdr; + phnum = main_map->l_phnum; /* We overwrite here a pointer to a malloc()ed string. But since the malloc() implementation used at this point is the dummy implementations which has no real free() function it does not makes sense to free the old string first. */ - GL(dl_loaded)->l_name = (char *) ""; - *user_entry = GL(dl_loaded)->l_entry; + main_map->l_name = (char *) ""; + *user_entry = main_map->l_entry; } else { /* Create a link_map for the executable itself. This will be what dlopen on "" returns. */ - _dl_new_object ((char *) "", "", lt_executable, NULL, 0); - if (GL(dl_loaded) == NULL) + _dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE); + main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + if (main_map == NULL) _dl_fatal_printf ("cannot allocate memory for link map\n"); - GL(dl_loaded)->l_phdr = phdr; - GL(dl_loaded)->l_phnum = phnum; - GL(dl_loaded)->l_entry = *user_entry; + main_map->l_phdr = phdr; + main_map->l_phnum = phnum; + main_map->l_entry = *user_entry; /* At this point we are in a bit of trouble. We would have to fill in the values for l_dev and l_ino. But in general we @@ -905,12 +914,14 @@ information for the program. */ } - GL(dl_loaded)->l_map_end = 0; - GL(dl_loaded)->l_text_end = 0; + main_map->l_map_end = 0; + main_map->l_text_end = 0; /* Perhaps the executable has no PT_LOAD header entries at all. */ - GL(dl_loaded)->l_map_start = ~0; + main_map->l_map_start = ~0; /* We opened the file, account for it. */ - ++GL(dl_loaded)->l_opencount; + ++main_map->l_opencount; + /* And it was opened directly. */ + ++main_map->l_direct_opencount; /* Scan the program header table for the dynamic section. */ for (ph = phdr; ph < &phdr[phnum]; ++ph) @@ -918,12 +929,12 @@ { case PT_PHDR: /* Find out the load address. */ - GL(dl_loaded)->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr; + main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr; break; case PT_DYNAMIC: /* This tells us where to find the dynamic section, which tells us everything we need to do. */ - GL(dl_loaded)->l_ld = (void *) GL(dl_loaded)->l_addr + ph->p_vaddr; + main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr; break; case PT_INTERP: /* This "interpreter segment" was used by the program loader to @@ -932,7 +943,7 @@ dlopen call or DT_NEEDED entry, for something that wants to link against the dynamic linker as a shared library, will know that the shared object is already loaded. */ - _dl_rtld_libname.name = ((const char *) GL(dl_loaded)->l_addr + _dl_rtld_libname.name = ((const char *) main_map->l_addr + ph->p_vaddr); /* _dl_rtld_libname.next = NULL; Already zero. */ GL(dl_rtld_map).l_libname = &_dl_rtld_libname; @@ -968,17 +979,16 @@ ElfW(Addr) allocend; /* Remember where the main program starts in memory. */ - mapstart = (GL(dl_loaded)->l_addr - + (ph->p_vaddr & ~(ph->p_align - 1))); - if (GL(dl_loaded)->l_map_start > mapstart) - GL(dl_loaded)->l_map_start = mapstart; + mapstart = (main_map->l_addr + (ph->p_vaddr & ~(ph->p_align - 1))); + if (main_map->l_map_start > mapstart) + main_map->l_map_start = mapstart; /* Also where it ends. */ - allocend = GL(dl_loaded)->l_addr + ph->p_vaddr + ph->p_memsz; - if (GL(dl_loaded)->l_map_end < allocend) - GL(dl_loaded)->l_map_end = allocend; - if ((ph->p_flags & PF_X) && allocend > GL(dl_loaded)->l_text_end) - GL(dl_loaded)->l_text_end = allocend; + allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz; + if (main_map->l_map_end < allocend) + main_map->l_map_end = allocend; + if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end) + main_map->l_text_end = allocend; } break; #ifdef USE_TLS @@ -989,18 +999,18 @@ here since we read the PT_TLS entry already in _dl_start_final. But the result is repeatable so do not check for this special but unimportant case. */ - GL(dl_loaded)->l_tls_blocksize = ph->p_memsz; - GL(dl_loaded)->l_tls_align = ph->p_align; + main_map->l_tls_blocksize = ph->p_memsz; + main_map->l_tls_align = ph->p_align; if (ph->p_align == 0) - GL(dl_loaded)->l_tls_firstbyte_offset = 0; + main_map->l_tls_firstbyte_offset = 0; else - GL(dl_loaded)->l_tls_firstbyte_offset = (ph->p_vaddr - & (ph->p_align - 1)); - GL(dl_loaded)->l_tls_initimage_size = ph->p_filesz; - GL(dl_loaded)->l_tls_initimage = (void *) ph->p_vaddr; + main_map->l_tls_firstbyte_offset = (ph->p_vaddr + & (ph->p_align - 1)); + main_map->l_tls_initimage_size = ph->p_filesz; + main_map->l_tls_initimage = (void *) ph->p_vaddr; /* This image gets the ID one. */ - GL(dl_tls_max_dtv_idx) = GL(dl_loaded)->l_tls_modid = 1; + GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1; } break; #endif @@ -1009,21 +1019,21 @@ break; case PT_GNU_RELRO: - GL(dl_loaded)->l_relro_addr = ph->p_vaddr; - GL(dl_loaded)->l_relro_size = ph->p_memsz; + main_map->l_relro_addr = ph->p_vaddr; + main_map->l_relro_size = ph->p_memsz; break; } #ifdef USE_TLS /* Adjust the address of the TLS initialization image in case the executable is actually an ET_DYN object. */ - if (GL(dl_loaded)->l_tls_initimage != NULL) - GL(dl_loaded)->l_tls_initimage - = (char *) GL(dl_loaded)->l_tls_initimage + GL(dl_loaded)->l_addr; -#endif - if (! GL(dl_loaded)->l_map_end) - GL(dl_loaded)->l_map_end = ~0; - if (! GL(dl_loaded)->l_text_end) - GL(dl_loaded)->l_text_end = ~0; + if (main_map->l_tls_initimage != NULL) + main_map->l_tls_initimage + = (char *) main_map->l_tls_initimage + main_map->l_addr; +#endif + if (! main_map->l_map_end) + main_map->l_map_end = ~0; + if (! main_map->l_text_end) + main_map->l_text_end = ~0; if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name) { /* We were invoked directly, so the program might not have a @@ -1038,9 +1048,9 @@ if (! rtld_is_main) { /* Extract the contents of the dynamic section for easy access. */ - elf_get_dynamic_info (GL(dl_loaded), NULL); + elf_get_dynamic_info (main_map, NULL); /* Set up our cache of pointers into the hash table. */ - _dl_setup_hash (GL(dl_loaded)); + _dl_setup_hash (main_map); } if (__builtin_expect (mode, normal) == verify) @@ -1049,7 +1059,7 @@ executable using us as the program interpreter. Exit with an error if we were not able to load the binary or no interpreter is specified (i.e., this is no dynamically linked binary. */ - if (GL(dl_loaded)->l_ld == NULL) + if (main_map->l_ld == NULL) _exit (1); /* We allow here some platform specific code. */ @@ -1072,16 +1082,16 @@ found by the PT_INTERP name. */ GL(dl_rtld_map).l_name = (char *) GL(dl_rtld_map).l_libname->name; GL(dl_rtld_map).l_type = lt_library; - GL(dl_loaded)->l_next = &GL(dl_rtld_map); - GL(dl_rtld_map).l_prev = GL(dl_loaded); - ++GL(dl_nloaded); + main_map->l_next = &GL(dl_rtld_map); + GL(dl_rtld_map).l_prev = main_map; + ++GL(dl_ns)[LM_ID_BASE]._ns_nloaded; ++GL(dl_load_adds); /* If LD_USE_LOAD_BIAS env variable has not been seen, default to not using bias for non-prelinked PIEs and libraries and using it for executables or prelinked PIEs or libraries. */ if (GLRO(dl_use_load_bias) == (ElfW(Addr)) -2) - GLRO(dl_use_load_bias) = (GL(dl_loaded)->l_addr == 0) ? -1 : 0; + GLRO(dl_use_load_bias) = main_map->l_addr == 0 ? -1 : 0; /* Set up the program header information for the dynamic linker itself. It is needed in the dl_iterate_phdr() callbacks. */ @@ -1125,8 +1135,9 @@ && (__builtin_expect (! INTUSE(__libc_enable_secure), 1) || strchr (p, '/') == NULL)) { - struct link_map *new_map = _dl_map_object (GL(dl_loaded), p, 1, - lt_library, 0, 0); + struct link_map *new_map = _dl_map_object (main_map, p, 1, + lt_library, 0, 0, + LM_ID_BASE); if (++new_map->l_opencount == 1) /* It is no duplicate. */ ++npreloads; @@ -1208,7 +1219,7 @@ struct map_args args; args.str = p; - args.loader = GL(dl_loaded); + args.loader = main_map; args.is_preloaded = 1; args.mode = 0; @@ -1231,8 +1242,9 @@ if (problem != NULL) { char *p = strndupa (problem, file_size - (problem - file)); - struct link_map *new_map = _dl_map_object (GL(dl_loaded), p, 1, - lt_library, 0, 0); + struct link_map *new_map = _dl_map_object (main_map, p, 1, + lt_library, 0, 0, + LM_ID_BASE); if (++new_map->l_opencount == 1) /* It is no duplicate. */ ++npreloads; @@ -1272,7 +1284,7 @@ We just want our data structures to describe it as if we had just mapped and relocated it normally. */ struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL, - 0); + 0, LM_ID_BASE); if (__builtin_expect (l != NULL, 1)) { static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro; @@ -1337,18 +1349,18 @@ specified some libraries to load, these are inserted before the actual dependencies in the executable's searchlist for symbol resolution. */ HP_TIMING_NOW (start); - _dl_map_object_deps (GL(dl_loaded), preloads, npreloads, mode == trace, 0); + _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0); HP_TIMING_NOW (stop); HP_TIMING_DIFF (diff, start, stop); HP_TIMING_ACCUM_NT (load_time, diff); /* Mark all objects as being in the global scope and set the open counter. */ - for (i = GL(dl_loaded)->l_searchlist.r_nlist; i > 0; ) + for (i = main_map->l_searchlist.r_nlist; i > 0; ) { --i; - GL(dl_loaded)->l_searchlist.r_list[i]->l_global = 1; - ++GL(dl_loaded)->l_searchlist.r_list[i]->l_opencount; + main_map->l_searchlist.r_list[i]->l_global = 1; + ++main_map->l_searchlist.r_list[i]->l_opencount; } #ifndef MAP_ANON @@ -1369,13 +1381,13 @@ chain in symbol search order because gdb uses the chain's order as its symbol search order. */ i = 1; - while (GL(dl_loaded)->l_searchlist.r_list[i] != &GL(dl_rtld_map)) + while (main_map->l_searchlist.r_list[i] != &GL(dl_rtld_map)) ++i; - GL(dl_rtld_map).l_prev = GL(dl_loaded)->l_searchlist.r_list[i - 1]; + GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1]; if (__builtin_expect (mode, normal) == normal) { - GL(dl_rtld_map).l_next = (i + 1 < GL(dl_loaded)->l_searchlist.r_nlist - ? GL(dl_loaded)->l_searchlist.r_list[i + 1] + GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist + ? main_map->l_searchlist.r_list[i + 1] : NULL); #ifdef NEED_DL_SYSINFO if (sysinfo_map != NULL @@ -1459,7 +1471,7 @@ GL(dl_tls_dtv_slotinfo_list)->next = NULL; /* Fill in the information from the loaded modules. */ - for (l = GL(dl_loaded), i = 0; l != NULL; l = l->l_next) + for (l = main_map, i = 0; 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. */ @@ -1495,7 +1507,7 @@ if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) { - struct r_scope_elem *scope = &GL(dl_loaded)->l_searchlist; + struct r_scope_elem *scope = &main_map->l_searchlist; for (i = 0; i < scope->r_nlist; i++) { @@ -1531,7 +1543,7 @@ /* Look through the dependencies of the main executable and determine which of them is not actually required. */ - struct link_map *l = GL(dl_loaded); + struct link_map *l = main_map; /* Relocate the main executable. */ struct relocate_args args = { .l = l, .lazy = GLRO(dl_lazy) }; @@ -1539,7 +1551,7 @@ /* This loop depends on the dependencies of the executable to correspond in number and order to the DT_NEEDED entries. */ - ElfW(Dyn) *dyn = GL(dl_loaded)->l_ld; + ElfW(Dyn) *dyn = main_map->l_ld; bool first = true; while (dyn->d_tag != DT_NULL) { @@ -1564,11 +1576,11 @@ _exit (first != true); } - else if (! GL(dl_loaded)->l_info[DT_NEEDED]) + else if (! main_map->l_info[DT_NEEDED]) _dl_printf ("\tstatically linked\n"); else { - for (l = GL(dl_loaded)->l_next; l; l = l->l_next) + for (l = main_map->l_next; l; l = l->l_next) if (l->l_faked) /* The library was not found. */ _dl_printf ("\t%s => not found\n", l->l_libname->name); @@ -1589,8 +1601,8 @@ ElfW(Addr) loadbase; lookup_t result; - result = _dl_lookup_symbol_x (INTUSE(_dl_argv)[i], GL(dl_loaded), - &ref, GL(dl_loaded)->l_scope, NULL, + result = _dl_lookup_symbol_x (INTUSE(_dl_argv)[i], main_map, + &ref, main_map->l_scope, NULL, ELF_RTYPE_CLASS_PLT, DL_LOOKUP_ADD_DEPENDENCY, NULL); @@ -1613,7 +1625,7 @@ args.lazy = GLRO(dl_lazy); - l = GL(dl_loaded); + l = main_map; while (l->l_next) l = l->l_next; do @@ -1629,7 +1641,7 @@ if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && GL(dl_rtld_map).l_opencount > 1) - _dl_relocate_object (&GL(dl_rtld_map), GL(dl_loaded)->l_scope, + _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); } @@ -1639,9 +1651,9 @@ /* Print more information. This means here, print information about the versions needed. */ int first = 1; - struct link_map *map = GL(dl_loaded); + struct link_map *map; - for (map = GL(dl_loaded); map != NULL; map = map->l_next) + for (map = main_map; map != NULL; map = map->l_next) { const char *strtab; ElfW(Dyn) *dyn = map->l_info[VERNEEDTAG]; @@ -1709,28 +1721,27 @@ _exit (0); } - if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)] + if (main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)] && ! __builtin_expect (GLRO(dl_profile) != NULL, 0)) { ElfW(Lib) *liblist, *liblistend; struct link_map **r_list, **r_listend, *l; - const char *strtab = (const void *) D_PTR (GL(dl_loaded), - l_info[DT_STRTAB]); + const char *strtab = (const void *) D_PTR (main_map, l_info[DT_STRTAB]); - assert (GL(dl_loaded)->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL); + assert (main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)] != NULL); liblist = (ElfW(Lib) *) - GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr; + main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr; liblistend = (ElfW(Lib) *) - ((char *) liblist - + GL(dl_loaded)->l_info [VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val); - r_list = GL(dl_loaded)->l_searchlist.r_list; - r_listend = r_list + GL(dl_loaded)->l_searchlist.r_nlist; + ((char *) liblist + + main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val); + r_list = main_map->l_searchlist.r_list; + r_listend = r_list + main_map->l_searchlist.r_nlist; for (; r_list < r_listend && liblist < liblistend; r_list++) { l = *r_list; - if (l == GL(dl_loaded)) + if (l == main_map) continue; /* If the library is not mapped where it should, fail. */ @@ -1767,9 +1778,7 @@ /* Initialize _r_debug. */ struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr); { - struct link_map *l; - - l = GL(dl_loaded); + struct link_map *l = main_map; #ifdef ELF_MACHINE_DEBUG_SETUP @@ -1793,18 +1802,18 @@ } /* Now set up the variable which helps the assembler startup code. */ - GL(dl_main_searchlist) = &GL(dl_loaded)->l_searchlist; - GL(dl_global_scope)[0] = &GL(dl_loaded)->l_searchlist; + GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist = &main_map->l_searchlist; + GL(dl_ns)[LM_ID_BASE]._ns_global_scope[0] = &main_map->l_searchlist; /* Save the information about the original global scope list since we need it in the memory handling later. */ - GLRO(dl_initial_searchlist) = *GL(dl_main_searchlist); + GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist; if (prelinked) { struct link_map *l; - if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL) + if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL) { ElfW(Rela) *conflict, *conflictend; #ifndef HP_TIMING_NONAVAIL @@ -1813,20 +1822,20 @@ #endif HP_TIMING_NOW (start); - assert (GL(dl_loaded)->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL); + assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL); conflict = (ElfW(Rela) *) - GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr; + main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr; conflictend = (ElfW(Rela) *) ((char *) conflict - + GL(dl_loaded)->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val); - _dl_resolve_conflicts (GL(dl_loaded), conflict, conflictend); + + main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val); + _dl_resolve_conflicts (main_map, conflict, conflictend); HP_TIMING_NOW (stop); HP_TIMING_DIFF (relocate_time, start, stop); } /* Mark all the objects so we know they have been already relocated. */ - for (l = GL(dl_loaded); l != NULL; l = l->l_next) + for (l = main_map; l != NULL; l = l->l_next) { l->l_relocated = 1; if (l->l_relro_size) @@ -1857,7 +1866,7 @@ /* If we are profiling we also must do lazy reloaction. */ GLRO(dl_lazy) |= consider_profiling; - l = GL(dl_loaded); + l = main_map; while (l->l_next) l = l->l_next; @@ -1906,7 +1915,7 @@ /* There was an explicit ref to the dynamic linker as a shared lib. Re-relocate ourselves with user-controlled symbol definitions. */ HP_TIMING_NOW (start); - _dl_relocate_object (&GL(dl_rtld_map), GL(dl_loaded)->l_scope, 0, 0); + _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); HP_TIMING_NOW (stop); HP_TIMING_DIFF (add, start, stop); HP_TIMING_ACCUM_NT (relocate_time, add); @@ -2323,20 +2332,24 @@ #endif unsigned long int num_relative_relocations = 0; - struct r_scope_elem *scope = &GL(dl_loaded)->l_searchlist; - unsigned int i; - - for (i = 0; i < scope->r_nlist; i++) + for (Lmid_t ns = 0; ns < DL_NNS; ++ns) { - struct link_map *l = scope->r_list [i]; + struct r_scope_elem *scope = &GL(dl_ns)[ns]._ns_loaded->l_searchlist; - if (!l->l_addr) - continue; + for (unsigned int i = 0; i < scope->r_nlist; i++) + { + struct link_map *l = scope->r_list [i]; + + if (!l->l_addr) + continue; - if (l->l_info[VERSYMIDX (DT_RELCOUNT)]) - num_relative_relocations += l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val; - if (l->l_info[VERSYMIDX (DT_RELACOUNT)]) - num_relative_relocations += l->l_info[VERSYMIDX (DT_RELACOUNT)]->d_un.d_val; + if (l->l_info[VERSYMIDX (DT_RELCOUNT)]) + num_relative_relocations + += l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val; + if (l->l_info[VERSYMIDX (DT_RELACOUNT)]) + num_relative_relocations + += l->l_info[VERSYMIDX (DT_RELACOUNT)]->d_un.d_val; + } } _dl_debug_printf (" number of relocations: %lu\n" --- libc/elf/do-lookup.h 2004/03/07 05:20:39 1.29 +++ libc/elf/do-lookup.h 2004/10/14 02:06:51 1.30 @@ -42,7 +42,7 @@ int num_versions = 0; const ElfW(Sym) *versioned_sym = NULL; - map = list[i]; + map = list[i]->l_real; /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */ if (skip != NULL && map == skip) --- libc/elf/dl-support.c 2004/09/26 12:11:41 1.85 +++ libc/elf/dl-support.c 2004/10/14 02:06:18 1.86 @@ -67,10 +67,8 @@ /* Nonzero if runtime lookup should not update the .got/.plt. */ int _dl_bind_not; -/* Initially empty list of loaded objects. */ -struct link_map *_dl_loaded; -/* Number of object in the _dl_loaded list. */ -unsigned int _dl_nloaded; +/* Namespace information. */ +struct link_namespaces _dl_ns[DL_NNS]; /* Incremented whenever something may have been added to dl_loaded. */ unsigned long long _dl_load_adds; @@ -79,12 +77,6 @@ main application but here we don't have something like this. So create a fake scope containing nothing. */ struct r_scope_elem _dl_initial_searchlist; -/* Variable which can be used in lookup to process the global scope. */ -struct r_scope_elem *_dl_global_scope[2] = { &_dl_initial_searchlist, NULL }; -/* This is a global pointer to this structure which is public. It is - used by dlopen/dlclose to add and remove objects from what is regarded - to be the global scope. */ -struct r_scope_elem *_dl_main_searchlist = &_dl_initial_searchlist; #ifndef HAVE_INLINED_SYSCALLS /* Nonzero during startup. */ @@ -109,11 +101,6 @@ void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls; #endif -/* This is zero at program start to signal that the global scope map is - allocated by rtld. Later it keeps the size of the map. It might be - reset if in _dl_close if the last global object is removed. */ -size_t _dl_global_scope_alloc; - size_t _dl_pagesize; unsigned int _dl_osversion; --- libc/elf/dl-open.c 2004/09/23 07:43:21 1.112 +++ libc/elf/dl-open.c 2004/10/14 02:05:42 1.113 @@ -72,6 +72,8 @@ /* This is the caller if _dl_open(). */ const void *caller_dl_open; struct link_map *map; + /* Namespace ID. */ + Lmid_t nsid; }; @@ -101,15 +103,17 @@ in an realloc() call. Therefore we allocate a completely new array the first time we have to add something to the locale scope. */ - if (GL(dl_global_scope_alloc) == 0) + if (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc == 0) { /* This is the first dynamic object given global scope. */ - GL(dl_global_scope_alloc) = GL(dl_main_searchlist)->r_nlist + to_add + 8; + GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + 8; new_global = (struct link_map **) - malloc (GL(dl_global_scope_alloc) * sizeof (struct link_map *)); + malloc (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + * sizeof (struct link_map *)); if (new_global == NULL) { - GL(dl_global_scope_alloc) = 0; + GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0; nomem: GLRO(dl_signal_error) (ENOMEM, new->l_libname->name, NULL, N_("cannot extend global scope")); @@ -117,25 +121,26 @@ } /* Copy over the old entries. */ - memcpy (new_global, GL(dl_main_searchlist)->r_list, - (GL(dl_main_searchlist)->r_nlist * sizeof (struct link_map *))); - - GL(dl_main_searchlist)->r_list = new_global; + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list + = memcpy (new_global, + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list, + (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + * sizeof (struct link_map *))); } - else if (GL(dl_main_searchlist)->r_nlist + to_add - > GL(dl_global_scope_alloc)) + else if (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + > GL(dl_ns)[new->l_ns]._ns_global_scope_alloc) { /* We have to extend the existing array of link maps in the main map. */ new_global = (struct link_map **) - realloc (GL(dl_main_searchlist)->r_list, - ((GL(dl_global_scope_alloc) + to_add + 8) + realloc (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list, + ((GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + to_add + 8) * sizeof (struct link_map *))); if (new_global == NULL) goto nomem; - GL(dl_global_scope_alloc) += to_add + 8; - GL(dl_main_searchlist)->r_list = new_global; + GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8; + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global; } /* Now add the new entries. */ @@ -146,9 +151,9 @@ if (map->l_global == 0) { map->l_global = 1; - GL(dl_main_searchlist)->r_list[GL(dl_main_searchlist)->r_nlist] + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list[GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist] = map; - ++GL(dl_main_searchlist)->r_nlist; + ++GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist; } } @@ -175,28 +180,34 @@ GLRO(dl_signal_error) (0, "dlopen", NULL, N_("invalid caller")); /* Determine the caller's map if necessary. This is needed in case - we have a DST or when the file name has no path in which case we - need to look along the RUNPATH/RPATH of the caller. */ + we have a DST, when we don't know the namespace ID we have to put + the new object in, or when the file name has no path in which + case we need to look along the RUNPATH/RPATH of the caller. */ const char *dst = strchr (file, '$'); - if (dst != NULL || strchr (file, '/') == NULL) + if (dst != NULL || args->nsid == __LM_ID_CALLER + || strchr (file, '/') == NULL) { const void *caller_dlopen = args->caller_dlopen; - /* We have to find out from which object the caller is calling. */ - call_map = NULL; - for (l = GL(dl_loaded); l; l = l->l_next) - if (caller_dlopen >= (const void *) l->l_map_start - && caller_dlopen < (const void *) l->l_map_end) - { - /* There must be exactly one DSO for the range of the virtual - memory. Otherwise something is really broken. */ - call_map = l; - break; - } + /* We have to find out from which object the caller is calling. + By default we assume this is the main application. */ + call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + + for (Lmid_t ns = 0; ns < DL_NNS; ++ns) + for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next) + if (caller_dlopen >= (const void *) l->l_map_start + && caller_dlopen < (const void *) l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + assert (ns == l->l_ns); + call_map = l; + goto found_caller; + } - if (call_map == NULL) - /* In this case we assume this is the main application. */ - call_map = GL(dl_loaded); + found_caller: + if (args->nsid == __LM_ID_CALLER) + args->nsid = call_map->l_ns; } /* Maybe we have to expand a DST. */ @@ -238,7 +249,7 @@ /* Load the named object. */ args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0, - mode | __RTLD_CALLMAP); + mode | __RTLD_CALLMAP, args->nsid); /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is set and the object is not already loaded. */ @@ -252,21 +263,30 @@ /* This happens only if we load a DSO for 'sprof'. */ return; + /* This object is directly loaded. */ + ++new->l_direct_opencount; + /* It was already open. */ if (__builtin_expect (new->l_searchlist.r_list != NULL, 0)) { /* Let the user know about the opencount. */ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)) - GLRO(dl_debug_printf) ("opening file=%s; opencount == %u\n\n", - new->l_name, new->l_opencount); + GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n", + new->l_name, new->l_ns, new->l_opencount); /* If the user requested the object to be in the global namespace but it is not so far, add it now. */ if ((mode & RTLD_GLOBAL) && new->l_global == 0) (void) add_to_global (new); - /* Increment just the reference counter of the object. */ - ++new->l_opencount; + if (new->l_direct_opencount == 1) + /* This is the only direct reference. Increment all the + dependencies' reference counter. */ + for (i = 0; i < new->l_searchlist.r_nlist; ++i) + ++new->l_searchlist.r_list[i]->l_opencount; + else + /* Increment just the reference counter of the object. */ + ++new->l_opencount; return; } @@ -277,8 +297,9 @@ /* So far, so good. Now check the versions. */ for (i = 0; i < new->l_searchlist.r_nlist; ++i) - if (new->l_searchlist.r_list[i]->l_versions == NULL) - (void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i], 0, 0); + if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL) + (void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i]->l_real, + 0, 0); #ifdef SCOPE_DEBUG show_scope (new); @@ -295,7 +316,7 @@ l = l->l_next; while (1) { - if (! l->l_relocated) + if (! l->l_real->l_relocated) { #ifdef SHARED if (GLRO(dl_profile) != NULL) @@ -349,7 +370,7 @@ loaded object to the scope. */ for (i = 0; i < new->l_searchlist.r_nlist; ++i) if (++new->l_searchlist.r_list[i]->l_opencount > 1 - && new->l_searchlist.r_list[i]->l_type == lt_loaded) + && new->l_real->l_searchlist.r_list[i]->l_type == lt_loaded) { struct link_map *imap = new->l_searchlist.r_list[i]; struct r_scope_elem **runp = imap->l_scope; @@ -503,14 +524,14 @@ /* Let the user know about the opencount. */ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)) - GLRO(dl_debug_printf) ("opening file=%s; opencount == %u\n\n", - new->l_name, new->l_opencount); + GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n", + new->l_name, new->l_ns, new->l_opencount); } void * internal_function -_dl_open (const char *file, int mode, const void *caller_dlopen) +_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid) { struct dl_open_args args; const char *objname; @@ -525,11 +546,29 @@ /* Make sure we are alone. */ __rtld_lock_lock_recursive (GL(dl_load_lock)); + if (nsid == LM_ID_NEWLM) + { + /* Find a new namespace. */ + for (nsid = 1; nsid < DL_NNS; ++nsid) + if (GL(dl_ns)[nsid]._ns_loaded == NULL) + break; + + if (nsid == DL_NNS) + { + /* No more namespace available. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + GLRO(dl_signal_error) (EINVAL, file, NULL, N_("\ +no more namespaces available for dlmopen()")); + } + } + args.file = file; args.mode = mode; args.caller_dlopen = caller_dlopen; args.caller_dl_open = RETURN_ADDRESS (0); args.map = NULL; + args.nsid = nsid; errcode = GLRO(dl_catch_error) (&objname, &errstring, dl_open_worker, &args); #ifndef MAP_COPY --- libc/elf/dl-object.c 2004/09/23 07:40:25 1.38 +++ libc/elf/dl-object.c 2004/10/14 02:05:07 1.39 @@ -32,7 +32,7 @@ struct link_map * internal_function _dl_new_object (char *realname, const char *libname, int type, - struct link_map *loader, int mode) + struct link_map *loader, int mode, Lmid_t nsid) { struct link_map *l; int idx; @@ -45,6 +45,7 @@ if (new == NULL) return NULL; + new->l_real = new; new->l_libname = newname = (struct libname_list *) (new + 1); newname->name = (char *) memcpy (newname + 1, libname, libname_len); /* newname->next = NULL; We use calloc therefore not necessary. */ @@ -56,6 +57,7 @@ #if defined USE_TLS && NO_TLS_OFFSET != 0 new->l_tls_offset = NO_TLS_OFFSET; #endif + new->l_ns = nsid; /* new->l_global = 0; We use calloc therefore not necessary. */ @@ -68,9 +70,9 @@ /* Counter for the scopes we have to handle. */ idx = 0; - if (GL(dl_loaded) != NULL) + if (GL(dl_ns)[nsid]._ns_loaded != NULL) { - l = GL(dl_loaded); + l = GL(dl_ns)[nsid]._ns_loaded; while (l->l_next != NULL) l = l->l_next; new->l_prev = l; @@ -78,11 +80,11 @@ l->l_next = new; /* Add the global scope. */ - new->l_scope[idx++] = &GL(dl_loaded)->l_searchlist; + new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist; } else - GL(dl_loaded) = new; - ++GL(dl_nloaded); + GL(dl_ns)[nsid]._ns_loaded = new; + ++GL(dl_ns)[nsid]._ns_nloaded; ++GL(dl_load_adds); /* If we have no loader the new object acts as it. */ --- libc/elf/dl-lookup.c 2004/09/18 06:46:15 1.116 +++ libc/elf/dl-lookup.c 2004/10/14 02:04:37 1.117 @@ -137,7 +137,7 @@ reference is still available. There is a brief period in which the object could have been removed since we found the definition. */ - runp = GL(dl_loaded); + runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded; while (runp != NULL && runp != map) runp = runp->l_next; @@ -182,13 +182,18 @@ for (list = map->l_initfini; *list != NULL; ++list) ++(*list)->l_opencount; + /* As if it is opened through _dl_open. */ + ++map->l_direct_opencount; + /* Display information if we are debugging. */ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)) _dl_debug_printf ("\ -\nfile=%s; needed by %s (relocation dependency)\n\n", +\nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n", map->l_name[0] ? map->l_name : rtld_progname, + map->l_ns, undef_map->l_name[0] - ? undef_map->l_name : rtld_progname); + ? undef_map->l_name : rtld_progname, + undef_map->l_ns); } else /* Whoa, that was bad luck. We have to search again. */ @@ -408,8 +413,8 @@ struct sym_val val = { NULL, NULL }; if ((GLRO(dl_trace_prelink_map) == NULL - || GLRO(dl_trace_prelink_map) == GL(dl_loaded)) - && undef_map != GL(dl_loaded)) + || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded) + && undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded) { const unsigned long int hash = _dl_elf_hash (undef_name); @@ -421,12 +426,12 @@ conflict = 1; } -#ifdef USE_TLS +# ifdef USE_TLS if (value->s && (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info) == STT_TLS, 0))) type_class = 4; -#endif +# endif if (conflict || GLRO(dl_trace_prelink_map) == undef_map --- libc/elf/dl-load.c 2004/09/23 07:44:34 1.250 +++ libc/elf/dl-load.c 2004/10/14 02:03:20 1.251 @@ -699,7 +699,7 @@ #ifdef SHARED /* This points to the map of the main object. */ - l = GL(dl_loaded); + l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; if (l != NULL) { assert (l->l_type != lt_loaded); @@ -795,10 +795,10 @@ if (l->l_prev == NULL) /* No other module loaded. This happens only in the static library, or in rtld under --verify. */ - GL(dl_loaded) = NULL; + GL(dl_ns)[l->l_ns]._ns_loaded = NULL; else l->l_prev->l_next = NULL; - --GL(dl_nloaded); + --GL(dl_ns)[l->l_ns]._ns_nloaded; free (l); } free (realname); @@ -815,7 +815,7 @@ struct link_map * _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp, char *realname, struct link_map *loader, int l_type, - int mode, void **stack_endp) + int mode, void **stack_endp, Lmid_t nsid) { struct link_map *l = NULL; const ElfW(Ehdr) *header; @@ -839,7 +839,7 @@ } /* Look again to see if the real name matched another already loaded. */ - for (l = GL(dl_loaded); l; l = l->l_next) + for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next) if (l->l_ino == st.st_ino && l->l_dev == st.st_dev) { /* The object is already loaded. @@ -854,6 +854,31 @@ return l; } +#ifdef SHARED + /* When loading into a namespace other than the base one we must + avoid loading ld.so since there can only be one copy. Ever. */ + if (__builtin_expect (nsid != LM_ID_BASE, 0) + && ((st.st_ino == GL(dl_rtld_map).l_ino + && st.st_dev == GL(dl_rtld_map).l_dev) + || _dl_name_match_p (name, &GL(dl_rtld_map)))) + { + /* This is indeed ld.so. Create a new link_map which refers to + the real one for almost everything. */ + l = _dl_new_object (realname, name, l_type, loader, mode, nsid); + if (l == NULL) + goto fail_new; + + /* Refer to the real descriptor. */ + l->l_real = &GL(dl_rtld_map); + + /* No need to bump the refcount of the real object, ld.so will + never be unloaded. */ + __close (fd); + + return l; + } +#endif + if (mode & RTLD_NOLOAD) /* We are not supposed to load the object unless it is already loaded. So return now. */ @@ -861,7 +886,7 @@ /* Print debugging message. */ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)) - _dl_debug_printf ("file=%s; generating link map\n", name); + _dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid); /* This is the ELF header. We read it in `open_verify'. */ header = (void *) fbp->buf; @@ -881,9 +906,10 @@ #endif /* Enter the new object in the list of loaded objects. */ - l = _dl_new_object (realname, name, l_type, loader, mode); - if (__builtin_expect (! l, 0)) + l = _dl_new_object (realname, name, l_type, loader, mode, nsid); + if (__builtin_expect (l == NULL, 0)) { + fail_new: errstring = N_("cannot create shared object descriptor"); goto call_lose_errno; } @@ -1771,7 +1797,7 @@ struct link_map * internal_function _dl_map_object (struct link_map *loader, const char *name, int preloaded, - int type, int trace_mode, int mode) + int type, int trace_mode, int mode, Lmid_t nsid) { int fd; char *realname; @@ -1779,8 +1805,11 @@ struct link_map *l; struct filebuf fb; + assert (nsid >= 0); + assert (nsid < DL_NNS); + /* Look for this name among those already loaded. */ - for (l = GL(dl_loaded); l; l = l->l_next) + for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next) { /* If the requested name matches the soname of a loaded object, use that object. Elide this check for names that have not @@ -1812,9 +1841,9 @@ /* Display information if we are debugging. */ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0) && loader != NULL) - _dl_debug_printf ("\nfile=%s; needed by %s\n", name, + _dl_debug_printf ("\nfile=%s [%lu]; needed by %s [%lu]\n", name, nsid, loader->l_name[0] - ? loader->l_name : rtld_progname); + ? loader->l_name : rtld_progname, loader->l_ns); if (strchr (name, '/') == NULL) { @@ -1823,7 +1852,7 @@ size_t namelen = strlen (name) + 1; if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)) - _dl_debug_printf ("find library=%s; searching\n", name); + _dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid); fd = -1; @@ -1839,12 +1868,15 @@ &realname, &fb); /* If dynamically linked, try the DT_RPATH of the executable - itself. */ - l = GL(dl_loaded); - if (fd == -1 && l && l->l_type != lt_loaded && l != loader - && l->l_rpath_dirs.dirs != (void *) -1) - fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, - &realname, &fb); + itself. NB: we do this for lookups in any namespace. */ + if (fd == -1) + { + l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + if (l && l->l_type != lt_loaded && l != loader + && l->l_rpath_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, + &realname, &fb); + } } /* Try the LD_LIBRARY_PATH environment variable. */ @@ -1870,7 +1902,8 @@ if (cached != NULL) { #ifdef SHARED - l = loader ?: GL(dl_loaded); + // XXX Correct to unconditionally default to namespace 0? + l = loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded; #else l = loader; #endif @@ -1920,7 +1953,7 @@ /* Finally, try the default path. */ if (fd == -1 - && ((l = loader ?: GL(dl_loaded)) == NULL + && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL || __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1)) && rtld_search_dirs.dirs != (void *) -1) fd = open_path (name, namelen, preloaded, &rtld_search_dirs, @@ -1966,7 +1999,7 @@ /* Enter the new object in the list of loaded objects. */ if ((name_copy = local_strdup (name)) == NULL || (l = _dl_new_object (name_copy, name, type, loader, - mode)) == NULL) + mode, nsid)) == NULL) _dl_signal_error (ENOMEM, name, NULL, N_("cannot create shared object descriptor")); /* Signal that this is a faked entry. */ @@ -1987,7 +2020,7 @@ void *stack_end = __libc_stack_end; return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode, - &stack_end); + &stack_end, nsid); } @@ -2047,10 +2080,13 @@ while (l != NULL); /* If dynamically linked, try the DT_RPATH of the executable itself. */ - l = GL(dl_loaded); - if (l != NULL && l->l_type != lt_loaded && l != loader) - if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH")) - add_path (&l->l_rpath_dirs, XXX_RPATH); + if (loader->l_ns == LM_ID_BASE) + { + l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; + if (l != NULL && l->l_type != lt_loaded && l != loader) + if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH")) + add_path (&l->l_rpath_dirs, XXX_RPATH); + } } /* Try the LD_LIBRARY_PATH environment variable. */ --- libc/elf/dl-libc.c 2004/03/07 08:38:43 1.22 +++ libc/elf/dl-libc.c 2004/10/14 02:02:33 1.23 @@ -77,7 +77,7 @@ { struct do_dlopen_args *args = (struct do_dlopen_args *) ptr; /* Open and relocate the shared object. */ - args->map = _dl_open (args->name, args->mode, NULL); + args->map = _dl_open (args->name, args->mode, NULL, __LM_ID_CALLER); } static void @@ -217,18 +217,19 @@ } /* Remove all additional names added to the objects. */ - for (l = GL(dl_loaded); l != NULL; l = l->l_next) - { - struct libname_list *lnp = l->l_libname->next; - - l->l_libname->next = NULL; - - while (lnp != NULL) - { - struct libname_list *old = lnp; - lnp = lnp->next; - if (! old->dont_free) + for (Lmid_t ns = 0; ns < DL_NNS; ++ns) + for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next) + { + struct libname_list *lnp = l->l_libname->next; + + l->l_libname->next = NULL; + + while (lnp != NULL) + { + struct libname_list *old = lnp; + lnp = lnp->next; + if (! old->dont_free) free (old); - } - } + } + } } --- libc/elf/dl-iteratephdr.c 2004/01/27 21:29:22 1.11 +++ libc/elf/dl-iteratephdr.c 2004/10/14 02:02:06 1.12 @@ -42,14 +42,32 @@ __rtld_lock_lock_recursive (GL(dl_load_lock)); __libc_cleanup_push (cancel_handler, 0); - for (l = GL(dl_loaded); l != NULL; l = l->l_next) + /* We have to determine the namespace of the caller since this determines + which namespace is reported. */ + const void *caller = RETURN_ADDRESS (0); + size_t nloaded = GL(dl_ns)[0]._ns_nloaded; + Lmid_t ns = 0; + for (Lmid_t cnt = DL_NNS - 1; cnt > 0; --cnt) + for (struct link_map *l = GL(dl_ns)[cnt]._ns_loaded; l; l = l->l_next) + { + /* We have to count the total number of loaded objects. */ + nloaded += GL(dl_ns)[cnt]._ns_nloaded; + + if (caller >= (const void *) l->l_map_start + && caller < (const void *) l->l_map_end) + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + ns = cnt; + } + + for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next) { info.dlpi_addr = l->l_addr; info.dlpi_name = l->l_name; info.dlpi_phdr = l->l_phdr; info.dlpi_phnum = l->l_phnum; info.dlpi_adds = GL(dl_load_adds); - info.dlpi_subs = GL(dl_load_adds) - GL(dl_nloaded); + info.dlpi_subs = GL(dl_load_adds) - nloaded; ret = callback (&info, sizeof (struct dl_phdr_info), data); if (ret) break; @@ -87,7 +105,7 @@ info.dlpi_phdr = _dl_phdr; info.dlpi_phnum = _dl_phnum; info.dlpi_adds = GL(dl_load_adds); - info.dlpi_subs = GL(dl_load_adds) - GL(dl_nloaded); + info.dlpi_subs = GL(dl_load_adds) - GL(dl_ns)[LM_ID_BASE]._ns_nloaded; ret = (*callback) (&info, sizeof (struct dl_phdr_info), data); if (ret) return ret; --- libc/elf/dl-fini.c 2004/07/08 00:52:17 1.35 +++ libc/elf/dl-fini.c 2004/10/14 02:01:39 1.36 @@ -32,10 +32,10 @@ _dl_fini (void) { /* Lots of fun ahead. We have to call the destructors for all still - loaded objects. The problem is that the ELF specification now - demands that dependencies between the modules are taken into account. - I.e., the destructor for a module is called before the ones for any - of its dependencies. + loaded objects, in all namespaces. The problem is that the ELF + specification now demands that dependencies between the modules + are taken into account. I.e., the destructor for a module is + called before the ones for any of its dependencies. To make things more complicated, we cannot simply use the reverse order of the constructors. Since the user might have loaded objects @@ -45,140 +45,179 @@ unsigned int i; unsigned int nloaded; struct link_map *l; - struct link_map **maps; + struct link_map **maps = NULL; + size_t maps_size = 0; - /* Protect against concurrent loads and unloads. */ - __rtld_lock_lock_recursive (GL(dl_load_lock)); - - nloaded = GL(dl_nloaded); - - /* XXX Could it be (in static binaries) that there is no object loaded? */ - assert (nloaded > 0); - - /* Now we can allocate an array to hold all the pointers and copy - the pointers in. */ - maps = (struct link_map **) alloca (nloaded * sizeof (struct link_map *)); - for (l = GL(dl_loaded), i = 0; l != NULL; l = l->l_next) + /* We First run the destructors of the main namespaces, then the + other ones. The order should not matter since the namespace + content is supposed to be independent. But we can have auditing + code in a auxiliaty namespace and we want it to monitor the + destructors. */ + for (Lmid_t cnt = 0; cnt < DL_NNS; ++cnt) { - assert (i < nloaded); + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); - maps[i++] = l; + nloaded = GL(dl_ns)[cnt]._ns_nloaded; - /* Bump l_opencount of all objects so that they are not dlclose()ed - from underneath us. */ - ++l->l_opencount; - } - assert (i == nloaded); - - /* Now we have to do the sorting. */ - for (l = GL(dl_loaded)->l_next; l != NULL; l = l->l_next) - { - unsigned int j; - unsigned int k; + /* XXX Could it be (in static binaries) that there is no object + loaded? */ + assert (cnt != LM_ID_BASE || nloaded > 0); + + /* Now we can allocate an array to hold all the pointers and copy + the pointers in. */ + if (maps_size < nloaded * sizeof (struct link_map *)) + { + if (maps_size == 0) + { + maps_size = nloaded * sizeof (struct link_map *); + maps = (struct link_map **) alloca (maps_size); + } + else + maps = (struct link_map **) + extend_alloca (maps, maps_size, + nloaded * sizeof (struct link_map *)); + } - /* Find the place in the 'maps' array. */ - for (j = 1; maps[j] != l; ++j) - ; - - /* Find all object for which the current one is a dependency and - move the found object (if necessary) in front. */ - for (k = j + 1; k < nloaded; ++k) + for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next) { - struct link_map **runp = maps[k]->l_initfini; - if (runp != NULL) + assert (i < nloaded); + + /* Do not handle ld.so in secondary namespaces. */ + if (l == l->l_real) { - while (*runp != NULL) - if (*runp == l) - { - struct link_map *here = maps[k]; - - /* Move it now. */ - memmove (&maps[j] + 1, - &maps[j], - (k - j) * sizeof (struct link_map *)); - maps[j++] = here; - - break; - } - else - ++runp; + maps[i++] = l; + + /* Bump l_opencount of all objects so that they are not + dlclose()ed from underneath us. */ + ++l->l_opencount; } + } + assert (cnt != LM_ID_BASE || i == nloaded); + assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1); + unsigned int nmaps = i; - if (__builtin_expect (maps[k]->l_reldeps != NULL, 0)) + if (nmaps != 0) + { + /* Now we have to do the sorting. */ + l = GL(dl_ns)[cnt]._ns_loaded; + if (cnt == LM_ID_BASE) + /* The main executable always comes first. */ + l = l->l_next; + for (; l != NULL; l = l->l_next) { - unsigned int m = maps[k]->l_reldepsact; - struct link_map **relmaps = maps[k]->l_reldeps; + unsigned int j; + unsigned int k; - while (m-- > 0) + /* Find the place in the 'maps' array. */ + for (j = 1; maps[j] != l; ++j) + ; + + /* Find all object for which the current one is a dependency and + move the found object (if necessary) in front. */ + for (k = j + 1; k < nmaps; ++k) { - if (relmaps[m] == l) + struct link_map **runp = maps[k]->l_initfini; + if (runp != NULL) { - struct link_map *here = maps[k]; + while (*runp != NULL) + if (*runp == l) + { + struct link_map *here = maps[k]; + + /* Move it now. */ + memmove (&maps[j] + 1, + &maps[j], + (k - j) * sizeof (struct link_map *)); + maps[j++] = here; + + break; + } + else + ++runp; + } - /* Move it now. */ - memmove (&maps[j] + 1, - &maps[j], - (k - j) * sizeof (struct link_map *)); - maps[j] = here; + if (__builtin_expect (maps[k]->l_reldeps != NULL, 0)) + { + unsigned int m = maps[k]->l_reldepsact; + struct link_map **relmaps = maps[k]->l_reldeps; - break; + while (m-- > 0) + { + if (relmaps[m] == l) + { + struct link_map *here = maps[k]; + + /* Move it now. */ + memmove (&maps[j] + 1, + &maps[j], + (k - j) * sizeof (struct link_map *)); + maps[j] = here; + + break; + } + } } } } } - } - /* We do not rely on the linked list of loaded object anymore from - this point on. We have our own list here (maps). The various - members of this list cannot vanish since the open count is too - high and will be decremented in this loop. So we release the - lock so that some code which might be called from a destructor - can directly or indirectly access the lock. */ - __rtld_lock_unlock_recursive (GL(dl_load_lock)); - - /* 'maps' now contains the objects in the right order. Now call the - destructors. We have to process this array from the front. */ - for (i = 0; i < nloaded; ++i) - { - l = maps[i]; - - if (l->l_init_called) + /* We do not rely on the linked list of loaded object anymore from + this point on. We have our own list here (maps). The various + members of this list cannot vanish since the open count is too + high and will be decremented in this loop. So we release the + lock so that some code which might be called from a destructor + can directly or indirectly access the lock. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + /* 'maps' now contains the objects in the right order. Now call the + destructors. We have to process this array from the front. */ + for (i = 0; i < nmaps; ++i) { - /* Make sure nothing happens if we are called twice. */ - l->l_init_called = 0; - - /* Don't call the destructors for objects we are not supposed to. */ - if (l->l_name[0] == '\0' && l->l_type == lt_executable) - continue; - - /* Is there a destructor function? */ - if (l->l_info[DT_FINI_ARRAY] == NULL && l->l_info[DT_FINI] == NULL) - continue; - - /* When debugging print a message first. */ - if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) - _dl_debug_printf ("\ncalling fini: %s\n\n", - l->l_name[0] ? l->l_name : rtld_progname); + l = maps[i]; - /* First see whether an array is given. */ - if (l->l_info[DT_FINI_ARRAY] != NULL) + if (l->l_init_called) { - ElfW(Addr) *array = - (ElfW(Addr) *) (l->l_addr - + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); - unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val - / sizeof (ElfW(Addr))); - while (i-- > 0) - ((fini_t) array[i]) (); + /* Make sure nothing happens if we are called twice. */ + l->l_init_called = 0; + + /* Don't call the destructors for objects we are not + supposed to. */ + if (l->l_name[0] == '\0' && l->l_type == lt_executable) + continue; + + /* Is there a destructor function? */ + if (l->l_info[DT_FINI_ARRAY] == NULL + && l->l_info[DT_FINI] == NULL) + continue; + + /* When debugging print a message first. */ + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, + 0)) + _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", + l->l_name[0] ? l->l_name : rtld_progname, + cnt); + + /* First see whether an array is given. */ + if (l->l_info[DT_FINI_ARRAY] != NULL) + { + ElfW(Addr) *array = + (ElfW(Addr) *) (l->l_addr + + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); + unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + while (i-- > 0) + ((fini_t) array[i]) (); + } + + /* Next try the old-style destructor. */ + if (l->l_info[DT_FINI] != NULL) + ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); } - /* Next try the old-style destructor. */ - if (l->l_info[DT_FINI] != NULL) - ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); + /* Correct the previous increment. */ + --l->l_opencount; } - - /* Correct the previous increment. */ - --l->l_opencount; } if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0)) --- libc/elf/dl-deps.c 2004/09/23 07:42:29 1.76 +++ libc/elf/dl-deps.c 2004/10/14 02:01:14 1.77 @@ -63,7 +63,8 @@ args->aux = _dl_map_object (args->map, args->name, 0, (args->map->l_type == lt_executable ? lt_library : args->map->l_type), - args->trace_mode, args->open_mode); + args->trace_mode, args->open_mode, + args->map->l_ns); } static ptrdiff_t @@ -510,7 +511,7 @@ } if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0 - && map == GL(dl_loaded)) + && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded) { /* If we are to compute conflicts, we have to build local scope for each library, not just the ultimate loader. */ --- libc/elf/dl-close.c 2004/10/13 19:27:16 1.105 +++ libc/elf/dl-close.c 2004/10/14 02:00:27 1.106 @@ -130,6 +130,10 @@ /* Acquire the lock. */ __rtld_lock_lock_recursive (GL(dl_load_lock)); + /* One less direct use. */ + assert (map->l_direct_opencount > 0); + --map->l_direct_opencount; + /* Decrement the reference count. */ if (map->l_opencount > 1 || map->l_type != lt_loaded) { @@ -141,6 +145,12 @@ /* Decrement the object's reference counter, not the dependencies'. */ --map->l_opencount; + /* If the direct use counter reaches zero we have to decrement + all the dependencies' usage counter. */ + if (map->l_direct_opencount == 0) + for (i = 1; i < map->l_searchlist.r_nlist; ++i) + --map->l_searchlist.r_list[i]->l_opencount; + __rtld_lock_unlock_recursive (GL(dl_load_lock)); return; } @@ -167,12 +177,13 @@ for (i = 1; list[i] != NULL; ++i) if ((list[i]->l_flags_1 & DF_1_NODELETE) == 0 /* Decrement counter. */ - && --new_opencount[i] == 0) + && (assert (new_opencount[i] > 0), --new_opencount[i] == 0)) { void mark_removed (struct link_map *remmap) { /* Test whether this object was also loaded directly. */ - if (remmap->l_searchlist.r_list != NULL) + if (remmap->l_searchlist.r_list != NULL + && remmap->l_direct_opencount > 0) { /* In this case we have to decrement all the dependencies of this object. They are all in MAP's dependency list. */ @@ -184,6 +195,7 @@ || ! dep_list[j]->l_init_called) { assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist); + assert (new_opencount[dep_list[j]->l_idx] > 0); if (--new_opencount[dep_list[j]->l_idx] == 0) { assert (dep_list[j]->l_type == lt_loaded); @@ -197,17 +209,53 @@ unsigned int j; for (j = 0; j < remmap->l_reldepsact; ++j) { + struct link_map *depmap = remmap->l_reldeps[j]; + /* Find out whether this object is in our list. */ - if (remmap->l_reldeps[j]->l_idx < nopencount - && (list[remmap->l_reldeps[j]->l_idx] - == remmap->l_reldeps[j])) - /* Yes, it is. */ - if (--new_opencount[remmap->l_reldeps[j]->l_idx] == 0) - { - /* This one is now gone, too. */ - assert (remmap->l_reldeps[j]->l_type == lt_loaded); - mark_removed (remmap->l_reldeps[j]); - } + if (depmap->l_idx < nopencount + && list[depmap->l_idx] == depmap) + { + /* Yes, it is. If is has a search list, make a + recursive call to handle this. */ + if (depmap->l_searchlist.r_list != NULL) + { + assert (new_opencount[depmap->l_idx] > 0); + if (--new_opencount[depmap->l_idx] == 0) + { + /* This one is now gone, too. */ + assert (depmap->l_type == lt_loaded); + mark_removed (depmap); + } + } + else + { + /* Otherwise we have to handle the dependency + deallocation here. */ + unsigned int k; + for (k = 0; depmap->l_initfini[k] != NULL; ++k) + { + struct link_map *rl = depmap->l_initfini[k]; + + if (rl->l_idx < nopencount + & list[rl->l_idx] == rl) + { + assert (new_opencount[rl->l_idx] > 0); + if (--new_opencount[rl->l_idx] == 0) + { + /* Another module to remove. */ + assert (rl->l_type == lt_loaded); + mark_removed (rl); + } + } + else + { + assert (rl->l_opencount > 0); + if (--rl->l_opencount == 0) + mark_removed (rl); + } + } + } + } } } } @@ -225,7 +273,8 @@ { /* When debugging print a message first. */ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) - GLRO(dl_debug_printf) ("\ncalling fini: %s\n\n", imap->l_name); + GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n", + imap->l_name, imap->l_ns); /* Call its termination function. Do not do it for half-cooked objects. */ @@ -340,18 +389,21 @@ if (__builtin_expect (imap->l_global, 0)) { /* This object is in the global scope list. Remove it. */ - unsigned int cnt = GL(dl_main_searchlist)->r_nlist; + unsigned int cnt + = GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist; do --cnt; - while (GL(dl_main_searchlist)->r_list[cnt] != imap); + while (GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt] + != imap); /* The object was already correctly registered. */ - while (++cnt < GL(dl_main_searchlist)->r_nlist) - GL(dl_main_searchlist)->r_list[cnt - 1] - = GL(dl_main_searchlist)->r_list[cnt]; + while (++cnt + < GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist) + GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt - 1] + = GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt]; - --GL(dl_main_searchlist)->r_nlist; + --GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist; } #ifdef USE_TLS @@ -442,19 +494,18 @@ DL_UNMAP (imap); /* Finally, unlink the data structure and free it. */ -#ifdef SHARED - /* We will unlink the first object only if this is a statically - linked program. */ - assert (imap->l_prev != NULL); - imap->l_prev->l_next = imap->l_next; -#else if (imap->l_prev != NULL) imap->l_prev->l_next = imap->l_next; else - GL(dl_loaded) = imap->l_next; + { +#ifdef SHARED + assert (imap->l_ns != LM_ID_BASE); #endif - --GL(dl_nloaded); - if (imap->l_next) + GL(dl_ns)[imap->l_ns]._ns_loaded = imap->l_next; + } + + --GL(dl_ns)[imap->l_ns]._ns_nloaded; + if (imap->l_next != NULL) imap->l_next->l_prev = imap->l_prev; free (imap->l_versions); @@ -528,7 +579,7 @@ if (any_tls) { if (__builtin_expect (++GL(dl_tls_generation) == 0, 0)) - __libc_fatal (_("TLS generation counter wrapped! Please send report as described in .")); + __libc_fatal (_("TLS generation counter wrapped! Please report as described in .")); if (tls_free_end == GL(dl_tls_static_used)) GL(dl_tls_static_used) = tls_free_start; @@ -596,22 +647,26 @@ libc_freeres_fn (free_mem) { - if (__builtin_expect (GL(dl_global_scope_alloc), 0) != 0 - && (GL(dl_main_searchlist)->r_nlist - == GLRO(dl_initial_searchlist).r_nlist)) - { - /* All object dynamically loaded by the program are unloaded. Free - the memory allocated for the global scope variable. */ - struct link_map **old = GL(dl_main_searchlist)->r_list; - - /* Put the old map in. */ - GL(dl_main_searchlist)->r_list = GLRO(dl_initial_searchlist).r_list; - /* Signal that the original map is used. */ - GL(dl_global_scope_alloc) = 0; + for (Lmid_t ns = 0; ns < DL_NNS; ++ns) + if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0 + && (GL(dl_ns)[ns]._ns_main_searchlist->r_nlist + // XXX Check whether we need NS-specific initial_searchlist + == GLRO(dl_initial_searchlist).r_nlist)) + { + /* All object dynamically loaded by the program are unloaded. Free + the memory allocated for the global scope variable. */ + struct link_map **old = GL(dl_ns)[ns]._ns_main_searchlist->r_list; + + /* Put the old map in. */ + GL(dl_ns)[ns]._ns_main_searchlist->r_list + // XXX Check whether we need NS-specific initial_searchlist + = GLRO(dl_initial_searchlist).r_list; + /* Signal that the original map is used. */ + GL(dl_ns)[ns]._ns_global_scope_alloc = 0; - /* Now free the old map. */ - free (old); - } + /* Now free the old map. */ + free (old); + } #ifdef USE_TLS if (USE___THREAD || GL(dl_tls_dtv_slotinfo_list) != NULL) --- libc/elf/Makefile 2004/09/23 07:44:59 1.285 +++ libc/elf/Makefile 2004/10/14 01:59:45 1.286 @@ -154,7 +154,7 @@ circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \ $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \ - tst-dlopenrpath tst-deep1 + tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 # reldep9 test-srcs = tst-pathopt tests-vis-yes = vismain @@ -187,7 +187,8 @@ reldep8mod1 reldep8mod2 reldep8mod3 \ reldep9mod1 reldep9mod2 reldep9mod3 \ tst-alignmod $(modules-execstack-$(have-z-execstack)) \ - tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 + tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \ + tst-dlmopen1mod ifeq (yes,$(have-initfini-array)) modules-names += tst-array2dep endif @@ -762,3 +763,10 @@ $(objpfx)tst-deep1.out: $(objpfx)tst-deep1mod2.so LDFLAGS-tst-deep1 += -rdynamic tst-deep1mod3.so-no-z-defs = yes + +$(objpfx)tst-dlmopen1mod.so: $(libdl) +$(objpfx)tst-dlmopen1: $(libdl) +$(objpfx)tst-dlmopen1.out: $(objpfx)tst-dlmopen1mod.so + +$(objpfx)tst-dlmopen2: $(libdl) +$(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so --- libc/elf/tst-dlmopen2.c +++ libc/elf/tst-dlmopen2.c 2004-11-30 17:40:10.937455000 +0000 @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include + + +static int +do_test (void) +{ + int result = 0; + + for (int i = 1; i <= 10; ++i) + { + void *h[DL_NNS - 1]; + char used[DL_NNS]; + + printf ("round %d\n", i); + + memset (used, '\0', sizeof (used)); + used[LM_ID_BASE] = 1; + + for (int j = 0; j < DL_NNS - 1; ++j) + { + h[j] = dlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so", + RTLD_LAZY); + if (h[j] == NULL) + { + printf ("round %d, namespace %d: load failed: %s\n", + i, j, dlerror ()); + return 1; + } + Lmid_t ns; + if (dlinfo (h[j], RTLD_DI_LMID, &ns) != 0) + { + printf ("round %d, namespace %d: dlinfo failed: %s\n", + i, j, dlerror ()); + return 1; + } + if (ns < 0 || ns >= DL_NNS) + { + printf ("round %d, namespace %d: invalid namespace %ld", + i, j, (long int) ns); + result = 1; + } + else if (used[ns] != 0) + { + printf ("\ +round %d, namespace %d: duplicate allocate of namespace %ld", + i, j, (long int) ns); + result = 1; + } + else + used[ns] = 1; + } + + for (int j = 0; j < DL_NNS - 1; ++j) + if (dlclose (h[j]) != 0) + { + printf ("round %d, namespace %d: close failed: %s\n", + i, j, dlerror ()); + return 1; + } + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- libc/elf/tst-dlmopen1mod.c +++ libc/elf/tst-dlmopen1mod.c 2004-11-30 17:41:04.643439000 +0000 @@ -0,0 +1,38 @@ +#include +#include +#include + + +int +foo (Lmid_t ns2) +{ + void *h = dlopen (LIBC_SO, RTLD_LAZY|RTLD_NOLOAD); + if (h == NULL) + { + printf ("cannot get handle for %s: %s\n", LIBC_SO, dlerror ()); + return 1; + } + + Lmid_t ns = -10; + if (dlinfo (h, RTLD_DI_LMID, &ns) != 0) + { + printf ("dlinfo for %s in %s failed: %s\n", + LIBC_SO, __func__, dlerror ()); + return 1; + } + + if (ns != ns2) + { + printf ("namespace for %s not LM_ID_BASE\n", LIBC_SO); + return 1; + } + + if (dlclose (h) != 0) + { + printf ("dlclose for %s in %s failed: %s\n", + LIBC_SO, __func__, dlerror ()); + return 1; + } + + return 0; +} --- libc/elf/tst-dlmopen1.c +++ libc/elf/tst-dlmopen1.c 2004-11-30 17:41:30.989715000 +0000 @@ -0,0 +1,80 @@ +#include +#include +#include + + +static int +do_test (void) +{ + void *h = dlopen (LIBC_SO, RTLD_LAZY|RTLD_NOLOAD); + if (h == NULL) + { + printf ("cannot get handle for %s: %s\n", LIBC_SO, dlerror ()); + return 1; + } + + Lmid_t ns = -10; + if (dlinfo (h, RTLD_DI_LMID, &ns) != 0) + { + printf ("dlinfo for %s in %s failed: %s\n", + LIBC_SO, __func__, dlerror ()); + return 1; + } + + if (ns != LM_ID_BASE) + { + printf ("namespace for %s not LM_ID_BASE\n", LIBC_SO); + return 1; + } + + if (dlclose (h) != 0) + { + printf ("dlclose for %s in %s failed: %s\n", + LIBC_SO, __func__, dlerror ()); + return 1; + } + + h = dlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot get handle for %s: %s\n", + "tst-dlmopen1mod.so", dlerror ()); + return 1; + } + + ns = -10; + if (dlinfo (h, RTLD_DI_LMID, &ns) != 0) + { + printf ("dlinfo for %s in %s failed: %s\n", + "tst-dlmopen1mod.so", __func__, dlerror ()); + return 1; + } + + if (ns == LM_ID_BASE) + { + printf ("namespace for %s is LM_ID_BASE\n", LIBC_SO); + return 1; + } + + int (*fct) (Lmid_t) = dlsym (h, "foo"); + if (fct == NULL) + { + printf ("could not find %s: %s\n", "foo", dlerror ()); + return 1; + } + + if (fct (ns) != 0) + return 1; + + if (dlclose (h) != 0) + { + printf ("dlclose for %s in %s failed: %s\n", + LIBC_SO, __func__, dlerror ()); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" --- libc/include/link.h 2004/09/18 06:42:31 1.32 +++ libc/include/link.h 2004/10/14 01:57:54 1.33 @@ -129,6 +129,14 @@ /* All following members are internal to the dynamic linker. They may change without notice. */ + /* This is an element which is only ever different from a pointer to + the very same copy of this type for ld.so when it is used in more + than one namespace. */ + struct link_map *l_real; + + /* Number of the namespace this link map belongs to. */ + Lmid_t l_ns; + struct libname_list *l_libname; /* Indexed pointers to dynamic section. [0,DT_NUM) are indexed by the processor-independent tags. @@ -169,7 +177,8 @@ Elf_Symndx l_nbuckets; const Elf_Symndx *l_buckets, *l_chain; - unsigned int l_opencount; /* Reference count for dlopen/dlclose. */ + unsigned int l_opencount; /* Counter for direct and indirect usage. */ + unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose. */ enum /* Where this object came from. */ { lt_executable, /* The main executable program. */ --- libc/include/dlfcn.h 2004/08/09 06:38:03 1.17 +++ libc/include/dlfcn.h 2004/10/14 01:57:25 1.18 @@ -8,6 +8,8 @@ #define __RTLD_OPENEXEC 0x20000000 #define __RTLD_CALLMAP 0x10000000 +#define __LM_ID_CALLER -2 + /* Now define the internal interfaces. */ extern void *__dlvsym (void *__handle, __const char *__name, __const char *__version); @@ -31,7 +33,8 @@ /* Open the shared object NAME, relocate it, and run its initializer if it hasn't already been run. MODE is as for `dlopen' (see ). If the object is already opened, returns its existing map. */ -extern void *_dl_open (const char *name, int mode, const void *caller) +extern void *_dl_open (const char *name, int mode, const void *caller, + Lmid_t nsid) internal_function; libc_hidden_proto (_dl_open) --- libc/malloc/malloc.c 2004/10/06 18:01:28 1.130 +++ libc/malloc/malloc.c 2004/10/14 01:56:52 1.131 @@ -24,7 +24,7 @@ Doug Lea and adapted to multiple threads/arenas by Wolfram Gloger. * Version ptmalloc2-20011215 - $Id: malloc.c,v 1.130 2004/10/06 18:01:28 drepper Exp $ + $Id: malloc.c,v 1.131 2004/10/14 01:56:52 drepper Exp $ based on: VERSION 2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) @@ -289,9 +289,13 @@ /* For writev and struct iovec. */ #include - /* For syslog. */ +/* For syslog. */ #include +/* For various dynamic linking things. */ +#include + + /* Debugging: --- libc/malloc/arena.c 2004/10/04 02:27:14 1.10 +++ libc/malloc/arena.c 2004/10/14 01:55:55 1.11 @@ -18,7 +18,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: arena.c,v 1.10 2004/10/04 02:27:14 drepper Exp $ */ +/* $Id: arena.c,v 1.11 2004/10/14 01:55:55 drepper Exp $ */ /* Compile-time constants. */ @@ -339,7 +339,16 @@ mp_.pagesize = malloc_getpagesize; } + #ifdef _LIBC +# ifdef SHARED +static void * +__failing_morecore (ptrdiff_t d) +{ + return (void *) MORECORE_FAILURE; +} +# endif + # if defined SHARED && defined USE_TLS && !USE___THREAD # include @@ -419,6 +428,14 @@ mutex_init(&main_arena.mutex); main_arena.next = &main_arena; +#if defined _LIBC && defined SHARED + /* In case this libc copy is in a non-default namespace, never use brk. */ + Dl_info di; + struct link_map *l; + if (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0 && l->l_ns != LM_ID_BASE) + __morecore = __failing_morecore; +#endif + mutex_init(&list_lock); tsd_key_create(&arena_key, NULL); tsd_setspecific(arena_key, (Void_t *)&main_arena); --- libc/sysdeps/generic/dl-tls.c 2004/03/06 08:12:40 1.42 +++ libc/sysdeps/generic/dl-tls.c 2004/10/14 01:55:20 1.43 @@ -33,7 +33,7 @@ /* Amount of excess space to allocate in the static TLS area to allow dynamic loading of modules defining IE-model TLS data. */ -# define TLS_STATIC_SURPLUS 64 +# define TLS_STATIC_SURPLUS 64 + DL_NNS * 100 /* Value used for dtv entries for which the allocation is delayed. */ # define TLS_DTV_UNALLOCATED ((void *) -1l) --- libc/sysdeps/generic/ldsodefs.h 2004/09/23 07:37:38 1.103 +++ libc/sysdeps/generic/ldsodefs.h 2004/10/14 01:54:41 1.104 @@ -216,18 +216,27 @@ /* Don't change the order of the following elements. 'dl_loaded' must remain the first element. Forever. */ - /* And a pointer to the map for the main map. */ - EXTERN struct link_map *_dl_loaded; - /* Number of object in the _dl_loaded list. */ - EXTERN unsigned int _dl_nloaded; - /* Array representing global scope. */ - EXTERN struct r_scope_elem *_dl_global_scope[2]; - /* Direct pointer to the searchlist of the main object. */ - EXTERN struct r_scope_elem *_dl_main_searchlist; - /* This is zero at program start to signal that the global scope map is - allocated by rtld. Later it keeps the size of the map. It might be - reset if in _dl_close if the last global object is removed. */ - EXTERN size_t _dl_global_scope_alloc; +/* Non-shared code has no support for multiple namespaces. */ +#ifdef SHARED +# define DL_NNS 16 +#else +# define DL_NNS 1 +#endif + EXTERN struct link_namespaces + { + /* And a pointer to the map for the main map. */ + struct link_map *_ns_loaded; + /* Number of object in the _dl_loaded list. */ + unsigned int _ns_nloaded; + /* Array representing global scope. */ + struct r_scope_elem *_ns_global_scope[2]; + /* Direct pointer to the searchlist of the main object. */ + struct r_scope_elem *_ns_main_searchlist; + /* This is zero at program start to signal that the global scope map is + allocated by rtld. Later it keeps the size of the map. It might be + reset if in _dl_close if the last global object is removed. */ + size_t _ns_global_scope_alloc; + } _dl_ns[DL_NNS]; /* During the program run we must not modify the global data of loaded shared object simultanously in two threads. Therefore we @@ -477,7 +486,7 @@ char *(*_dl_dst_substitute) (struct link_map *, const char *, char *, int); struct link_map *(internal_function *_dl_map_object) (struct link_map *, const char *, int, - int, int, int); + int, int, int, Lmid_t); void (internal_function *_dl_map_object_deps) (struct link_map *, struct link_map **, unsigned int, int, int); @@ -658,7 +667,8 @@ value to allow additional security checks. */ extern struct link_map *_dl_map_object (struct link_map *loader, const char *name, int preloaded, - int type, int trace_mode, int mode) + int type, int trace_mode, int mode, + Lmid_t nsid) internal_function attribute_hidden; /* Call _dl_map_object on the dependencies of MAP, and set up @@ -723,7 +733,7 @@ and enter it into the _dl_main_map list. */ extern struct link_map *_dl_new_object (char *realname, const char *libname, int type, struct link_map *loader, - int mode) + int mode, Lmid_t nsid) internal_function attribute_hidden; /* Relocate the given object (if it hasn't already been). --- libc/sysdeps/unix/sysv/linux/i386/dl-librecon.h 2004/03/05 10:14:47 1.14 +++ libc/sysdeps/unix/sysv/linux/i386/dl-librecon.h 2004/10/14 01:53:55 1.15 @@ -28,15 +28,15 @@ /* We have to find out whether the binary is linked against \ libc 5 or glibc. We do this by looking at all the DT_NEEDED \ entries. If one is libc.so.5 this is a libc 5 linked binary. */ \ - if (GL(dl_loaded)->l_info[DT_NEEDED]) \ + if (main_map->l_info[DT_NEEDED]) \ { \ /* We have dependencies. */ \ const ElfW(Dyn) *d; \ const char *strtab; \ \ - strtab = (const char *) D_PTR (GL(dl_loaded), l_info[DT_STRTAB]); \ + strtab = (const char *) D_PTR (main_map, l_info[DT_STRTAB]); \ \ - for (d = GL(dl_loaded)->l_ld; d->d_tag != DT_NULL; ++d) \ + for (d = main_map->l_ld; d->d_tag != DT_NULL; ++d) \ if (d->d_tag == DT_NEEDED \ && strcmp (strtab + d->d_un.d_val, "libc.so.5") == 0) \ break; \ --- libc/elf/dl-version.c 2004/03/06 08:12:41 1.38 +++ libc/elf/dl-version.c 2004/10/14 01:53:55 1.39 @@ -59,7 +59,8 @@ struct link_map *tmap; unsigned int n; - for (tmap = GL(dl_loaded); tmap != NULL; tmap = tmap->l_next) + for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL; + tmap = tmap->l_next) if (_dl_name_match_p (name, tmap)) return tmap; @@ -243,7 +244,7 @@ ? map->l_name : rtld_progname), aux->vna_hash, strtab + aux->vna_name, - needed, verbose, + needed->l_real, verbose, aux->vna_flags & VER_FLG_WEAK); /* Compare the version index. */ --- libc/elf/dl-sym.c 2004/10/11 07:10:47 1.23 +++ libc/elf/dl-sym.c 2004/10/14 01:53:55 1.24 @@ -69,17 +69,19 @@ /* If the address is not recognized the call comes from the main program (we hope). */ - struct link_map *match = GL(dl_loaded); + struct link_map *match = GL(dl_ns)[LM_ID_BASE]._ns_loaded; /* Find the highest-addressed object that CALLER is not below. */ - for (struct link_map *l = GL(dl_loaded); l != NULL; l = l->l_next) - if (caller >= l->l_map_start && caller < l->l_map_end) - { - /* There must be exactly one DSO for the range of the virtual - memory. Otherwise something is really broken. */ - match = l; - break; - } + for (Lmid_t ns = 0; ns < DL_NNS; ++ns) + for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL; + l = l->l_next) + if (caller >= l->l_map_start && caller < l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + match = l; + break; + } if (handle == RTLD_DEFAULT) /* Search the global scope. */ @@ -88,7 +90,7 @@ NULL); else if (handle == RTLD_NEXT) { - if (__builtin_expect (match == GL(dl_loaded), 0)) + if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0)) { if (match == NULL || caller < match->l_map_start --- libc/elf/dl-debug.c 2004/03/06 08:12:41 1.11 +++ libc/elf/dl-debug.c 2004/10/14 01:53:55 1.12 @@ -39,7 +39,9 @@ /* Tell the debugger where to find the map of loaded objects. */ _r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */; _r_debug.r_ldbase = ldbase; - _r_debug.r_map = GL(dl_loaded); + // XXX This is problematic. It means we cannot tell the debugger + // XXX about namespaces other than the main one. + _r_debug.r_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; _r_debug.r_brk = (ElfW(Addr)) &_dl_debug_state; } --- libc/elf/dl-conflict.c 2004/03/05 10:14:50 1.11 +++ libc/elf/dl-conflict.c 2004/10/14 01:53:55 1.12 @@ -54,8 +54,10 @@ (map) = resolve_conflict_map; \ } while (0) + /* Prelinking makes no sense for anything but the main namespace. */ + assert (l->l_ns == LM_ID_BASE); struct link_map *resolve_conflict_map __attribute__ ((__unused__)) - = GL(dl_loaded); + = GL(dl_ns)[LM_ID_BASE]._ns_loaded; #include "dynamic-link.h" --- libc/elf/dl-caller.c 2004/03/27 03:14:19 1.1 +++ libc/elf/dl-caller.c 2004/10/14 01:53:55 1.2 @@ -35,44 +35,46 @@ #endif static const char expected4[] = LD_SO; - for (struct link_map *l = GL(dl_loaded); l != NULL; l = l->l_next) - if (caller >= (const void *) l->l_map_start - && caller < (const void *) l->l_text_end) - { - /* The address falls into this DSO's address range. Check the - name. */ - if ((mask & allow_libc) && strcmp (expected1, l->l_name) == 0) - return 0; - if ((mask & allow_libdl) && strcmp (expected2, l->l_name) == 0) - return 0; + for (Lmid_t ns = 0; ns < DL_NNS; ++ns) + for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL; + l = l->l_next) + if (caller >= (const void *) l->l_map_start + && caller < (const void *) l->l_text_end) + { + /* The address falls into this DSO's address range. Check the + name. */ + if ((mask & allow_libc) && strcmp (expected1, l->l_name) == 0) + return 0; + if ((mask & allow_libdl) && strcmp (expected2, l->l_name) == 0) + return 0; #ifdef LIBPTHREAD_SO - if ((mask & allow_libpthread) && strcmp (expected3, l->l_name) == 0) - return 0; + if ((mask & allow_libpthread) && strcmp (expected3, l->l_name) == 0) + return 0; #endif - if ((mask & allow_ldso) && strcmp (expected4, l->l_name) == 0) - return 0; + if ((mask & allow_ldso) && strcmp (expected4, l->l_name) == 0) + return 0; - struct libname_list *runp = l->l_libname; + struct libname_list *runp = l->l_libname; - while (runp != NULL) - { - if ((mask & allow_libc) && strcmp (expected1, runp->name) == 0) - return 0; - if ((mask & allow_libdl) && strcmp (expected2, runp->name) == 0) - return 0; + while (runp != NULL) + { + if ((mask & allow_libc) && strcmp (expected1, runp->name) == 0) + return 0; + if ((mask & allow_libdl) && strcmp (expected2, runp->name) == 0) + return 0; #ifdef LIBPTHREAD_SO - if ((mask & allow_libpthread) - && strcmp (expected3, runp->name) == 0) - return 0; + if ((mask & allow_libpthread) + && strcmp (expected3, runp->name) == 0) + return 0; #endif - if ((mask & allow_ldso) && strcmp (expected4, runp->name) == 0) - return 0; + if ((mask & allow_ldso) && strcmp (expected4, runp->name) == 0) + return 0; - runp = runp->next; - } + runp = runp->next; + } - break; - } + break; + } /* Maybe the dynamic linker is not yet on the list. */ if ((mask & allow_ldso) != 0 --- libc/elf/dl-addr.c 2004/10/11 07:08:08 1.22 +++ libc/elf/dl-addr.c 2004/10/14 01:53:55 1.23 @@ -38,26 +38,27 @@ /* Find the highest-addressed object that ADDRESS is not below. */ match = NULL; - for (struct link_map *l = GL(dl_loaded); l; l = l->l_next) - if (addr >= l->l_map_start && addr < l->l_map_end) - { - /* We know ADDRESS lies within L if in any shared object. - Make sure it isn't past the end of L's segments. */ - size_t n = l->l_phnum; - if (n > 0) - { - do - --n; - while (l->l_phdr[n].p_type != PT_LOAD); - if (addr >= (l->l_addr + - l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz)) - /* Off the end of the highest-addressed shared object. */ - continue; - } - - match = l; - break; - } + for (Lmid_t ns = 0; ns < DL_NNS; ++ns) + for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l; l = l->l_next) + if (addr >= l->l_map_start && addr < l->l_map_end) + { + /* We know ADDRESS lies within L if in any shared object. + Make sure it isn't past the end of L's segments. */ + size_t n = l->l_phnum; + if (n > 0) + { + do + --n; + while (l->l_phdr[n].p_type != PT_LOAD); + if (addr >= (l->l_addr + + l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz)) + /* Off the end of the highest-addressed shared object. */ + continue; + } + + match = l; + break; + } int result = 0; if (match != NULL) --- libc/dlfcn/dlopenold.c 2001/07/06 04:54:45 1.7 +++ libc/dlfcn/dlopenold.c 2004/10/14 01:48:54 1.8 @@ -1,5 +1,5 @@ /* Load a shared object at run time. - Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -37,13 +37,21 @@ }; +/* Non-shared code has no support for multiple namespaces. */ +#ifdef SHARED +# define NS __LM_ID_CALLER +#else +# define NS LM_ID_BASE +#endif + + static void dlopen_doit (void *a) { struct dlopen_args *args = (struct dlopen_args *) a; args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN, - args->caller); + args->caller, args->file == NULL ? LM_ID_BASE : NS); } extern void *__dlopen_nocheck (const char *file, int mode); --- libc/dlfcn/dlopen.c 2003/09/19 20:40:11 1.8 +++ libc/dlfcn/dlopen.c 2004/10/14 01:48:54 1.9 @@ -1,5 +1,5 @@ /* Load a shared object at run time. - Copyright (C) 1995,96,97,98,99,2000,2003 Free Software Foundation, Inc. + Copyright (C) 1995,96,97,98,99,2000,2003,2004 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -31,13 +31,22 @@ const void *caller; }; + +/* Non-shared code has no support for multiple namespaces. */ +#ifdef SHARED +# define NS __LM_ID_CALLER +#else +# define NS LM_ID_BASE +#endif + + static void dlopen_doit (void *a) { struct dlopen_args *args = (struct dlopen_args *) a; args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN, - args->caller); + args->caller, args->file == NULL ? LM_ID_BASE : NS); } --- libc/dlfcn/dlinfo.c 2004/03/06 08:09:14 1.2 +++ libc/dlfcn/dlinfo.c 2004/10/14 01:48:22 1.3 @@ -55,12 +55,15 @@ switch (args->request) { - case RTLD_DI_LMID: case RTLD_DI_CONFIGADDR: default: GLRO(dl_signal_error) (0, NULL, NULL, N_("unsupported dlinfo request")); break; + case RTLD_DI_LMID: + *(Lmid_t *) args->arg = l->l_ns; + break; + case RTLD_DI_LINKMAP: *(struct link_map **) args->arg = l; break; --- libc/dlfcn/dlfcn.h 2003/07/15 06:48:45 1.13 +++ libc/dlfcn/dlfcn.h 2004/10/14 01:47:53 1.14 @@ -1,5 +1,5 @@ /* User functions for run-time dynamic loading. - Copyright (C) 1995-1999,2000,2001,2003 Free Software Foundation, Inc. + Copyright (C) 1995-1999,2000,2001,2003,2004 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -39,6 +39,14 @@ the run-time address of the symbol called NAME in the global scope is returned. */ # define RTLD_DEFAULT ((void *) 0) + + +/* Type for namespace indeces. */ +typedef long int Lmid_t; + +/* Special namespace ID values. */ +# define LM_ID_BASE 0 /* Initial namespace. */ +# define LM_ID_NEWLM -1 /* For dlmopen: request new namespace. */ #endif @@ -58,6 +66,9 @@ __const char *__restrict __name) __THROW; #ifdef __USE_GNU +/* Like `dlopen', but request object to be allocated in a new namespace. */ +extern void *dlmopen (Lmid_t __nsid, __const char *__file, int __mode) __THROW; + /* Find the run-time address in the shared object HANDLE refers to of the symbol called NAME with VERSION. */ extern void *dlvsym (void *__restrict __handle, @@ -114,6 +125,9 @@ /* These are the possible values for the REQUEST argument to `dlinfo'. */ enum { + /* Treat ARG as `lmid_t *'; store namespace ID for HANDLE there. */ + RTLD_DI_LMID = 1, + /* Treat ARG as `struct link_map **'; store the `struct link_map *' for HANDLE there. */ RTLD_DI_LINKMAP = 2, @@ -130,7 +144,6 @@ expand $ORIGIN in this shared object's dependency file names. */ RTLD_DI_ORIGIN = 6, - RTLD_DI_LMID = 1, /* Unsupported, defined by Solaris. */ RTLD_DI_CONFIGADDR = 3 /* Unsupported, defined by Solaris. */ }; --- libc/dlfcn/Versions 2003/03/15 23:14:44 1.3 +++ libc/dlfcn/Versions 2004/10/14 01:47:20 1.4 @@ -8,4 +8,7 @@ GLIBC_2.3.3 { dladdr1; dlinfo; } + GLIBC_2.3.4 { + dlmopen; + } } --- libc/dlfcn/Makefile 2004/08/21 09:25:46 1.32 +++ libc/dlfcn/Makefile 2004/10/14 01:46:57 1.33 @@ -19,7 +19,8 @@ subdir := dlfcn headers := bits/dlfcn.h dlfcn.h extra-libs := libdl -libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo +libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \ + dlmopen distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \ defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \ modcxaatexit.c modstatic.c \ --- libc/dlfcn/dlmopen.c +++ libc/dlfcn/dlmopen.c 2004-11-30 17:48:32.586386000 +0000 @@ -0,0 +1,69 @@ +/* Load a shared object at run time. + Copyright (C) 1995,96,97,98,99,2000,2003,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include + +struct dlmopen_args +{ + /* Namespace ID. */ + Lmid_t nsid; + /* The arguments for dlopen_doit. */ + const char *file; + int mode; + /* The return value of dlopen_doit. */ + void *new; + /* Address of the caller. */ + const void *caller; +}; + +static void +dlmopen_doit (void *a) +{ + struct dlmopen_args *args = (struct dlmopen_args *) a; + + /* Non-shared code has no support for multiple namespaces. */ + if (args->nsid != LM_ID_BASE) +#ifdef SHARED + /* If trying to open the link map for the main executable the namespace + must be the main one. */ + if (args->file == NULL) +#endif + GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace")); + + args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN, + args->caller, args->nsid); +} + + +void * +dlmopen (Lmid_t nsid, const char *file, int mode) +{ + struct dlmopen_args args; + args.nsid = nsid; + args.file = file; + args.mode = mode; + args.caller = RETURN_ADDRESS (0); + + return _dlerror_run (dlmopen_doit, &args) ? NULL : args.new; +} +static_link_warning (dlmopen)