我正在考虑尝试一些jit compilataion(仅仅是为了学习)而且让它在跨平台工作会很好,因为我在家里运行所有主要的三个(windows,os x,linux) 。 考虑到这一点,我想知道是否有任何方法可以摆脱使用虚拟内存窗口函数来分配具有执行权限的内存。很高兴只使用malloc或new并将处理器指向这样的块。
任何提示?
答案 0 :(得分:9)
DEP只是关闭内存的每个非代码页的执行权限。应用程序代码被加载到具有执行权限的内存中;即使DEP处于活动状态,也有很多JIT可以在Windows / Linux / MacOSX中运行。这是因为有一种方法可以动态分配具有所需权限集的内存。
通常,不应使用普通malloc,因为权限是每页的。将malloced内存与页面对齐仍然可能以一些开销为代价。如果你不使用malloc,一些自定义内存管理(仅适用于可执行代码)。自定义管理是执行JIT的常用方法。
Chromium项目有一个解决方案,它使用JIT for javascript V8 VM,它是跨平台的。为了跨平台,所需的功能在几个文件中实现,并在编译时选择它们。
Linux:(chromium src / v8 / src / platform-linux.cc)标志是mmap()的PROT_EXEC。
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
const size_t msize = RoundUp(requested, AllocateAlignment());
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* addr = OS::GetRandomMmapAddr();
void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mbase == MAP_FAILED) {
/** handle error */
return NULL;
}
*allocated = msize;
UpdateAllocatedSpaceLimits(mbase, msize);
return mbase;
}
Win32(src / v8 / src / platform-win32.cc):标志是VirtualAlloc的PAGE_EXECUTE_READWRITE
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
// The address range used to randomize RWX allocations in OS::Allocate
// Try not to map pages into the default range that windows loads DLLs
// Use a multiple of 64k to prevent committing unused memory.
// Note: This does not guarantee RWX regions will be within the
// range kAllocationRandomAddressMin to kAllocationRandomAddressMax
#ifdef V8_HOST_ARCH_64_BIT
static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
#else
static const intptr_t kAllocationRandomAddressMin = 0x04000000;
static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
#endif
// VirtualAlloc rounds allocated size to page size automatically.
size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
intptr_t address = 0;
// Windows XP SP2 allows Data Excution Prevention (DEP).
int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
// For exectutable pages try and randomize the allocation address
if (prot == PAGE_EXECUTE_READWRITE &&
msize >= static_cast<size_t>(Page::kPageSize)) {
address = (V8::RandomPrivate(Isolate::Current()) << kPageSizeBits)
| kAllocationRandomAddressMin;
address &= kAllocationRandomAddressMax;
}
LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address),
msize,
MEM_COMMIT | MEM_RESERVE,
prot);
if (mbase == NULL && address != 0)
mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);
if (mbase == NULL) {
LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed"));
return NULL;
}
ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));
*allocated = msize;
UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize));
return mbase;
}
MacOS(src / v8 / src / platform-macos.cc):flag是mmap的PROT_EXEC,就像Linux或其他posix一样。
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
const size_t msize = RoundUp(requested, getpagesize());
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* mbase = mmap(OS::GetRandomMmapAddr(),
msize,
prot,
MAP_PRIVATE | MAP_ANON,
kMmapFd,
kMmapFdOffset);
if (mbase == MAP_FAILED) {
LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
UpdateAllocatedSpaceLimits(mbase, msize);
return mbase;
}
我还要注意,bcdedit.exe
- 类似的方式应该仅用于非常旧的程序,它在内存中创建新的可执行代码,但不在此页面上设置Exec属性。对于较新的程序,如firefox或Chrome / Chromium,或任何现代JIT,DEP应该是活动的,JIT将以细粒度的方式管理内存权限。
答案 1 :(得分:-1)
一种可能性是要求运行程序的Windows安装配置为DEP AlwaysOff(坏主意)或DEP OptOut(更好的主意)。
这可以通过更改boot.ini文件来配置(至少在WinXp SP2 +和Win2k3 SP1 +下):
/noexecute=OptOut
然后通过选择(在XP下)将您的个人程序配置为选择退出:
Start button
Control Panel
System
Advanced tab
Performance Settings button
Data Execution Prevention tab
这应该允许您在程序中执行代码,这些代码是在malloc()
块中动态创建的。
请记住,这会使您的程序更容易受到DEP意图阻止的攻击。</ p>
在Windows 2008中看起来也可以使用以下命令:
bcdedit.exe /set {current} nx OptOut
但是,说实话,如果你只是想最大限度地减少与平台相关的代码,只需将代码隔离到一个函数中就可以轻松完成,例如:
void *MallocWithoutDep(size_t sz) {
#if defined _IS_WINDOWS
return VirtualMalloc(sz, OPT_DEP_OFF); // or whatever
#elif defined IS_LINUX
// Do linuxy thing
#elif defined IS_MACOS
// Do something almost certainly inexplicable
#endif
}
如果将所有与平台相关的函数放在自己的文件中,则其余代码将自动与平台无关。