как код операции PHP связан с фактически исполняемым двоичным кодом?

test.php в виде обычного текста:

<?php
$x = "a";
echo $x;

test.php в качестве кода операции:

debian:~ php -d vld.active=1 -d vld.execute=0 -f test.php

Finding entry points
Branch analysis from position: 0
Return found
filename:       /root/test.php
function name:  (null)
number of ops:  5
compiled vars:  !0 = $x
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   2     0  >   EXT_STMT
         1      ASSIGN                                                   !0, 'a'
   3     2      EXT_STMT
         3      ECHO                                                     !0
   4     4    > RETURN                                                   1

branch: #  0; line:     2-    4; sop:     0; eop:     4
path #1: 0,

test.php в виде двоичного представления:

debian:~ php -d apc.stat=0 -r "
  require '/root/test.php'; 
  echo PHP_EOL; 
  echo chunk_split(bin2hex(
    apc_bin_dump(array('/root/test.php'))
  ),64);
"

(пропуская вывод эха test.php)

    b110000001000000325dedaa64d801bca2f73027abf0d5ab67f3023901000000
    2c0000000a000000871000000300000000000000000000004c0000005b000000
    8a0200008a020000650000002f726f6f742f746573742e7068700002070f9c00
    00000000000000000000000000000000000000000000000000000000000100fa
    000000fe00000005000000050000007c02000001000000100000000100000000
    00000000000000ffffffff0000000000000000000000000000000000000000ff
    ffffffeb00000000000000000000000000000000000000ffffffff0000000000
    00000001000000000000002f726f6f742f746573742e7068700001000000204a
    3308080000000000000000000000000000000000000008000000000000000000
    0000000000000000000008000000000000000000000000000000000000000000
    00000200000065000000204a3308040000000000000001000000000000000000
    00001000000000000000100000000100000006000000010000007a0200000100
    00000100000006000000000000000200000026000000204a3308080000000000
    0000000000000000000000000000080000000000000000000000000000000000
    0000080000000000000000000000000000000000000000000000030000006500
    0000900f34080800000000000000000000000000000000000000100000000000
    0000100000000100000006000000080000000000000000000000000000000000
    0000000000000300000028000000204a33080800000000000000000000000000
    00000000000001000000010000002c70d7b6010000000100d7b6080000000000
    000000000000000000000000000000000000040000003e000000610088020000
    01000000bd795900780000000000000000000000000000000000000000000000
[ ... a lot of lines just containing 0s ... ]
    0000000000000038000000c30000007f0000007a010000830000007c0200008f
    0000003c000000400000004400000008

Теперь я хочу узнать больше о том, как код операции преобразуется в двоичное представление.

Отредактированный и уточненный вопрос:

Как код операции транслируется в двоичную версию? Вы видите там НАЗНАЧЕНИЕ 'a' на !0? Есть ли где-нибудь оператор ECHO и что он выводит?

Я нашел несколько шаблонов в двоичной версии, которые намекают на построчное представление кода операции.

(«2f726f6f742f746573742e706870» — это шестнадцатеричное представление «/root/test.php»)

ИЗМЕНИТЬ:

шестнадцатеричное представление выявляет шаблоны, когда длина строки установлена ​​​​на 4 байта и сравнивается между разными программами.

...
00000002  // 2 seems to be something like the "line number"
00000065  // seems to increase by 1 for every subsequent statement.
00000040  // 
06330808  // seems to mark the START of a statement
00000000
00000000
00000000
00000000
00000001  //
00000012  // In a program with three echo statements,
03000007  // this block was present three times. With mild
00000001  // changes that seem to represent the spot where
00000006  // the output-string is located.
00000008  //
00000000
00000000
00000000
00000000
00000000
00000002  // 2 seems to be something like the "line number"
00000028  //
00000020  //
4a330808  // seems to mark the END of a statement
00000000
00000000
00000000
00000000
00000008  // repeating between (echo-)statements
00000000
00000000
00000000
00000000
00000008  // repeating between (echo-)statements
...

Но мои знания о том, как работают виртуальные машины на таком уровне, слишком слабы, чтобы действительно правильно проанализировать это и связать с кодом C.

