Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 Dec 2009 14:13:13 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r200839 - stable/7/libexec/rtld-elf
Message-ID:  <200912221413.nBMEDDrp066246@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Dec 22 14:13:13 2009
New Revision: 200839
URL: http://svn.freebsd.org/changeset/base/200839

Log:
  MFC r190883:
  Update comment, fix spacing.
  
  MFC r190885:
  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.
  
  MFC r195743:
  Only perform .bss mapping and cleaning operations when segment file size
  is not equal to its memory size.
  
  Tested by:	Mykola Dzham <freebsd levsha org ua>

Modified:
  stable/7/libexec/rtld-elf/map_object.c
Directory Properties:
  stable/7/libexec/rtld-elf/   (props changed)

Modified: stable/7/libexec/rtld-elf/map_object.c
==============================================================================
--- stable/7/libexec/rtld-elf/map_object.c	Tue Dec 22 13:53:34 2009	(r200838)
+++ stable/7/libexec/rtld-elf/map_object.c	Tue Dec 22 14:13:13 2009	(r200839)
@@ -91,8 +91,7 @@ map_object(int fd, const char *path, con
     /*
      * Scan the program header entries, and save key information.
      *
-     * We rely on there being exactly two load segments, text and data,
-     * in that order.
+     * We expect that the loadable segments are ordered by load address.
      */
     phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff);
     phsize  = hdr->e_phnum * sizeof (phdr[0]);
@@ -153,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));
@@ -167,7 +166,7 @@ map_object(int fd, const char *path, con
 	return NULL;
     }
 
-    for (i = 0; i <=  nsegs; i++) {
+    for (i = 0; i <= nsegs; i++) {
 	/* Overlay the segment onto the proper region. */
 	data_offset = trunc_page(segs[i]->p_offset);
 	data_vaddr = trunc_page(segs[i]->p_vaddr);
@@ -175,45 +174,49 @@ 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;
 	}
 
-	/* Clear any BSS in the last page of the segment. */
-	clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz;
-	clear_addr = mapbase + (clear_vaddr - base_vaddr);
-	clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr);
-	if ((nclear = data_vlimit - clear_vaddr) > 0) {
-	    /* Make sure the end of the segment is writable */
-	    if ((data_prot & PROT_WRITE) == 0 &&
-		-1 ==  mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) {
+	/* Do BSS setup */
+	if (segs[i]->p_filesz != segs[i]->p_memsz) {
+
+	    /* Clear any BSS in the last page of the segment. */
+	    clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz;
+	    clear_addr = mapbase + (clear_vaddr - base_vaddr);
+	    clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr);
+
+	    if ((nclear = data_vlimit - clear_vaddr) > 0) {
+		/* Make sure the end of the segment is writable */
+		if ((data_prot & PROT_WRITE) == 0 && -1 ==
+		     mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) {
 			_rtld_error("%s: mprotect failed: %s", path,
 			    strerror(errno));
 			return NULL;
-	    }
+		}
 
-	    memset(clear_addr, 0, nclear);
+		memset(clear_addr, 0, nclear);
 
-	    /* Reset the data protection back */
-	    if ((data_prot & PROT_WRITE) == 0)
-		 mprotect(clear_page, PAGE_SIZE, data_prot);
-	}
+		/* Reset the data protection back */
+		if ((data_prot & PROT_WRITE) == 0)
+		    mprotect(clear_page, PAGE_SIZE, data_prot);
+	    }
 
-	/* Overlay the BSS segment onto the proper region. */
-	bss_vaddr = data_vlimit;
-	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,
+	    /* Overlay the BSS segment onto the proper region. */
+	    bss_vaddr = data_vlimit;
+	    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 (mprotect(bss_addr, bss_vlimit - bss_vaddr, data_prot) == -1) {
+		    _rtld_error("%s: mprotect of bss failed: %s", path,
 			strerror(errno));
-		return NULL;
+		    return NULL;
+		}
 	    }
 	}
+
 	if (phdr_vaddr == 0 && data_offset <= hdr->e_phoff &&
 	  (data_vlimit - data_vaddr + data_offset) >=
 	  (hdr->e_phoff + hdr->e_phnum * sizeof (Elf_Phdr))) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912221413.nBMEDDrp066246>