svn commit: r190885 - head/libexec/rtld-elf

Konstantin Belousov kib at FreeBSD.org
Fri Apr 10 10:14:05 UTC 2009


Author: kib
Date: Fri Apr 10 10:14:04 2009
New Revision: 190885
URL: http://svn.freebsd.org/changeset/base/190885

Log:
  Currently, when mapping an object, rtld reserves the whole address space
  for the mapping by the object' file with the protection and mode of
  the first loadable segment over the whole region. Then, it maps other
  segments at the appropriate addresses inside the region.
  
  On amd64, due to default alignment of the segments being 1Gb, the
  subsequent segment mappings leave the holes in the region, that usually
  contain mapping of the object' file past eof. Such mappings prevent
  wiring of the address space, because the pages cannot be faulted in.
  
  Change the way the mapping of the ELF objects is constructed, by first
  mapping PROT_NONE anonymous memory over the whole range, and then
  mapping the segments of the object over it. Take advantage of this new
  order and allocate .bss by changing the protection of the range instead
  of remapping.
  
  Note that we cannot simply keep the holes between segments, because
  other mappings may be made there. Among other issues, when the dso is
  unloaded, rtld unmaps the whole region, deleting unrelated mappings.
  
  The kernel ELF image activator does put the holes between segments, but
  this is not critical for now because kernel loads only executable image
  and interpreter, both cannot be unloaded. This will be fixed later, if
  needed.
  
  Reported and tested by:	Hans Ottevanger <fbsdhackers beasties demon nl>
  Suggested and reviewed by:	kan, alc

Modified:
  head/libexec/rtld-elf/map_object.c

Modified: head/libexec/rtld-elf/map_object.c
==============================================================================
--- head/libexec/rtld-elf/map_object.c	Fri Apr 10 10:12:09 2009	(r190884)
+++ head/libexec/rtld-elf/map_object.c	Fri Apr 10 10:14:04 2009	(r190885)
@@ -152,8 +152,8 @@ map_object(int fd, const char *path, con
     mapsize = base_vlimit - base_vaddr;
     base_addr = hdr->e_type == ET_EXEC ? (caddr_t) base_vaddr : NULL;
 
-    mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags),
-      convert_flags(segs[0]->p_flags), fd, base_offset);
+    mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE |
+      MAP_NOCORE, -1, 0);
     if (mapbase == (caddr_t) -1) {
 	_rtld_error("%s: mmap of entire address space failed: %s",
 	  path, strerror(errno));
@@ -174,8 +174,7 @@ map_object(int fd, const char *path, con
 	data_addr = mapbase + (data_vaddr - base_vaddr);
 	data_prot = convert_prot(segs[i]->p_flags);
 	data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED;
-	/* Do not call mmap on the first segment - this is redundant */
-	if (i && mmap(data_addr, data_vlimit - data_vaddr, data_prot,
+	if (mmap(data_addr, data_vlimit - data_vaddr, data_prot,
 	  data_flags, fd, data_offset) == (caddr_t) -1) {
 	    _rtld_error("%s: mmap of data failed: %s", path, strerror(errno));
 	    return NULL;
@@ -206,9 +205,8 @@ map_object(int fd, const char *path, con
 	bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz);
 	bss_addr = mapbase +  (bss_vaddr - base_vaddr);
 	if (bss_vlimit > bss_vaddr) {	/* There is something to do */
-	    if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot,
-		MAP_PRIVATE|MAP_FIXED|MAP_ANON, -1, 0) == (caddr_t) -1) {
-		    _rtld_error("%s: mmap of bss failed: %s", path,
+	    if (mprotect(bss_addr, bss_vlimit - bss_vaddr, data_prot) == -1) {
+		    _rtld_error("%s: mprotect of bss failed: %s", path,
 			strerror(errno));
 		return NULL;
 	    }


More information about the svn-src-head mailing list