ИЗМЕНИТЬ:

Есть ли в PHP виртуальная машина, такая как Java?

Можно ли встраивать движок Zend вне PHP?


person Raffael    schedule 01.12.2011    source источник


Ответы (2)


Отличный вопрос...

ОБНОВЛЕНИЕ: коды операций выполняются непосредственно виртуальной машиной PHP (движок Zend). Похоже, что они выполняются разными функциями-обработчиками, определенными в ./Zend/zend_vm_execute.h.

Дополнительную информацию см. в архитектуре Zend Engine. о том, как выполняются коды операций Zend.

Эти ресурсы могут немного помочь:

http://php.net/manual/en/internals2.opcodes.list.php

http://www.php.net/manual/en/internals2.opcodes.ops.php

Кроме того, я собираюсь проверить источник PECL VLD для получения дополнительных подсказок ...

http://pecl.php.net/package/vld

http://derickrethans.nl/projects.html#vld

Также может помочь написание авторов расширения VLD Pecl: Дерика Ретанса, Андрея Змиевского или Маркуса Бёргера.

Их адреса электронной почты находятся вверху srm_oparray.c в источнике расширения.

ОБНОВЛЕНИЕ: нашел еще несколько подсказок

В PHP 5.3.8 я нашел три указания на то, где выполняются коды операций:

./Zend/zend_execute.c:1270 
ZEND_API void execute_internal

./Zend/zend.c:1214:ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, int file_count, ...)
./Zend/zend.c:1236:                  zend_execute(EG(active_op_array) TSRMLS_CC);

./Zend/zend_vm_gen.php

Я не смог найти определение для zend_execute(), но я предполагаю, что оно может быть сгенерировано с помощью ./zend_vm_gen.php

Кажется, я нашел это...

./Zend/zend_vm_execute.h:42
ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)

Я могу ошибаться, но похоже, что все обработчики кода операции также определены в ./Zend/zend_vm_execute.h.

См. ./Zend/zend_vm_execute.h:2413 для примера того, что выглядит как код операции «целочисленное сложение».

person Homer6    schedule 01.12.2011
comment
уже проверил эти ресурсы; как я использую VLD выше. Кажется, они просто охватывают переход от кода PHP к коду операции. - person Raffael; 01.12.2011
comment
Обновлено... добавлено предложение адреса электронной почты. - person Homer6; 01.12.2011
comment
Итак, вы уже проверили исходный код? Это точно куда-нибудь приведет. Но я не знаком с C, это мой недостаток. Все, что я нашел до сих пор, это то, что T_ECHO присвоен номер 316. - person Raffael; 01.12.2011
comment
Вы смотрели исходный код PHP: ./Zend/README.ZEND_VM - person Homer6; 01.12.2011
comment
Эти файлы выглядят многообещающе... ./Zend/zend_vm_opcodes.h ./Zend/zend_vm_def.h - person Homer6; 01.12.2011
comment
Обновление: нашел еще несколько подсказок в исходниках PHP. - person Homer6; 02.12.2011
comment
Обновление: найдены определения функций обработчика кода операции Zend VM. - person Homer6; 02.12.2011
comment
выглядит очень интересно! но я пока не вижу связи между опкодом и бинарной версией. Однако это ничего не значит, поскольку я в принципе понятия не имею, как эти виртуальные машины работают на таком уровне. - person Raffael; 02.12.2011
comment
Насколько я понимаю, бинарной версии нет. Виртуальная машина напрямую выполняет каждую инструкцию, закодированную как код операции Zend. - person Homer6; 02.12.2011
comment
Zend VM является частью ZE. - person Homer6; 02.12.2011

apc_bin_dump() возвращает необработанное представление записи кэша в памяти.

Он возвращает содержимое apc_bd_t struct< /а>.

Эта структура представляет собой массив apc_bd_entry_t с некоторыми контрольными суммами для обнаружения ошибок.

apc_bd_entry_t содержит apc_cache_entry_value_t.

Вы можете просмотреть apc_bin_dump. и внутренние функции apc_bin_load для посмотрите, как делаются дамп и загрузка.

person Arnaud Le Blanc    schedule 02.12.2011