首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JIT编译和DEP

JIT编译和DEP
EN

Stack Overflow用户
提问于 2009-02-20 16:32:21
回答 2查看 2.2K关注 0票数 3

我正在考虑尝试一些jit编译(只是为了学习),而且它能跨平台工作是很好的,因为我在家里运行所有三个主要的平台(windows,os x,linux)。考虑到这一点,我想知道是否有任何方法可以避免使用虚拟内存窗口函数来分配具有执行权限的内存。如果只使用malloc或new,并将处理器指向这样的块,那就更好了。

有什么建议吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-04-08 02:53:34

一种可能是要求运行您的程序的Windows安装要么配置为DEP AlwaysOff (糟糕的想法),要么配置为DEP OptOut (更好的想法)。

这可以通过将boot.ini文件更改为以下设置来配置(至少在WinXp SP2+和Win2k3 SP1+下):

代码语言:javascript
复制
/noexecute=OptOut

然后通过选择(在XP下)来配置您的个人程序以选择退出:

代码语言:javascript
复制
Start button
    Control Panel
        System
            Advanced tab
                Performance Settings button
                    Data Execution Prevention tab

这应该允许您从程序中执行在malloc()块中动态创建的代码。

请记住,这会使您的程序更容易受到DEP本应防止的攻击。

在Windows 2008中,使用以下命令也可以做到这一点:

代码语言:javascript
复制
bcdedit.exe /set {current} nx OptOut

但是,老实说,如果您只是想最小化与平台相关的代码,那么只需将代码隔离到单个函数中就很容易做到,例如:

代码语言:javascript
复制
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
}

如果您将所有与平台相关的函数放在它们自己的文件中,则其余代码将自动与平台无关。

票数 0
EN

Stack Overflow用户

发布于 2012-02-08 10:22:13

DEP只是关闭了内存的每个非代码页的执行权限。应用程序的代码被加载到有执行权限的内存中,即使在DEP激活的情况下,也有大量的JIT可以在Windows/Linux/MacOSX上运行。这是因为有一种方法可以动态分配设置了所需权限的内存。

通常,不应该使用普通的malloc,因为权限是按页计算的。将错误分配的内存与页面对齐仍然是可能的,代价是一些开销。如果您不打算使用malloc,可以使用一些自定义内存管理(仅适用于可执行代码)。自定义管理是执行JIT的一种常见方式。

有一个来自Chromium project的解决方案,它将JIT用于javascript V8 VM,并且是跨平台的。为了跨平台,所需的功能在几个文件中实现,并在编译时选择它们。

Linux:(chromium src/v8/src/platform-linux.cc)标志是mmap()的PROT_EXEC。

代码语言:javascript
复制
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;
}

平台(src/v8/src/ Win32 -win32.cc):PAGE_EXECUTE_READWRITE是VirtualAlloc的标志

代码语言:javascript
复制
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):PROT_EXEC是mmap的标志,就像Linux或其他posix一样。

代码语言:javascript
复制
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-like方法应该仅用于非常旧的程序,它在内存中创建新的可执行代码,但不在此页上设置Exec属性。对于较新的程序,如firefox或Chrome/Chromium,或任何现代的JIT,DEP应该是活动的,JIT将以细粒度的方式管理内存权限。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/570257

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档