2009-02-20 56 views
1

我正在考虑尝试我的手在一些JIT compilataion(只是为了学习),它会很高兴让它跨平台工作,因为我在家里运行所有主要的三个(Windows,操作系统x,linux)。有鉴于此,我想知道是否有任何方法摆脱使用虚拟内存窗口函数来分配具有执行权限的内存。只要使用malloc或new并将处理器指向这样的块就会很好。JIT编译和DEP

任何提示?

+0

VirtualProtectEx有什么问题? “我想要做什么VirtualProtectEx,但我不想使用VirtualProtectEx?”咦? – 2009-02-20 18:25:37

+0

如果您仔细阅读我的问题,您会看到我想让代码跨平台。这意味着我不想使用Windows API中的任何东西,只要我能帮到它。唯一的平台依赖的东西应该最好是x86指令集。 – mac 2009-02-20 19:34:53

+1

这只是不会发生。编译器(而不是解释器)是特定于平台的。即使在x86中,你也必须在Linux中处理像位置无关的代码。更不用提执行权限,这是硬件辅助的,但是居住在操作系统中。 – 2009-02-20 19:43:43

回答

0

其中一种可能性是要求运行程序的Windows安装要么配置为DEP AlwaysOff(坏主意)或DEP OptOut(更好的主意)。

这可以(在WinXp下SP2 +和WIN2K3 SP1 +至少),通过改变boot.ini文件有设置进行配置:

/noexecute=OptOut 

,然后配置您的个性化方案,通过选择退出(下XP):

Start button 
    Control Panel 
     System 
      Advanced tab 
       Performance Settings button 
        Data Execution Prevention tab 

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

请记住,这会让您的程序更容易受到DEP旨在防止的攻击的影响。

它看起来像这样,也可以在Windows 2008上使用命令:

bcdedit.exe /set {current} nx OptOut 
5

DEP是刚刚从内存每个非代码页关闭执行权限。应用程序代码被加载到具有执行权限的内存中;并且在Windows/Linux/MacOSX中有很多JIT,即使在DEP处于活动状态时也是如此。这是因为有一种方法可以根据需要设置权限来动态分配内存。

通常,不应使用普通的malloc,因为权限是每页。在某些开销的情况下,仍然可以将malloced内存与页面对齐。如果你不会使用malloc,一些自定义内存管理(仅限于可执行代码)。定制管理是进行JIT的常用方式。

有一个来自Chromium项目的解决方案,它使用JIT for javascript V8 VM,并且它是跨平台的。为了实现跨平台,所需的功能在多个文件中实现,并在编译时选择。 Linux(铬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

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)的PAGE_EXECUTE_READWRITE:旗是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将以细粒度的方式管理内存许可。