@@ -320,22 +320,87 @@ sqInt sqMemoryExtraBytesLeft(sqInt includingSwap) { return uxMemoryExtraBytesL
320320
321321#define roundDownToPage (v ) ((v)&pageMask)
322322#define roundUpToPage (v ) (((v)+pageSize-1)&pageMask)
323+
323324#if COGVM
325+ # if DUAL_MAPPED_CODE_ZONE
326+ /* We are indebted to Chris Wellons who designed this elegant API for dual
327+ * mapping which we depend on for fine-grained code modification (classical
328+ * Deutsch/Schiffman style inline cacheing and derivatives). Chris's code is:
329+ https://nullprogram.com/blog/2016/04/10/
330+ *
331+ * To cope with modern OSs that disallow executing code in writable memory we
332+ * dual-map the code zone, one mapping with read/write permissions and the other
333+ * with read/execute permissions. In such a configuration the code zone has
334+ * already been alloated and is not included in (what is no longer) the initial
335+ * alloc.
336+ */
337+ static void
338+ memory_alias_map (size_t size , size_t naddr , void * * addrs )
339+ {
340+ extern char * exeName ;
341+ char path [128 ];
342+ snprintf (path , sizeof (path ), "/%s(%lu,%p)" ,
343+ exeName ? exeName : __FUNCTION__ , (long )getpid (), addrs );
344+ int fd = shm_open (path , O_RDWR | O_CREAT | O_EXCL , 0600 );
345+ if (fd == -1 ) {
346+ perror ("memory_alias_map: shm_open" );
347+ exit (0666 );
348+ }
349+ shm_unlink (path );
350+ ftruncate (fd , size );
351+ for (size_t i = 0 ; i < naddr ; i ++ ) {
352+ addrs [i ] = mmap (addrs [i ], size , PROT_READ | PROT_WRITE ,
353+ addrs [i ] ? MAP_FIXED | MAP_SHARED : MAP_SHARED ,
354+ fd , 0 );
355+ if (addrs [i ] == MAP_FAILED ) {
356+ perror ("memory_alias_map: mmap(addrs[i]..." );
357+ exit (0667 );
358+ }
359+ }
360+ close (fd );
361+ return ;
362+ }
363+ # endif /* DUAL_MAPPED_CODE_ZONE */
364+
324365void
325- sqMakeMemoryExecutableFromTo (unsigned long startAddr , unsigned long endAddr )
366+ sqMakeMemoryExecutableFromToCodeToDataDelta (usqInt startAddr ,
367+ usqInt endAddr ,
368+ sqInt * codeToDataDelta )
326369{
327- unsigned long firstPage = roundDownToPage (startAddr );
370+ usqInt firstPage = roundDownToPage (startAddr );
371+ usqInt size = endAddr - firstPage ;
372+
373+ # if DUAL_MAPPED_CODE_ZONE
374+ usqInt mappings [2 ];
375+
376+ mappings [0 ] = firstPage ;
377+ mappings [1 ] = 0 ;
378+
379+ memory_alias_map (size , 2 , (void * * )mappings );
380+ assert (mappings [0 ] == firstPage );
381+ * codeToDataDelta = mappings [1 ] - startAddr ;
382+
328383 if (mprotect ((void * )firstPage ,
329- endAddr - firstPage + 1 ,
384+ size ,
385+ PROT_READ | PROT_EXEC ) < 0 )
386+ perror ("mprotect(x,y,PROT_READ | PROT_EXEC)" );
387+
388+ # else /* DUAL_MAPPED_CODE_ZONE */
389+
390+ if (mprotect ((void * )firstPage ,
391+ size ,
330392 PROT_READ | PROT_WRITE | PROT_EXEC ) < 0 )
331393 perror ("mprotect(x,y,PROT_READ | PROT_WRITE | PROT_EXEC)" );
394+
395+ * codeToDataDelta = 0 ;
396+ # endif
332397}
333398
334399void
335- sqMakeMemoryNotExecutableFromTo (unsigned long startAddr , unsigned long endAddr )
400+ sqMakeMemoryNotExecutableFromTo (usqInt startAddr , usqInt endAddr )
336401{
337402# if 0
338- unsigned long firstPage = roundDownToPage (startAddr );
403+ usqInt firstPage = roundDownToPage (startAddr );
339404 /* Arguably this is pointless since allocated memory always does include
340405 * write permission. Annoyingly the mprotect call fails on both linux &
341406 * mac os x. So make the whole thing a nop.
@@ -352,7 +417,8 @@ sqMakeMemoryNotExecutableFromTo(unsigned long startAddr, unsigned long endAddr)
352417
353418# define MBytes *1024*1024
354419
355- int main ()
420+ int
421+ main ()
356422{
357423 char * mem = sqAllocateMemory (4 MBytes , 40 MBytes );
358424 printf ("memory allocated at %p\n" , mem );
0 commit comments