Discussion:
[Rpcemu] NX/XD/DEP patch
J Percival
2018-05-13 22:42:16 UTC
Permalink
I've added support for DEP on Windows and re-done the 'length' calculation
for Linux (mprotect) as it looked wrong to me (potentially including one
too few or one too many pages if I'm not mistaken). I've only tested it on
a Windows10/64-bit host however.

Not sure if the mailing list can handle file attachments so I'll just
copy/paste the diff:

diff -r b0e396f600d9 src/codegen_amd64.c
--- a/src/codegen_amd64.c Sat May 05 21:00:45 2018 +0100
+++ b/src/codegen_amd64.c Sun May 13 23:20:07 2018 +0100
@@ -32,11 +32,7 @@
#include "mem.h"
#include "arm.h"
#include "arm_common.h"
-
-#if defined __linux__ || defined __MACH__
-#include <sys/mman.h>
-#include <unistd.h>
-#endif
+#include "codegen_common.h"

void generateupdatepc(void);
int lastflagchange;
@@ -178,12 +174,7 @@
initcodeblocks(void)
{
int c;
-#if defined __linux__ || defined __MACH__
- void *start;
- size_t len;
- long pagesize = sysconf(_SC_PAGESIZE);
- long pagemask = ~(pagesize - 1);
-#endif
+
/* Clear all blocks */
memset(codeblockpc, 0xff, sizeof(codeblockpc));
memset(blocks, 0xff, sizeof(blocks));
@@ -192,16 +183,9 @@
}
blockpoint = 0;

-#if defined __linux__ || defined __MACH__
/* Set memory pages containing rcodeblock[]s executable -
- necessary when NX/XD feature is active on CPU(s) */
- start = (void *)((long)rcodeblock & pagemask);
- len = (sizeof rcodeblock + pagesize) & pagemask;
- if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
- perror("mprotect");
- exit(1);
- }
-#endif
+ necessary when NX/XD feature is active on CPU(s) */
+ set_memory_executable(rcodeblock, (sizeof rcodeblock)) ;
}

void
diff -r b0e396f600d9 src/codegen_common.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/codegen_common.c Sun May 13 23:20:07 2018 +0100
@@ -0,0 +1,55 @@
+/*
+ RPCEmu - An Acorn system emulator
+
+ Copyright (C) 2005-2010 Sarah Walker
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "codegen_common.h"
+
+#if defined __linux__ || defined __MACH__
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+#if defined WIN32 || defined _WIN32
+#include <windows.h>
+#endif
+
+/* Set memory pages falling within given address range to executable -
+ necessary when NX/XD feature is active on CPU(s) */
+void set_memory_executable(void *ptr, size_t len) // Note: * UNTESTED ON
LINUX AND AMD64 *
+{
+ #if defined __linux__ || defined __MACH__
+ long pagesize = sysconf(_SC_PAGESIZE);
+
+ long offset = ((size_t) ptr) & (pagesize - 1) ; // Offset from
page boundary
+ void *memstart = (void *) (((size_t) ptr) - offset) ; // Start
address aligned with start of page (may be required by implementation of
mprotect)
+ size_t memlen = (offset + len + pagesize - 1) & ~(pagesize - 1);
// Length of memory area (including slack in last page although probably
not required)
+ if (mprotect(memstart, memlen, PROT_READ | PROT_WRITE | PROT_EXEC)
!= 0) {
+ perror("mprotect");
+ exit(1);
+ }
+ #endif
+
+ #if defined WIN32 || defined _WIN32
+ DWORD flOldProtect ;
+ if (VirtualProtect(ptr, len, PAGE_EXECUTE_READWRITE,
&flOldProtect) == 0) {
+ perror("VirtualProtect");
+ exit(1);
+ }
+ #endif
+}
\ No newline at end of file
diff -r b0e396f600d9 src/codegen_common.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/codegen_common.h Sun May 13 23:20:07 2018 +0100
@@ -0,0 +1,23 @@
+/*
+ RPCEmu - An Acorn system emulator
+
+ Copyright (C) 2005-2010 Sarah Walker
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stddef.h>
+
+void set_memory_executable(void *memstart, size_t len) ;
\ No newline at end of file
diff -r b0e396f600d9 src/codegen_x86.c
--- a/src/codegen_x86.c Sat May 05 21:00:45 2018 +0100
+++ b/src/codegen_x86.c Sun May 13 23:20:07 2018 +0100
@@ -30,11 +30,7 @@
#include "mem.h"
#include "arm.h"
#include "arm_common.h"
-
-#if defined __linux__ || defined __MACH__
-#include <sys/mman.h>
-#include <unistd.h>
-#endif
+#include "codegen_common.h"

void generateupdatepc(void);
int linecyc;
@@ -115,12 +111,7 @@
initcodeblocks(void)
{
int c;
-#if defined __linux__ || defined __MACH__
- void *start;
- size_t len;
- long pagesize = sysconf(_SC_PAGESIZE);
- long pagemask = ~(pagesize - 1);
-#endif
+
/* Clear all blocks */
memset(codeblockpc, 0xff, sizeof(codeblockpc));
memset(blocks, 0xff, sizeof(blocks));
@@ -137,16 +128,9 @@
lahftablesub[c]=lahftable[c]^0x20;
}

-#if defined __linux__ || defined __MACH__
/* Set memory pages containing rcodeblock[]s executable -
- necessary when NX/XD feature is active on CPU(s) */
- start = (void *)((long)rcodeblock & pagemask);
- len = (sizeof rcodeblock + pagesize) & pagemask;
- if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
- perror("mprotect");
- exit(1);
- }
-#endif
+ necessary when NX/XD feature is active on CPU(s) */
+ set_memory_executable(rcodeblock, (sizeof rcodeblock)) ;
}

void
diff -r b0e396f600d9 src/qt5/rpcemu.pro
--- a/src/qt5/rpcemu.pro Sat May 05 21:00:45 2018 +0100
+++ b/src/qt5/rpcemu.pro Sun May 13 23:20:07 2018 +0100
@@ -1,6 +1,6 @@
# http://doc.qt.io/qt-5/qmake-tutorial.html

-CONFIG += debug_and_release
+CONFIG += debug_and_release dynarec


QT += core widgets gui multimedia
@@ -92,9 +92,11 @@
DESTDIR = ../..

CONFIG(dynarec) {
- SOURCES += ../ArmDynarec.c
+ SOURCES += ../ArmDynarec.c \
+ ../codegen_common.c
HEADERS += ../ArmDynarecOps.h \
- ../codegen_x86_common.h
+ ../codegen_x86_common.h \
+ ../codegen_common.h

contains(QMAKE_HOST.arch, x86_64):!win32: { # win32 always uses 32bit
dynarec
HEADERS += ../codegen_amd64.h

Loading...