Оставляя в стороне бэк-код бэк-кода, о котором мы уже говорили, и говоря только о бэкэнде C
, все, что делает perlcc
, это переводит optree вашей скомпилированной perl-программы в программу на C, которую затем компилирует. Эта программа на C при запуске затем реконструирует этот optree в память и в основном выполняет его, как обычно это делает perl. Суть в том, чтобы ускорить время компиляции обычного Perl-кода.
Этот optree вашей программы будет доступен в глобальной переменной PL_main_root
. У нас уже есть модуль с именем B::Deparse
, который может использовать optrees и превращать их в исходный код, который примерно эквивалентен исходному коду, из которого скомпилирован optree. Бывает, что есть метод compile
, который возвращает кодовую ссылку, которая при выполнении выдает результат разброса PL_main_root
.
Также есть функция C Perl_eval_pv
, которую вы можете использовать для оценки фрагментов Perl из пространства 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
Конечно, применяются обычные предостережения B :: Deparse, но это, безусловно, будет полезно для реинжиниринга. На самом деле восстановление исходного исходного кода в большинстве случаев будет невозможно, даже если это сработало для приведенного выше примера.
Точная магия GDB, которую вы должны будете сделать, чтобы получить B :: Deparse, чтобы дать вам что-то разумное, также во многом зависит от вашего Perl. Я использую Perl с ithreads, и, следовательно, множественность. Вот почему я передаю переменную my_perl
. Другие perls могут не нуждаться в этом. Кроме того, если кто-то удалит двоичный файл, скомпилированный с помощью perlcc, все станет немного сложнее, но тот же метод будет работать.
Также вы можете использовать это для компиляции любого optree, который вы можете каким-то образом получить в любой момент во время выполнения программы. Посмотрите на скомпилируемую подпрограмму B :: Deparse и сделайте что-то похожее, за исключением того, что предоставьте ей объект B
для любого optree, который вы хотите сбросить вместо B::main_root
.
То же самое относится и к упомянутому бэк-коду байт-кода perlcc. Я не совсем уверен насчет оптимизированного бэкэнда C под названием CC
.