Pergunta

Eu estava pensando em tentar minha mão em algum compilataion jit (apenas por uma questão de aprendizagem) e seria bom tê-lo trabalhar multiplataforma desde que eu executar todos os principais três em casa (Windows, OS X, Linux) . Com isso em mente, eu quero saber se há alguma maneira de sair de usar as funções do Windows memória virtual para alocar memória com permissões de execução. Seria bom para malloc uso justo ou novo e apontar o processador em tal bloco a.

Todas as dicas?

Foi útil?

Solução

Uma possibilidade é torná-lo um requisito que as instalações do Windows executando o seu programa ser ou configurado para DEP AlwaysOff (má idéia) ou DEP OptOut (melhor idéia).

Isso pode ser configurado (no WinXP SP2 + e Win2k3 SP1 +, pelo menos), alterando o arquivo boot.ini para ter a configuração:

/noexecute=OptOut

e, em seguida, configurar o seu programa individual de optar por escolher (no XP):

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

Isso deve permitir que você execute código de dentro do seu programa que é criado na mosca em blocos malloc().

Tenha em mente que isso faz com que o seu programa mais suscetível a ataques que DEP foi destinadas a evitar.

Parece que este também é possível em Windows 2008 com o comando:

bcdedit.exe /set {current} nx OptOut

Mas, para ser honesto, se você quiser apenas para minimizar o código dependente de plataforma, que é fácil de fazer apenas isolando o código em uma única função, algo como:

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
}

Se você colocar todas as funções dependentes a sua plataforma em seus próprios arquivos, o resto do seu código é automaticamente independente de plataforma.

Outras dicas

DEP é apenas desligar permissão de execução de cada página não-código de memória. O código de aplicativo é carregado para a memória que tem permissão de execução; e há grande quantidade de EIC que funciona em Windows / Linux / MacOSX, mesmo quando a DEP está ativo. Isso ocorre porque há uma maneira de alocar dinamicamente memória com permissões necessárias definidas.

Normalmente, malloc simples não deve ser usado, porque as permissões são por página. Alinhando de memória malloced para páginas ainda é possível a preço de alguma sobrecarga. Se você não vai usar malloc, alguns gerenciamento de memória personalizado (somente para código executável). gerenciamento personalizado é uma maneira comum de fazer JIT.

Há uma solução de projeto Chromium, que usa JIT para JavaScript V8 VM e que é multi-plataforma. Para ser multi-plataforma, a função necessária é implementado em vários arquivos e eles são selecionados em tempo de compilação.

Linux:. (Cromo src / v8 / src / platform-linux.cc) flag é PROT_EXEC de 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): flag é PAGE_EXECUTE_READWRITE de 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):. bandeira é PROT_EXEC de mmap, assim como Linux ou outro 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;
}

E eu também quero nota, que bcdedit.exe-como forma deve ser usado apenas para programas muito antigos, o que cria um novo código executável na memória, mas não define uma propriedade Exec nesta página. Para programas mais recentes, como o Firefox ou o Chrome / Chromium, ou qualquer JIT moderno, DEP deve ser ativo, e JIT irá gerenciar permissões de memória em forma de grão fino.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top