Question

Je pensais à essayer ma main à un compilataion jit (juste pour le plaisir de l'apprentissage) et il serait agréable de le faire fonctionner la plate-forme cross depuis que je cours tous les trois grands à la maison (fenêtres, os x, linux) . Avec cela à l'esprit, je veux savoir s'il y a un moyen de sortir de l'utilisation des fenêtres de mémoire virtuelle fonctions pour allouer de la mémoire avec des autorisations d'exécution. Ce serait bien d'utiliser juste malloc ou nouvelle et pointer le processeur à un tel bloc.

Des conseils?

Était-ce utile?

La solution

Il est possible d'en faire une exigence que les installations de Windows en cours d'exécution de votre programme pour être soit configuré DEP AlwaysOff (mauvaise idée) ou DEP OptOut (meilleure idée).

Cela peut être configuré (sous SP1 + SP2 + WinXp et Win2k3 au moins) en modifiant le fichier boot.ini pour avoir le paramètre:

/noexecute=OptOut

puis configurer votre programme individuel d'opter par le choix (sous XP):

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

Cela devrait vous permettre d'exécuter du code à partir de votre programme qui est créé à la volée dans des blocs de malloc().

Gardez à l'esprit que cela rend votre programme plus sensible aux attaques du DEP vise à prévenir.

Il ressemble à ceci est également possible dans Windows 2008 avec la commande:

bcdedit.exe /set {current} nx OptOut

Mais, pour être honnête, si vous voulez juste pour minimiser le code dépendant de la plate-forme, qui est facile à faire juste en isolant le code en une seule fonction, quelque chose comme:

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
}

Si vous mettez toutes vos fonctions dépendant de la plate-forme dans leurs propres fichiers, le reste de votre code est automatiquement plate-forme agnostique.

Autres conseils

DEP est juste en train de l'autorisation d'exécution de chaque page non code de mémoire. Le code d'application est chargée dans la mémoire qui a la permission d'exécution; et il y a beaucoup de JIT qui fonctionne sous Windows / Linux / MacOSX, même lorsque DEP est activé. En effet, il existe un moyen d'allouer dynamiquement la mémoire avec l'ensemble des autorisations nécessaires.

En général, malloc ordinaire ne doit pas être utilisé, car les autorisations sont par page. Alignement de la mémoire malloced aux pages est encore possible au prix de certains frais généraux. Si vous n'utilisez malloc, une gestion de la mémoire personnalisée (uniquement pour le code exécutable). gestion personnalisée est une façon courante de faire JIT.

Il existe une solution de projet Chrome, qui utilise JIT pour javascript V8 VM et qui est multi-plateforme. Pour être multi-plateforme, la fonction nécessaire est mis en œuvre dans plusieurs fichiers et ils sont choisis au moment de la compilation.

Linux: (chrome src / v8 / src / platform-linux.cc) flag est 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 est 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): drapeau est PROT_EXEC de mmap, comme Linux ou autre 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;
}

Et je veux aussi noter, cette façon de bcdedit.exe comme doit être utilisé que pour les programmes très anciens, ce qui crée un nouveau code exécutable dans la mémoire, mais ne met pas une propriété Exec sur cette page. Pour les nouveaux programmes, comme Firefox ou Chrome / chrome, ou tout JIT moderne, DEP doit être actif et JIT gérer les autorisations de mémoire de manière à grains fins.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top