Tralasciando il backend bytecode tchrist già coperto e solo parlando della C
backend, tutte perlcc
non fa altro che tradurre l'optree del vostro programma Perl compilato in un programma C, che poi compila. Quel programma C, quando verrà eseguito, ricostruirà quell'opzione in memoria e fondamentalmente lo eseguirà come perl solito. Il punto è proprio quello di velocizzare il tempo di compilazione del normale codice perl.
Tale opzione del programma è quindi disponibile nella variabile globale PL_main_root
. Abbiamo già un modulo chiamato B::Deparse
, che è in grado di consumare optrees e trasformarli in un codice sorgente che è approssimativamente equivalente al codice originale da cui è stato compilato l'optree. Capita di avere un metodo compile
che restituisce un codice sorgente che, una volta eseguito, stamperà il risultato depravato di PL_main_root
.
Inoltre c'è la funzione C Perl_eval_pv
, che è possibile utilizzare per valutare i frammenti Perl dallo spazio 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
Naturalmente la solita B :: applicano avvertimenti Deparse, ma questo sarà certamente utile per reverse-engeneering. In realtà, la ricostruzione del codice sorgente originale non sarà possibile nella maggior parte dei casi, anche se ha funzionato per l'esempio precedente.
L'esatta magia di gdb che devi fare per ottenere B :: Deparse per darti qualcosa di sensato dipende anche in gran parte dal tuo perl. Sto usando un perl con gli ithreads e quindi la molteplicità. Ecco perché sto passando la variabile my_perl
. Altri perls potrebbero non aver bisogno di questo.Inoltre, se qualcuno ha eliminato il binario compilato da perlcc, le cose diventeranno un po 'più difficili, ma la stessa tecnica funzionerà ancora.
Inoltre è possibile utilizzarlo per compilare qualsiasi opzione che è possibile ottenere in qualsiasi momento durante l'esecuzione del programma. Dai un'occhiata al sotto compilatore di B :: Deparse e fai qualcosa di simile, tranne forniscilo con un oggetto B
per qualsiasi tipo di optare che vuoi scaricato invece di B::main_root
.
La stessa cosa vale per il backend bytecode di perclcc. Non sono completamente sicuro del backend C ottimizzato chiamato CC
.
Per riferimento, sì, il termine è "reverse engineer"; stai passando da una rappresentazione a bassa astrazione (compilata/codice macchina) a una rappresentazione di astrazione superiore (codice sorgente strutturato). –