2009-02-20 3 views
1

Я подумывал попробовать себя в какой-то jit compilataion (только ради обучения), и было бы неплохо, если бы он работал на кросс-платформе, так как я запускаю все основные три дома (windows, os x, linux). Имея это в виду, я хочу знать, есть ли способ отказаться от использования функций окна виртуальной памяти для распределения памяти с разрешениями на выполнение. Было бы неплохо использовать malloc или new и указать процессор на таком блоке.JIT компиляция и DEP

Любые советы?

+0

Что не так с VirtualProtectEx? «Я хочу делать то, что делает VirtualProtectEx, но я не хочу использовать VirtualProtectEx?» А? –

+0

Если вы внимательно прочитаете мой вопрос, вы увидите, что я хотел бы иметь кросс-платформу кода. Это означает, что я не хочу ничего использовать из API окон, если я могу помочь. Единственной платформой, зависящей от объекта, должен быть набор команд x86. – mac

+1

Этого не произойдет. Компиляторы (в отличие от переводчиков) являются специфичными для платформы. Даже в x86 вам приходится иметь дело с вещами, такими как независимый от позиции код в Linux. Не говоря уже о разрешениях на выполнение, которые являются аппаратными, но живут в ОС. –

ответ

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 
+0

Пожалуйста, скажите: как JIT в JavaVM, в Firefox, в Chrome работают на каждом компьютере, даже если включен DEP? – osgx

+1

@osgx, _why_ я бы сделал это, когда вы отправили ответ, который покрывает это в _more_, чем достаточно подробно? Тем не менее, я просто хотел бы упомянуть, что в вопросе конкретно было задано использование функций _standard, не-platform-specific_ с «Я хочу знать, есть ли способ отказаться от использования функций окна виртуальной памяти для выделения памяти с помощью разрешения на выполнение. Было бы неплохо использовать malloc или new и указать процессор на такой блок ». – paxdiablo

5

DEP только отключив разрешение Execution от каждого без кода страницы памяти. Код приложения загружается в память, у которой есть разрешение на выполнение; и есть много JIT, которые работают в Windows/Linux/MacOSX, даже когда DEP активен. Это связано с тем, что существует возможность динамически распределять память с установленными разрешениями.

Обычно обычный malloc нельзя использовать, поскольку разрешения для каждой страницы. Выравнивание malloced памяти на страницах все еще возможно по цене некоторых накладных расходов. Если вы не будете использовать malloc, нестандартное управление памятью (только для исполняемого кода). Настраиваемое управление - это общий способ выполнения JIT.

Существует решение от проекта Chromium, в котором используется JIT для javascript V8 VM и который является кросс-платформенным. Чтобы быть кросс-платформенным, необходимая функция реализована в нескольких файлах, и они выбираются во время компиляции.

Linux: (хром src/v8/src/platform-linux.cc) флаг PROT_EXEC of mmap().

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): флаг PAGE_EXECUTE_READWRITE из 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): флаг это PROT_EXEC mmap, как 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 будет управлять разрешениями памяти мелкомасштабным образом.

+0

Это * правильный * способ сделать это, но в комментарии автора вопроса он заявил: «Я не хочу ничего использовать из API окон», поэтому подход на основе стека. – Gigi

+0

Или добавление уровня POSIX (SFU или cygwin) в Windows и выполнение этого в POSIX API. – osgx