diff options
author | Ulrich Drepper <drepper@redhat.com> | 2001-12-12 00:21:26 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2001-12-12 00:21:26 +0000 |
commit | 32e6df3621edc5067dfd6e87a387e1751f67f708 (patch) | |
tree | 957300a92ed16417fb46ce240d19f965fe773181 /elf/rtld.c | |
parent | 4be601a15e63d03adf55c48c19dda2d2e7377d8a (diff) | |
download | glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.tar.gz glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.tar.xz glibc-32e6df3621edc5067dfd6e87a387e1751f67f708.zip |
Update.
2001-12-11 Jakub Jelinek <jakub@redhat.com> * elf/Makefile (dl-routines): Add conflict. (rtld-ldscript-in, rtld-ldscript, rtld-parms): Remove. (ld.so): Add _begin local symbol. * elf/elf.h (DT_VALTAGIDX, DT_VALNUM, DT_ADDRTAGIDX, DT_ADDRNUM): Define. * elf/dl-deps.c (_dl_build_local_scope): New. (_dl_map_object_deps): If LD_TRACE_PRELINKING, compute local scopes of all libraries. * elf/do-rel.h (VALIDX): Define. (elf_dynamic_do_rel): If ELF_MACHINE_PLT_REL is defined, don't do lazy binding for RELA. If DT_GNU_PRELINKED, DT_RELACOUNT relocations can be skipped. * elf/dl-conflict.c: New file. * elf/dl-lookup.c (_dl_debug_bindings): New. (_dl_lookup_symbol): Use _dl_debug_bindings. Reference_name is always non-NULL. (_dl_lookup_symbol_skip): Likewise. (_dl_lookup_versioned_symbol): Likewise. (_dl_lookup_versioned_symbol_skip): Likewise. * elf/dl-runtime.c (PLTREL): If ELF_MACHINE_PLT_REL is defined, define to ElfW(Rel). * elf/dynamic-link.h (elf_get_dynamic_info): Record selected dynamic tags in the DT_VALRNGLO..DT_VALRNGHI and DT_ADDRRNGLO..DT_ADDRRNGHI ranges. Don't adjust address dynamic tags if l_addr is 0. * elf/rtld.c (_dl_trace_prelink, _dl_trace_prelink_map): New variables. (_dl_start): Skip ELF_DYNAMIC_RELOCATE if ld.so is prelinked. (VALIDX, ADDRIDX): Define. (_dl_start_final): Initialize _dl_rtld_map's l_map_start and l_map_end. (dl_main): Print library list for LD_TRACE_PRELINKING. If prelinking information can be used, skip relocating libraries and call _dl_resolve_conflicts instead. (process_envvars): Handle LD_TRACE_PRELINKING envvar. * elf/dl-load.c (_dl_map_object): Don't create fake libs if LD_TRACE_PRELINKING. * include/link.h (struct link_map) [l_info]: Add DT_VALNUM + DT_ADDRNUM. * sysdeps/generic/ldsodefs.h (_dl_trace_prelink_map): New declaration. (DL_DEBUG_PRELINK): Define. (_dl_resolve_conflicts): Add prototype. * sysdeps/alpha/dl-machine.h (elf_machine_runtime_setup): Reinitialize .plt for prelinked libraries where prelinking info cannot be used. (elf_machine_rela): If relocating R_ALPHA_JMP_SLOT in .gnu.conflict section, use RESOLVE_CONFLICT_FIND_MAP to find out reloc's link_map. * sysdeps/arm/bits/link.h: New file. * sysdeps/arm/dl-machine.h (elf_machine_runtime_setup): Save original content of .got[1]. (ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP. (ELF_MACHINE_PLT_REL): Define. (elf_machine_rela, elf_machine_rela_relative): New. (elf_machine_lazy_rel): Reinitialize R_ARM_JUMP_SLOT address instead of adjusting it if prelinked and prelinking cannot be used. * sysdeps/i386/bits/link.h: New file. * sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Save original content of .got[1]. (ELF_MACHINE_NO_RELA): Only define if RTLD_BOOTSTRAP. (ELF_MACHINE_PLT_REL): Define. (elf_machine_rela, elf_machine_rela_relative): New. (elf_machine_lazy_rel): Reinitialize R_386_JUMP_SLOT address instead of adjusting it if prelinked and prelinking cannot be used. * sysdeps/powerpc/dl-machine.h (elf_machine_rela): If relocating conflicts, skip finaladdr computation. Use RESOLVE_CONFLICT_FIND_MAP to find out map for R_PPC_JMP_SLOT relocs. * sysdeps/sparc/sparc32/dl-machine.h (VALIDX): Define. (OPCODE_BA): Define. (elf_machine_runtime_setup): Reinitialize .plt for prelinked libraries where prelinking info cannot be used. (sparc_fixup_plt): Renamed from elf_machine_fixup_plt. (elf_machine_fixup_plt): Call sparc_fixup_plt. (elf_machine_rela): Set value to 0 if relocating conflicts. Call sparc_fixup_plt for R_SPARC_JMP_SLOT. * sysdeps/sparc/sparc64/dl-machine.h (VALIDX): Define. (sparc64_fixup_plt): Fix a typo. (elf_machine_rela): Set value to 0 if relocating conflicts. Handle R_SPARC_JMP_SLOT relocs when relocating conflicts. (elf_machine_runtime_setup): Reinitialize .plt for prelinked libraries where prelinking info cannot be used. * sysdeps/sh/bits/link.h: New file. * sysdeps/sh/dl-machine.h (elf_machine_runtime_setup): Save original content of .got[1]. (elf_machine_lazy_rel): Reinitialize R_SH_JMP_SLOT address instead of adjusting it if prelinked and prelinking cannot be used. * sysdeps/s390/s390-32/bits/link.h: New file. * sysdeps/s390/s390-32/dl-machine.h (elf_machine_runtime_setup): Save original content of .got[1]. (elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead of adjusting it if prelinked and prelinking cannot be used. * sysdeps/s390/s390-64/bits/link.h: New file. * sysdeps/s390/s390-64/dl-machine.h (elf_machine_runtime_setup): Save original content of .got[1]. (elf_machine_lazy_rel): Reinitialize R_390_JMP_SLOT address instead of adjusting it if prelinked and prelinking cannot be used. * sysdeps/x86_64/bits/link.h: New file. * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): Save original content of .got[1]. (elf_machine_lazy_rel): Reinitialize R_X86_64_JMP_SLOT address instead of adjusting it if prelinked and prelinking cannot be used.
Diffstat (limited to 'elf/rtld.c')
-rw-r--r-- | elf/rtld.c | 167 |
1 files changed, 152 insertions, 15 deletions
diff --git a/elf/rtld.c b/elf/rtld.c index 8ed86eaedb..a05bbe9a62 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -67,6 +67,8 @@ struct r_search_path *_dl_search_paths; const char *_dl_profile; const char *_dl_profile_output; struct link_map *_dl_profile_map; +const char *_dl_trace_prelink; +struct link_map *_dl_trace_prelink_map; int _dl_lazy = 1; /* XXX I know about at least one case where we depend on the old weak behavior (it has to do with librt). Until we get DSO groups implemented @@ -183,10 +185,14 @@ _dl_start (void *arg) ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info); #endif - /* Relocate ourselves so we can do normal function calls and - data access using the global offset table. */ + if (bootstrap_map.l_addr || ! bootstrap_map.l_info[VALIDX(DT_GNU_PRELINKED)]) + { + /* Relocate ourselves so we can do normal function calls and + data access using the global offset table. */ + + ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0); + } - ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0); /* Please note that we don't allow profiling of this object and therefore need not test whether we have to allocate the array for the relocation results (as done in dl-reloc.c). */ @@ -209,6 +215,15 @@ _dl_start (void *arg) } +#ifndef VALIDX +# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRANUM + DT_VALTAGIDX (tag)) +#endif +#ifndef ADDRIDX +# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag)) +#endif + static ElfW(Addr) _dl_start_final (void *arg, struct link_map *bootstrap_map_p, hp_timing_t start_time) @@ -218,6 +233,7 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p, way to do this so we use this trick. gcc never inlines functions which use `alloca'. */ ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr))); + extern char _begin[], _end[]; if (HP_TIMING_AVAIL) { @@ -237,10 +253,8 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p, sizeof _dl_rtld_map.l_info); _dl_setup_hash (&_dl_rtld_map); _dl_rtld_map.l_mach = bootstrap_map_p->l_mach; - -/* Don't bother trying to work out how ld.so is mapped in memory. */ - _dl_rtld_map.l_map_start = ~0; - _dl_rtld_map.l_map_end = ~0; + _dl_rtld_map.l_map_start = (ElfW(Addr)) _begin; + _dl_rtld_map.l_map_end = (ElfW(Addr)) _end; /* Call the OS-dependent function to set up life so we can do things like file access. It will call `dl_main' (below) to do all the real work @@ -383,6 +397,7 @@ dl_main (const ElfW(Phdr) *phdr, char *file; int has_interp = 0; unsigned int i; + int prelinked = 0; int rtld_is_main = 0; #ifndef HP_TIMING_NONAVAIL hp_timing_t start; @@ -885,13 +900,42 @@ of this helper program; chances are you did not intend to run this program.\n\ { struct link_map *l; - for (l = _dl_loaded->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); - else - _dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name, - l->l_name, (int) sizeof l->l_addr * 2, l->l_addr); + if (_dl_debug_mask & DL_DEBUG_PRELINK) + { + struct r_scope_elem *scope = &_dl_loaded->l_searchlist; + + for (i = 0; i < scope->r_nlist; i++) + { + l = scope->r_list [i]; + if (l->l_faked) + { + _dl_printf ("\t%s => not found\n", l->l_libname->name); + continue; + } + if (_dl_name_match_p (_dl_trace_prelink, l)) + _dl_trace_prelink_map = l; + _dl_printf ("\t%s => %s (0x%0*Zx, 0x%0*Zx)\n", + l->l_libname->name[0] ? l->l_libname->name + : _dl_argv[0] ?: "<main program>", + l->l_name[0] ? l->l_name + : _dl_argv[0] ?: "<main program>", + (int) sizeof l->l_map_start * 2, + l->l_map_start, + (int) sizeof l->l_addr * 2, + l->l_addr); + } + } + else + { + for (l = _dl_loaded->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); + else + _dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name, + l->l_name, (int) sizeof l->l_map_start * 2, + l->l_map_start); + } } if (__builtin_expect (mode, trace) != trace) @@ -936,6 +980,10 @@ of this helper program; chances are you did not intend to run this program.\n\ } l = l->l_prev; } while (l); + + if ((_dl_debug_mask & DL_DEBUG_PRELINK) + && _dl_rtld_map.l_opencount > 1) + _dl_relocate_object (&_dl_rtld_map, _dl_loaded->l_scope, 0, 0); } #define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)) @@ -1014,6 +1062,84 @@ of this helper program; chances are you did not intend to run this program.\n\ _exit (0); } + if (_dl_loaded->l_info [ADDRIDX (DT_GNU_LIBLIST)] + && ! __builtin_expect (_dl_profile != NULL, 0)) + { + ElfW(Lib) *liblist, *liblistend; + struct link_map **r_list, **r_listend, *l; + const char *strtab = (const void *) + D_PTR (_dl_loaded, l_info[DT_STRTAB]); + + assert (_dl_loaded->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL); + liblist = (ElfW(Lib) *) + _dl_loaded->l_info [ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr; + liblistend = (ElfW(Lib) *) + ((char *) liblist + + _dl_loaded->l_info [VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val); + r_list = _dl_loaded->l_searchlist.r_list; + r_listend = r_list + _dl_loaded->l_searchlist.r_nlist; + + for (; r_list < r_listend && liblist < liblistend; r_list++) + { + l = *r_list; + + if (l == _dl_loaded) + continue; + + /* If the library is not mapped where it should, fail. */ + if (l->l_addr) + break; + + /* Next, check if checksum matches. */ + if (l->l_info [VALIDX(DT_CHECKSUM)] == NULL + || l->l_info [VALIDX(DT_CHECKSUM)]->d_un.d_val + != liblist->l_checksum) + break; + + if (l->l_info [VALIDX(DT_GNU_PRELINKED)] == NULL + || l->l_info [VALIDX(DT_GNU_PRELINKED)]->d_un.d_val + != liblist->l_time_stamp) + break; + + if (! _dl_name_match_p (strtab + liblist->l_name, l)) + break; + + ++liblist; + } + + + if (r_list == r_listend && liblist == liblistend) + prelinked = 1; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_printf ("\nprelink checking: %s\n", prelinked ? "ok" : "failed"); + } + + if (prelinked) + { + if (_dl_loaded->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL) + { + ElfW(Rela) *conflict, *conflictend; +#ifndef HP_TIMING_NONAVAIL + hp_timing_t start; + hp_timing_t stop; +#endif + + HP_TIMING_NOW (start); + assert (_dl_loaded->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL); + conflict = (ElfW(Rela) *) + _dl_loaded->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr; + conflictend = (ElfW(Rela) *) + ((char *) conflict + + _dl_loaded->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val); + _dl_resolve_conflicts (_dl_loaded, conflict, conflictend); + HP_TIMING_NOW (stop); + HP_TIMING_DIFF (relocate_time, start, stop); + } + + _dl_sysdep_start_cleanup (); + } + else { /* Now we have all the objects loaded. Relocate them all except for the dynamic linker itself. We do this in reverse order so that copy @@ -1094,7 +1220,7 @@ of this helper program; chances are you did not intend to run this program.\n\ _dl_main_searchlist = &_dl_loaded->l_searchlist; _dl_global_scope[0] = &_dl_loaded->l_searchlist; - /* Safe the information about the original global scope list since + /* Save the information about the original global scope list since we need it in the memory handling later. */ _dl_initial_searchlist = *_dl_main_searchlist; @@ -1371,6 +1497,17 @@ process_envvars (enum mode *modep) _dl_profile_output = &envline[15]; break; + case 16: + /* The mode of the dynamic linker can be set. */ + if (memcmp (envline, "TRACE_PRELINKING", 16) == 0) + { + mode = trace; + _dl_verbose = 1; + _dl_debug_mask |= DL_DEBUG_PRELINK; + _dl_trace_prelink = &envline[17]; + } + break; + case 20: /* The mode of the dynamic linker can be set. */ if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0) |