summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf/map_object.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-04-10 10:14:04 +0000
committerkib <kib@FreeBSD.org>2009-04-10 10:14:04 +0000
commit5a12c5d70e83806a92145c478867d74073203a09 (patch)
treec0fa23ef0f50f65ebe86bf8b1b0afe26c03afc1a /libexec/rtld-elf/map_object.c
parentcd9a5afff5db18022235b4e882b1ee5b9095d754 (diff)
downloadFreeBSD-src-5a12c5d70e83806a92145c478867d74073203a09.zip
FreeBSD-src-5a12c5d70e83806a92145c478867d74073203a09.tar.gz
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
Diffstat (limited to 'libexec/rtld-elf/map_object.c')
-rw-r--r--libexec/rtld-elf/map_object.c12
1 files changed, 5 insertions, 7 deletions
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 211c01c..028ac80 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -152,8 +152,8 @@ map_object(int fd, const char *path, const struct stat *sb)
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, const struct stat *sb)
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, const struct stat *sb)
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;
}
OpenPOWER on IntegriCloud