En quittant le backend bytecode tchrist déjà couvert et ne parle que du back-end C
, tous perlcc
ne traduit le optree de votre programme Perl compilé dans un programme C, qu'il compile ensuite. Ce programme C, lorsqu'il est exécuté, reconstruit alors cette optree en mémoire, et l'exécute fondamentalement comme le ferait habituellement Perl. Le but de cela est vraiment d'accélérer le temps de compilation du code perl normal.
Cette optrée de votre programme est alors disponible dans la variable globale PL_main_root
. Nous avons déjà un module appelé B::Deparse
, qui est capable de consommer optrees et de les transformer en code source qui est à peu près équivalent au code original à partir duquel l'optree a été compilé. Il arrive d'avoir une méthode compile
qui retourne un coderef qui, lorsqu'il est exécuté, affichera le résultat de départ de PL_main_root
.
Il existe également la fonction C Perl_eval_pv
, que vous pouvez utiliser pour évaluer les fragments Perl à partir de l'espace C.
$ echo 'print 42, "\\n"' > foo.pl
$ perl foo.pl
42
$ perlcc foo.pl
$ ./a.out
42
$ gdb a.out
...
(gdb) b perl_run
Breakpoint 1 at 0x4570e5: file perl.c, line 2213.
(gdb) r
...
Breakpoint 1, perl_run (my_perl=0xa11010) at perl.c:2213
(gdb) p Perl_eval_pv (my_perl, "use B::Deparse; B::Deparse->compile->()", 1)
print 42, "\n";
$1 = (SV *) 0xe47b10
Bien sûr l'habituel B :: mises en garde Deparse appliquent, mais ce sera certainement très pratique pour la marche arrière-engeneering. En fait, la reconstruction du code source original ne sera pas possible dans la plupart des cas, même si cela a fonctionné pour l'exemple ci-dessus. La magie gdb exacte que vous aurez à faire pour obtenir B :: Deparse pour vous donner quelque chose de sensible dépend aussi largement de votre perl. J'utilise un perl avec ithreads, et donc la multiplicité. C'est pourquoi je passe la variable my_perl
. D'autres perls pourraient ne pas avoir besoin de ça.De plus, si quelqu'un supprime le binaire compilé par perlcc, les choses seront un peu plus difficiles, mais la même technique fonctionnera toujours.
Vous pouvez également utiliser cela pour compiler n'importe quelle optrée que vous pouvez obtenir d'une manière ou d'une autre à tout moment pendant l'exécution du programme. Jetez un oeil à B :: Deparse compile sub et faire quelque chose de similaire, sauf lui fournir un objet B
pour tout optree que vous voulez déversé au lieu de B::main_root
.
La même chose s'applique au backend de bytecode de perlcc. Je ne suis pas tout à fait sûr de l'arrière-plan C optimisé appelé CC
.
À des fins de référence, oui, le terme est «reverse engineering»; vous passez d'une représentation à faible abstraction (code compilé/machine) à une représentation à plus haute abstraction (code source structuré). –