about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2007-07-12 15:34:58 +0000
committerJakub Jelinek <jakub@redhat.com>2007-07-12 15:34:58 +0000
commit561774ab86f8722cd0020809251febc09cf3d99c (patch)
tree641df1f27ba40d5b508a8533767c7fd104722000
parent3c8ed68000400bb993f4b9cc4efd36cb17c9c6ec (diff)
downloadglibc-561774ab86f8722cd0020809251febc09cf3d99c.tar.gz
glibc-561774ab86f8722cd0020809251febc09cf3d99c.tar.xz
glibc-561774ab86f8722cd0020809251febc09cf3d99c.zip
2007-06-19 Ulrich Drepper <drepper@redhat.com>
	* sysdeps/generic/ldsodefs.h (rtld_global): Reorder some elements
	to fill in holes
	(rtld_global_ro): Likewise.

2007-06-18  Jakub Jelinek  <jakub@redhat.com>

	* 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.
-rw-r--r--ChangeLog22
-rw-r--r--dlfcn/dlinfo.c5
-rw-r--r--elf/dl-addr.c36
-rw-r--r--elf/dl-iteratephdr.c6
-rw-r--r--elf/dl-load.c3
-rw-r--r--elf/dl-open.c24
-rw-r--r--elf/dl-sym.c5
-rw-r--r--include/link.h3
-rw-r--r--sysdeps/generic/ldsodefs.h24
9 files changed, 90 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index 6e635e6e95..1278a92bf4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2007-06-19  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/generic/ldsodefs.h (rtld_global): Reorder some elements
+	to fill in holes
+	(rtld_global_ro): Likewise.
+
+2007-06-18  Jakub Jelinek  <jakub@redhat.com>
+
+	* 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  <jakub@redhat.com>
 
 	* elf/rtld.c (dl_main): Don't call init_tls more than once.
diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c
index b1e2b009a5..e931b40b01 100644
--- a/dlfcn/dlinfo.c
+++ b/dlfcn/dlinfo.c
@@ -58,9 +58,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 17b73be724..e8620e686f 100644
--- a/elf/dl-addr.c
+++ b/elf/dl-addr.c
@@ -138,22 +138,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:
@@ -162,3 +152,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 52a114421d..7cd4d3e2b8 100644
--- a/elf/dl-iteratephdr.c
+++ b/elf/dl-iteratephdr.c
@@ -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 0bb58129c5..175cf89dbf 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1225,6 +1225,8 @@ cannot allocate TLS data structures for initial thread");
 		      loadcmds[nloadcmds - 1].mapstart - c->mapend,
 		      PROT_NONE);
 
+	l->l_contiguous = 1;
+
 	goto postmap;
       }
 
@@ -1244,6 +1246,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 e10b421b8a..69d48a622e 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -237,10 +237,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;
@@ -697,3 +697,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 7066566bed..cedd8def80 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -100,10 +100,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 37602345de..438ec013b2 100644
--- a/include/link.h
+++ b/include/link.h
@@ -182,6 +182,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.  */
 
     /* Array with version names.  */
     unsigned int l_nversions;
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 4c836e24ee..7989e221e8 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -438,23 +438,23 @@ 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;
 
+  /* Prevailing state of the stack, PF_X indicating it's executable.  */
+  EXTERN ElfW(Word) _dl_stack_flags;
+
   /* Keep the conditional TLS members at the end so the layout of the
      structure used by !USE_TLS code matches the prefix of the layout in
      the USE_TLS rtld.  Note that `struct link_map' is conditionally
      defined as well, so _dl_rtld_map needs to be last before this.  */
 #ifdef USE_TLS
-  /* Highest dtv index currently needed.  */
-  EXTERN size_t _dl_tls_max_dtv_idx;
   /* 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
   {
@@ -549,15 +549,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;
 
@@ -586,9 +586,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;
 
@@ -672,6 +669,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
@@ -1085,6 +1085,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