diff --git a/ChangeLog b/ChangeLog index e75170e75a..444973335f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2007-06-19 Ulrich Drepper + + * sysdeps/generic/ldsodefs.h (rtld_global): Reorder some elements + to fill in holes + (rtld_global_ro): Likewise. + +2007-06-18 Jakub Jelinek + + * elf/dl-addr.c (_dl_addr): Skip PT_LOAD checking if l_contiguous. + Move PT_LOAD checking to... + (_dl_addr_inside_object): ... here, new function. + * elf/dl-sym.c (do_sym): If not l_contiguous, + call _dl_addr_inside_object. + * elf/dl-iteratephdr.c (__dl_iterate_phdr): Likewise. + * dlfcn/dlinfo.c (dlinfo_doit): Likewise. + * elf/dl-open.c (dl_open_worker): Likewise. + (_dl_addr_inside_object): New function if IS_IN_rtld. + * elf/dl-load.c (_dl_map_object_from_fd): Set l_contiguous if no + holes are present or are PROT_NONE protected. + * include/link.h (struct link_map): Add l_contiguous field. + * sysdeps/generic/ldsodefs.h (_dl_addr_inside_object): New prototype. + 2007-06-18 Jakub Jelinek Tomas Janousek Ulrich Drepper diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c index 923127cbf3..b3a3e13899 100644 --- a/dlfcn/dlinfo.c +++ b/dlfcn/dlinfo.c @@ -1,5 +1,5 @@ /* dlinfo -- Get information from the dynamic linker. - Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2006, 2007 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 @@ -56,9 +56,8 @@ dlinfo_doit (void *argsblock) /* Find the highest-addressed object that CALLER is not below. */ for (nsid = 0; nsid < DL_NNS; ++nsid) for (l = GL(dl_ns)[nsid]._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. */ + if (caller >= l->l_map_start && caller < l->l_map_end + && (l->l_contiguous || _dl_addr_inside_object (l, caller))) break; if (l == NULL) diff --git a/elf/dl-addr.c b/elf/dl-addr.c index e13105572e..17745b55b0 100644 --- a/elf/dl-addr.c +++ b/elf/dl-addr.c @@ -134,22 +134,12 @@ _dl_addr (const void *address, Dl_info *info, /* Find the highest-addressed object that ADDRESS is not below. */ 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) + if (addr >= l->l_map_start && addr < l->l_map_end + && (l->l_contiguous || _dl_addr_inside_object (l, addr))) { - /* Make sure it lies within one of L's segments. */ - int n = l->l_phnum; - const ElfW(Addr) reladdr = addr - l->l_addr; - while (--n >= 0) - if (l->l_phdr[n].p_type == PT_LOAD) - { - if (reladdr - l->l_phdr[n].p_vaddr >= 0 - && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz) - { - determine_info (addr, l, info, mapp, symbolp); - result = 1; - goto out; - } - } + determine_info (addr, l, info, mapp, symbolp); + result = 1; + goto out; } out: @@ -158,3 +148,19 @@ _dl_addr (const void *address, Dl_info *info, return result; } libc_hidden_def (_dl_addr) + +/* Return non-zero if ADDR lies within one of L's segments. */ +int +internal_function +_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr) +{ + int n = l->l_phnum; + const ElfW(Addr) reladdr = addr - l->l_addr; + + while (--n >= 0) + if (l->l_phdr[n].p_type == PT_LOAD + && reladdr - l->l_phdr[n].p_vaddr >= 0 + && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz) + return 1; + return 0; +} diff --git a/elf/dl-iteratephdr.c b/elf/dl-iteratephdr.c index d03d8b6daf..55cf10852e 100644 --- a/elf/dl-iteratephdr.c +++ b/elf/dl-iteratephdr.c @@ -1,5 +1,5 @@ /* Get loaded objects program headers. - Copyright (C) 2001,2002,2003,2004,2006 Free Software Foundation, Inc. + Copyright (C) 2001,2002,2003,2004,2006,2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek , 2001. @@ -54,9 +54,9 @@ __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, 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. */ + && caller < (const void *) l->l_map_end + && (l->l_contiguous + || _dl_addr_inside_object (l, (ElfW(Addr)) caller))) ns = cnt; } diff --git a/elf/dl-load.c b/elf/dl-load.c index 1650ef953a..025b9fd86b 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1,5 +1,5 @@ /* Map in a shared object's segments from the file. - Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc. + Copyright (C) 1995-2005, 2006, 2007 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 @@ -1223,6 +1223,8 @@ cannot allocate TLS data structures for initial thread"); loadcmds[nloadcmds - 1].mapstart - c->mapend, PROT_NONE); + l->l_contiguous = 1; + goto postmap; } @@ -1242,6 +1244,7 @@ cannot allocate TLS data structures for initial thread"); /* Remember which part of the address space this object uses. */ l->l_map_start = c->mapstart + l->l_addr; l->l_map_end = l->l_map_start + maplength; + l->l_contiguous = !has_holes; while (c < &loadcmds[nloadcmds]) { diff --git a/elf/dl-open.c b/elf/dl-open.c index a043cf61b6..2000f580c3 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -201,10 +201,10 @@ dl_open_worker (void *a) 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) + && caller_dlopen < (const void *) l->l_map_end + && (l->l_contiguous + || _dl_addr_inside_object (l, (ElfW(Addr)) caller_dlopen))) { - /* 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; @@ -662,3 +662,21 @@ show_scope (struct link_map *new) } } #endif + +#ifdef IS_IN_rtld +/* Return non-zero if ADDR lies within one of L's segments. */ +int +internal_function +_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr) +{ + int n = l->l_phnum; + const ElfW(Addr) reladdr = addr - l->l_addr; + + while (--n >= 0) + if (l->l_phdr[n].p_type == PT_LOAD + && reladdr - l->l_phdr[n].p_vaddr >= 0 + && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz) + return 1; + return 0; +} +#endif diff --git a/elf/dl-sym.c b/elf/dl-sym.c index 1c3ab5c877..0e1b258b5a 100644 --- a/elf/dl-sym.c +++ b/elf/dl-sym.c @@ -98,10 +98,9 @@ do_sym (void *handle, const char *name, void *who, 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) + if (caller >= l->l_map_start && caller < l->l_map_end + && (l->l_contiguous || _dl_addr_inside_object (l, caller))) { - /* There must be exactly one DSO for the range of the virtual - memory. Otherwise something is really broken. */ match = l; break; } diff --git a/include/link.h b/include/link.h index 67d70470d1..56764a9164 100644 --- a/include/link.h +++ b/include/link.h @@ -187,6 +187,9 @@ struct link_map is interested in the PLT interception.*/ unsigned int l_removed:1; /* Nozero if the object cannot be used anymore since it is removed. */ + unsigned int l_contiguous:1; /* Nonzero if inter-segment holes are + mprotected or if no holes are present at + all. */ /* Collected information about own RPATH directories. */ struct r_search_path_struct l_rpath_dirs; diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 5205c41493..c910ed59c4 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -439,18 +439,18 @@ struct rtld_global EXTERN void (*_dl_rtld_unlock_recursive) (void *); #endif - /* Prevailing state of the stack, PF_X indicating it's executable. */ - EXTERN ElfW(Word) _dl_stack_flags; - /* If loading a shared object requires that we make the stack executable when it was not, we do it by calling this function. It returns an errno code or zero on success. */ EXTERN int (*_dl_make_stack_executable_hook) (void **) internal_function; - /* Highest dtv index currently needed. */ - EXTERN size_t _dl_tls_max_dtv_idx; + /* Prevailing state of the stack, PF_X indicating it's executable. */ + EXTERN ElfW(Word) _dl_stack_flags; + /* Flag signalling whether there are gaps in the module ID allocation. */ EXTERN bool _dl_tls_dtv_gaps; + /* Highest dtv index currently needed. */ + EXTERN size_t _dl_tls_max_dtv_idx; /* Information about the dtv slots. */ EXTERN struct dtv_slotinfo_list { @@ -534,15 +534,15 @@ struct rtld_global_ro #define DL_DEBUG_HELP (1 << 9) #define DL_DEBUG_PRELINK (1 << 10) - /* Cached value of `getpagesize ()'. */ - EXTERN size_t _dl_pagesize; - /* OS version. */ EXTERN unsigned int _dl_osversion; /* Platform name. */ EXTERN const char *_dl_platform; EXTERN size_t _dl_platformlen; + /* Cached value of `getpagesize ()'. */ + EXTERN size_t _dl_pagesize; + /* Copy of the content of `_dl_main_searchlist' at startup time. */ EXTERN struct r_scope_elem _dl_initial_searchlist; @@ -571,9 +571,6 @@ struct rtld_global_ro /* Expected cache ID. */ EXTERN int _dl_correct_cache_id; - /* 0 if internal pointer values should not be guarded, 1 if they should. */ - EXTERN int _dl_pointer_guard; - /* Mask for hardware capabilities that are available. */ EXTERN uint64_t _dl_hwcap; @@ -657,6 +654,9 @@ struct rtld_global_ro /* List of auditing interfaces. */ struct audit_ifaces *_dl_audit; unsigned int _dl_naudit; + + /* 0 if internal pointer values should not be guarded, 1 if they should. */ + EXTERN int _dl_pointer_guard; }; # define __rtld_global_attribute__ # ifdef IS_IN_rtld @@ -1061,6 +1061,8 @@ extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid); but never touch anything. Return null if it's not allocated yet. */ extern void *_dl_tls_get_addr_soft (struct link_map *l) internal_function; +extern int _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr) + internal_function attribute_hidden; __END_DECLS