summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-07-17 19:32:04 +0000
committerkib <kib@FreeBSD.org>2009-07-17 19:32:04 +0000
commita1f78e164214141f530fa8d073a4a18ccb5e0b37 (patch)
treea5e6d591ace4afa6b859024f9a7a394b30aa2d15
parentcb17ea09364d56a9fb8577f387e3869e16605ba0 (diff)
downloadFreeBSD-src-a1f78e164214141f530fa8d073a4a18ccb5e0b37.zip
FreeBSD-src-a1f78e164214141f530fa8d073a4a18ccb5e0b37.tar.gz
Only perform .bss mapping and cleaning operations when segment file size
is not equal to its memory size. This eliminates unneeded clearing of the text segment that often happens due to text end not being page-aligned. For instance, $ readelf -l /lib/libedit.so.6 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x00000000 0x00000000 0x139e1 0x139e1 R E 0x1000 LOAD 0x014000 0x00014000 0x00014000 0x00f04 0x00f14 RW 0x1000 DYNAMIC 0x014cc4 0x00014cc4 0x00014cc4 0x000d0 0x000d0 RW 0x4 $ procstat -v $$ (for /bin/sh) 68585 0x28097000 0x280aa000 r-x 6 0 21 14 CN vn /lib/libedit.so.6 68585 0x280aa000 0x280ab000 r-x 1 0 1 0 CN vn /lib/libedit.so.6 <== 68585 0x280ab000 0x280ac000 rwx 1 0 1 0 CN vn /lib/libedit.so.6 Note the splitted map entry marked by '<=='. Reviewed by: kan Approved by: re (kensmith) MFC after: 1 month
-rw-r--r--libexec/rtld-elf/map_object.c48
1 files changed, 27 insertions, 21 deletions
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 028ac80..6de0c9e 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -180,37 +180,43 @@ map_object(int fd, const char *path, const struct stat *sb)
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 (mprotect(bss_addr, bss_vlimit - bss_vaddr, data_prot) == -1) {
+ /* 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))) {
OpenPOWER on IntegriCloud