Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(203)

Unified Diff: src/native_client/src/trusted/service_runtime/nacl_text.c

Issue 7068021: Dynamic loading: Fill pages with halts only when they are needed (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Fix log messages Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/native_client/src/trusted/service_runtime/nacl_text.c
diff --git a/src/native_client/src/trusted/service_runtime/nacl_text.c b/src/native_client/src/trusted/service_runtime/nacl_text.c
index 1e308f2a46ca7e71e0d3755f574fa6b1dd19f1a4..2de527ef3872247390820c0427cb4d0e23b09472 100644
--- a/src/native_client/src/trusted/service_runtime/nacl_text.c
+++ b/src/native_client/src/trusted/service_runtime/nacl_text.c
@@ -7,6 +7,7 @@
#include <string.h>
#include "native_client/src/include/concurrency_ops.h"
+#include "native_client/src/include/nacl_platform.h"
#include "native_client/src/include/portability.h"
#include "native_client/src/shared/platform/nacl_check.h"
#include "native_client/src/shared/platform/nacl_log.h"
@@ -30,6 +31,25 @@
/* initial size of the malloced buffer for dynamic regions */
static const int kMinDynamicRegionsAllocated = 32;
+static const int kBitsPerByte = 8;
+
+static uint8_t *BitmapAllocate(uint32_t indexes) {
+ uint32_t byte_count = (indexes + kBitsPerByte - 1) / kBitsPerByte;
+ uint8_t *bitmap = malloc(byte_count);
+ if (bitmap != NULL) {
+ memset(bitmap, 0, byte_count);
+ }
+ return bitmap;
+}
+
+static int BitmapIsBitSet(uint8_t *bitmap, uint32_t index) {
+ return (bitmap[index / kBitsPerByte] & (1 << (index % kBitsPerByte))) != 0;
+}
+
+static void BitmapSetBit(uint8_t *bitmap, uint32_t index) {
+ bitmap[index / kBitsPerByte] |= 1 << (index % kBitsPerByte);
+}
+
/*
* Private subclass of NaClDescEffector, used only in this file.
*/
@@ -90,10 +110,11 @@ NaClErrorCode NaClMakeDynamicTextShared(struct NaClApp *nap) {
struct NaClDescEffectorShm shm_effector;
int shm_effector_initialized = 0;
uintptr_t shm_vaddr_base;
- uintptr_t shm_offset;
+ int mmap_protections;
uintptr_t mmap_ret;
uintptr_t shm_upper_bound;
+ uintptr_t text_sysaddr;
shm_vaddr_base = NaClEndOfStaticText(nap);
NaClLog(4,
@@ -163,76 +184,72 @@ NaClErrorCode NaClMakeDynamicTextShared(struct NaClApp *nap) {
}
shm_effector_initialized = 1;
+ text_sysaddr = NaClUserToSys(nap, shm_vaddr_base);
+
+ /* Existing memory is anonymous paging file backed. */
+ NaCl_page_free((void *) text_sysaddr, dynamic_text_size);
+
/*
- * Map shm in place of text. We currently do this eagerly, which
- * can result in excess memory/swap traffic.
+ * Unix allows us to map pages with PROT_NONE initially and later
+ * increase the mapping permissions with mprotect().
*
- * TODO(bsy): consider using NX and doing this lazily, or mapping a
- * canonical HLT-filled 64K shm repeatedly, and only remapping with
- * a "real" shm text as needed.
+ * Windows does not allow this, however: the initial permissions are
+ * an upper bound on what the permissions may later be changed to
+ * with VirtualProtect(). Given this, using PROT_NONE at this point
+ * does not even make sense. So we map with read+exec and
+ * immediately turn down the permissions, so that we can later
+ * re-enable read+exec page by page.
*/
- for (shm_offset = 0;
- shm_offset < dynamic_text_size;
- shm_offset += NACL_MAP_PAGESIZE) {
- uintptr_t text_vaddr = shm_vaddr_base + shm_offset;
- uintptr_t text_sysaddr = NaClUserToSys(nap, text_vaddr);
-
- /* Existing memory is anonymous paging file backed. */
- NaCl_page_free((void *) text_sysaddr, NACL_MAP_PAGESIZE);
+#if NACL_WINDOWS
+ mmap_protections = NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC;
+#else
+ mmap_protections = NACL_ABI_PROT_NONE;
+#endif
+ NaClLog(4,
+ "NaClMakeDynamicTextShared: Map(,,0x%"NACL_PRIxPTR",size = 0x%x,"
+ " prot=0x%x, flags=0x%x, offset=0)\n",
+ text_sysaddr,
+ (int) dynamic_text_size,
+ mmap_protections,
+ NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED);
+ mmap_ret = (*((struct NaClDescVtbl const *) shm->base.base.vtbl)->
+ Map)((struct NaClDesc *) shm,
+ (struct NaClDescEffector *) &shm_effector,
+ (void *) text_sysaddr,
+ dynamic_text_size,
+ mmap_protections,
+ NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED,
+ 0);
+ if (text_sysaddr != mmap_ret) {
+ NaClLog(LOG_FATAL, "Could not map in shm for dynamic text region\n");
+ }
- NaClLog(4,
- "NaClMakeDynamicTextShared: Map(,,0x%"NACL_PRIxPTR",size = 0x%x,"
- " prot=0x%x, flags=0x%x, offset=0x%"NACL_PRIxPTR"\n",
- text_sysaddr,
- NACL_MAP_PAGESIZE,
- NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
- NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED,
- shm_offset);
- mmap_ret = (*((struct NaClDescVtbl const *)
- shm->base.base.vtbl)->
- Map)((struct NaClDesc *) shm,
- (struct NaClDescEffector *) &shm_effector,
- (void *) text_sysaddr,
- NACL_MAP_PAGESIZE,
- NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
- NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED,
- shm_offset);
- if (text_sysaddr != mmap_ret) {
- NaClLog(LOG_FATAL,
- "Could not map in shm for dynamic text region, HLT filling.\n");
- }
- NaClFillMemoryRegionWithHalt((void *) text_sysaddr, NACL_MAP_PAGESIZE);
- if (-1 == (*((struct NaClDescVtbl const *)
- shm->base.base.vtbl)->
- UnmapUnsafe)((struct NaClDesc *) shm,
- ((struct NaClDescEffector *)
- &shm_effector),
- (void *) text_sysaddr,
- NACL_MAP_PAGESIZE)) {
- NaClLog(LOG_FATAL,
- "Could not unmap shm for dynamic text region, post HLT fill.\n");
- }
- NaClLog(4,
- "NaClMakeDynamicTextShared: Map(,,0x%"NACL_PRIxPTR",size = 0x%x,"
- " prot=0x%x, flags=0x%x, offset=0x%"NACL_PRIxPTR"\n",
- text_sysaddr,
- NACL_MAP_PAGESIZE,
- NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
- NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED,
- shm_offset);
- mmap_ret = (*((struct NaClDescVtbl const *)
- shm->base.base.vtbl)->
- Map)((struct NaClDesc *) shm,
- (struct NaClDescEffector *) &shm_effector,
- (void *) text_sysaddr,
- NACL_MAP_PAGESIZE,
- NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
- NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED,
- shm_offset);
- if (text_sysaddr != mmap_ret) {
- NaClLog(LOG_FATAL, "Could not map in shm for dynamic text region\n");
+#if NACL_WINDOWS
+ {
+ /*
+ * We need a loop here because the Map() call above creates one
+ * mapping per page. However, there is no need for it to do that
+ * for the dynamic code area.
+ * TODO(mseaborn): Create a single mapping here.
+ */
+ uintptr_t offset;
+ for (offset = 0; offset < dynamic_text_size; offset += NACL_MAP_PAGESIZE) {
+ DWORD old_prot;
+ if (!VirtualProtect((void *) (text_sysaddr + offset), NACL_MAP_PAGESIZE,
+ PAGE_NOACCESS, &old_prot)) {
+ NaClLog(LOG_FATAL,
+ "NaClMakeDynamicTextShared: VirtualProtect() failed to "
+ "set page permissions to PAGE_NOACCESS\n");
+ }
}
}
+#endif
+
+ nap->dynamic_page_bitmap =
+ BitmapAllocate((uint32_t) (dynamic_text_size / NACL_MAP_PAGESIZE));
+ if (NULL == nap->dynamic_page_bitmap) {
+ NaClLog(LOG_FATAL, "NaClMakeDynamicTextShared: BitmapAllocate() failed\n");
+ }
nap->text_shm = &shm->base;
retval = LOAD_OK;
@@ -494,6 +511,30 @@ static INLINE void CopyCodeSafelyInitial(uint8_t *dest,
*/
}
+static void MakeDynamicCodePageVisible(struct NaClApp *nap,
+ uint32_t page_index,
+ uint8_t *writable_addr) {
+ void *user_addr;
+
+ if (BitmapIsBitSet(nap->dynamic_page_bitmap, page_index)) {
+ /* The page is already visible: nothing to do. */
+ return;
+ }
+ user_addr = (void *) NaClUserToSys(nap, nap->dynamic_text_start
+ + page_index * NACL_MAP_PAGESIZE);
+
+ /* Sanity check: Ensure the page is not already in use. */
+ CHECK(*writable_addr == 0);
+
+ NaClFillMemoryRegionWithHalt(writable_addr, NACL_MAP_PAGESIZE);
+
+ if (NaCl_mprotect(user_addr, NACL_MAP_PAGESIZE, PROT_READ | PROT_EXEC) != 0) {
+ NaClLog(LOG_FATAL, "MakeDynamicCodePageVisible: NaCl_mprotect() failed\n");
+ }
+
+ BitmapSetBit(nap->dynamic_page_bitmap, page_index);
+}
+
/*
* Maps a writable version of the code at [offset, offset+size) and returns a
* pointer to the new mapping. Internally caches the last mapping between
@@ -551,6 +592,10 @@ static uintptr_t CachedMapWritableText(struct NaClApp *nap,
* update that cached version
*/
if (size > 0) {
+ uint32_t page_index;
+ uint32_t end_page_index;
+ uint8_t *writable_addr;
+
uintptr_t mapping = (*((struct NaClDescVtbl const *)
shm->base.vtbl)->
Map)(shm,
@@ -563,6 +608,16 @@ static uintptr_t CachedMapWritableText(struct NaClApp *nap,
if (NaClPtrIsNegErrno(&mapping)) {
return 0;
}
+
+ writable_addr = (uint8_t *) mapping;
+ end_page_index = (offset + size) / NACL_MAP_PAGESIZE;
+ for (page_index = offset / NACL_MAP_PAGESIZE;
+ page_index < end_page_index;
+ page_index++) {
+ MakeDynamicCodePageVisible(nap, page_index, writable_addr);
+ writable_addr += NACL_MAP_PAGESIZE;
+ }
+
nap->dynamic_mapcache_offset = offset;
nap->dynamic_mapcache_size = size;
nap->dynamic_mapcache_ret = mapping;
« no previous file with comments | « src/native_client/src/trusted/desc/nacl_desc_imc_shm.c ('k') | src/native_client/src/trusted/service_runtime/sel_addrspace.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698