2015-08-23 3 views
1

J'essaie d'émuler ce tutoriel (http://blog.reverberate.org/2012/12/hello-jit-world-joy-of-simple-jits.html) pour écrire un simple jit. Je ne suis pas sûr si l'interface python pour mmap supporte le cas d'utilisation suivant. Le code C (en cas de disparition du lien) ressemble à ceci.python mmap pour jit code

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/mman.h> 

int main(int argc, char *argv[]) { 
    // Machine code for: 
    // mov eax, 0 
    // ret 
    unsigned char code[] = {0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3}; 

    if (argc < 2) { 
    fprintf(stderr, "Usage: jit1 <integer>\n"); 
    return 1; 
    } 

    // Overwrite immediate value "0" in the instruction 
    // with the user's value. This will make our code: 
    // mov eax, <user's value> 
    // ret 
    int num = atoi(argv[1]); 
    memcpy(&code[1], &num, 4); 

    // Allocate writable/executable memory. 
    // Note: real programs should not map memory both writable 
    // and executable because it is a security risk. 
    void *mem = mmap(NULL, sizeof(code), PROT_WRITE | PROT_EXEC, 
        MAP_ANON | MAP_PRIVATE, -1, 0); 
    memcpy(mem, code, sizeof(code)); 

    // The function will return the user's value. 
    int (*func)() = mem; 
    return func(); 
} 

Mon code python pour le même ressemble à ceci.

code = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3] 

import mmap 
import ctypes 

size_in_bytes = len(code) * 4 
mem = mmap.mmap(-1, size_in_bytes, prot=mmap.PROT_WRITE | mmap.PROT_EXEC, flags= mmap.MAP_ANON | mmap.MAP_PRIVATE) 
# mmap.mmap.move(mem, ctypes.addressof(code), size_in_bytes) 

mem.write(ctypes.addressof(code), size_in_bytes) 
ftype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p) 

f = ftype(mem) 
f() 

Cependant, l'exécution de cette erreur me donne l'erreur.

Traceback (most recent call last): 
    File "main.py", line 10, in <module> 
    mem.write(ctypes.addressof(code), size_in_bytes) 
TypeError: invalid type 

Alors ma question est de savoir comment obtenir des pages inscriptibles mmap et comment copier les données afin qu'il puisse être jitted. Si ce n'est pas directement accessible depuis python, puis-je utiliser l'interface python c pour utiliser l'implémentation C sous-jacente?

La plupart des interfaces jit que j'ai examinées utilisent llvm ou un autre jit sous-jacent. Mais je ne pouvais pas vraiment comprendre comment PyPy le fait. Des idées ?

Répondre

0

Vous devez convertir votre liste de python à un tableau ctype:

arr = (ctypes.c_int * len(code))(*code) 

Ensuite, la méthode AddressOf fonctionne:

>>ctypes.addressof(arr) 
47651024 
+0

Merci rofls. J'ai essayé avec ce code après avoir ajouté le vôtre. mmap.mmap.move (mem, ctypes.addressof (arr), size_in_bytes) Je reçois l'erreur -> Traceback (dernier appel en dernier): Fichier "main.py", ligne 9, en mmap.mmap .move (mem, ctypes.addressof (arr), size_in_bytes) TypeError: move() prend exactement 3 arguments (2 donnés) – ssarangi

+0

@ssarangi, je l'ai trouvé aussi. Cela fonctionne: 'mem.write (arr)' mais je ne suis pas sûr si c'est ce que vous voulez à ce point ... – rofls

+0

mem.write (arr) fonctionne et mon prochain problème est l'objet mem assigné au pointeur de fonction (ftype) étant assigné comme dans le code C.L'autre chose est de savoir comment Mem.Write comprendre combien d'octets à écrire? – ssarangi

0

j'obtenu ce qui suit à « travailler », en ce sens que la La fonction est appelée.

from __future__ import print_function 
import ctypes 

code = bytes([0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]) 
arr = ctypes.create_string_buffer(code) 

ftype = ctypes.CFUNCTYPE(ctypes.c_int) 
f = ftype(ctypes.addressof(arr)) 
print("Ready to call f()!") 
f() 

Malheureusement, sur mon système d'exploitation (FreeBSD) il en résulte une erreur de segmentation, car les segments de données ne sont pas exécutables.

J'ai donc modifié le code pour incorporer mmap;

from __future__ import print_function 
import ctypes 
import mmap 

code = bytes([0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]) 
ftype = ctypes.CFUNCTYPE(ctypes.c_int) 

mem = mmap.mmap(-1, len(code), prot=mmap.PROT_WRITE | mmap.PROT_EXEC, 
       flags=mmap.MAP_ANON | mmap.MAP_PRIVATE) 
mem.write(code) 
arr = ctypes.create_string_buffer(mem) 

f = ftype(ctypes.addressof(arr)) 
print("Ready to call f()!") 
f() 

Mais cela donne un TypeError:

Traceback (most recent call last): 
    File "jit.py", line 11, in <module> 
    arr = ctypes.create_string_buffer(mem) 
    File "/usr/local/lib/python2.7/ctypes/__init__.py", line 68, in create_string_buffer 
    raise TypeError(init) 
TypeError: <mmap.mmap object at 0x8007cb928> 

Edit: En regardant le code pour create_string_buffer dans ctypes/__init__.py, il accepte que str, unicode, int ou long. La simulation de ce que peut faire create_string_buffer peut aider, mais je n'ai pas le temps d'essayer ça maintenant.

Edit2: Il semble que Python mmap (source code) ne tient pas compte du drapeau PROT_EXEC. Cela expliquerait les erreurs de segmentation.

+0

J'ai essayé les deux approches et j'ai vu les mêmes problèmes sur OSX. J'ai regardé les approches que tous les 3 jits prennent. PyPy est le même que je ne pouvais pas comprendre quant à la façon dont ils jit effectivement bien que je n'ai pas creusé beaucoup dans le code. Numba utilise essentiellement llvm jitter en interne (llvmlite) projet que j'essaie d'éviter. Pyston implémente tout en C++ et j'ai vu l'approche qu'ils adoptent, ce qui est ce que je connais dans l'utilisation de llvm. Je voulais cependant une manière simple d'écrire une gigue directement avec mmap de python au lieu d'avoir à faire un wrapper c pour cela. – ssarangi

+0

@ssarangi J'ai découvert pourquoi 'create_string_buffer' a échoué, voir la réponse éditée. Peut-être que simuler cela aiderait. –

+0

J'ai essayé de le faire .. mem.seek (0) arr = ctypes.create_string_buffer (mem.read (len (code))) .. Donc, après le mem.write (code), nous cherchons au début de la mem et puis passez cela pour lire len (code) octets. Cependant, j'ai toujours la même erreur de bus 10 sur OSX. Semblable à votre exemple précédent où vous avez dit que le segment de données n'était pas exécutable. Est-il donc illégal d'utiliser mmap de python pour retourner de la mémoire exécutable? – ssarangi