<address id="ousso"></address>
<form id="ousso"><track id="ousso"><big id="ousso"></big></track></form>
  1. php語言

    php內核分析之opcode

    時間:2025-02-15 00:07:53 php語言 我要投稿
    • 相關推薦

    php內核分析之opcode

      在做PHP項目之前首先要對所運用的知識了解,下面是百分網小編精心為大家整理的php內核分析之opcode,希望對有需要的人有幫助,更多內容請關注應屆畢業生網!

      這里閱讀的php版本為PHP-7.1.0 RC3,閱讀代碼的平臺為linux

      查看opcode

      php是先把源碼解析成opcode,然后再把opcode傳遞給zend_vm進行執行的。

      // 一個opcode的結構

      struct _zend_op {

      const void *handler; // opcode對應的執行函數,每個opcode都有一個對應的執行函數

      znode_op op1; // 執行參數的第一個元素

      znode_op op2; // 執行參數的第二個元素

      znode_op result; // 執行結果

      uint32_t extended_value; // 額外擴展的字段和值

      uint32_t lineno; // 行數

      zend_uchar opcode; // 操作碼,具體操作碼列表見 http://cn.php.net/manual/zh/internals2.opcodes.php

      zend_uchar op1_type; // 第一個元素的類型

      zend_uchar op2_type; // 第二個元素的類型

      zend_uchar result_type; // 結果的類型

      };

      在php7中,我們能很方便用phpdbg來查看一個文件或者一個函數的'opcode了。至于phpdbg的使用,現在網上介紹不多,不過好在有很詳細的help文檔。下面是一個最簡單的opcode代碼:

      $ bin/phpdbg -f /home/xiaoju/software/php7/demo/echo.php

      prompt> list 100

      00001:

      00002:

      00003: $a = 1;

      00004: $b = $a;

      00005: $b = $b + 1;

      00006: echo $b;

      00007:

      prompt> print exec

      [Context /home/xiaoju/software/php7/demo/echo.php (6 ops)]

      L1-7 {main}() /home/xiaoju/software/php7/demo/echo.php - 0x7fe3fae63300 + 6 ops

      L3 #0 ASSIGN $a 1

      L4 #1 ASSIGN $b $a

      L5 #2 ADD $b 1 ~2

      L5 #3 ASSIGN $b ~2

      L6 #4 ECHO $b

      L7 #5 RETURN 1

      這個php文件就做了一個最簡單的加法操作。生成了6個_zend_op。所展示的每一行代表一個_zend_op

      _zendop.lineno op號 _zend_op.opcode _zend_op.op1 _zend_op.op2 _zend_op.result

      L5 #2 ADD $b 1 ~2

      這里_zend_op.opcode對應的操作在網有文檔和詳細的例子可以查看:http://cn.php.net/manual/zh/internals2.opcodes.php

      值得一說的是,phpdbg還有一個遠端UI版本,能讓我們在近端診斷服務端的php信息

      gdb

      但是我們的目標還是在于研究php源碼,phpdbg只能分析到opcode這層,還是不夠的,gdb可能是更好的選擇。

      gdb的使用和平時使用差不多

      比如我現在有個腳本echo.php:

      1

      2

      3 $a = 1;

      4 $b = $a;

      5 $b = $b + 1;

      6 echo $b;

      我的php安裝路徑在:

      /home/xiaoju/software/php7/bin/php

      php源碼路徑在:

      /home/xiaoju/webroot/php-src/php-src-master/

      運行gdb

      $ gdb /home/xiaoju/software/php7/bin/php

      加載gdbinit:

      (gdb) source /home/xiaoju/webroot/php-src/php-src-master/.gdbinit

      設置斷點:

      (gdb) b zend_execute_scripts

      運行:

      (gdb) run -f /home/xiaoju/software/php7/demo/echo.php

      我想在1459這行設置個斷點:

      1452 for (i = 0; i < file_count; i++) {

      1453 file_handle = va_arg(files, zend_file_handle *);

      1454 if (!file_handle) {

      1455 continue;

      1456 }

      1457

      1458 op_array = zend_compile_file(file_handle, type);

      1459 if (file_handle->opened_path) {

      1460 zend_hash_add_empty_element(&EG(included_files), file_handle->opened_path);

      1461 }

      (gdb) b 1459

      繼續跑

      (gdb) continue

      (gdb) s

      (gdb) s

      打印出這個時候的op_array

      (gdb) p *op_array

      $4 = {type = 2 '02', arg_flags = "0000", fn_flags = 134217728, function_name = 0x0, scope = 0x0,

      prototype = 0x0, num_args = 0, required_num_args = 0, arg_info = 0x0, refcount = 0x7ffff6002000, last = 6,

      opcodes = 0x7ffff6076240, last_var = 2, T = 4, vars = 0x7ffff6079030, last_live_range = 0, last_try_catch = 0,

      live_range = 0x0, try_catch_array = 0x0, static_variables = 0x0, filename = 0x7ffff605c2d0, line_start = 1,

      line_end = 7, doc_comment = 0x0, early_binding = 4294967295, last_literal = 3, literals = 0x7ffff60030c0,

      cache_size = 0, run_time_cache = 0x0, reserved = {0x0, 0x0, 0x0, 0x0}}

      我可以優化輸出:

      (gdb) set print pretty on

      (gdb) p *op_array

      $5 = {

      type = 2 '02',

      arg_flags = "0000",

      fn_flags = 134217728,

      function_name = 0x0,

      scope = 0x0,

      prototype = 0x0,

      num_args = 0,

      required_num_args = 0,

      arg_info = 0x0,

      refcount = 0x7ffff6002000,

      last = 6,

      opcodes = 0x7ffff6076240,

      last_var = 2,

      T = 4,

      vars = 0x7ffff6079030,

      last_live_range = 0,

      last_try_catch = 0,

      live_range = 0x0,

      try_catch_array = 0x0,

      static_variables = 0x0,

      filename = 0x7ffff605c2d0,

      line_start = 1,

      line_end = 7,

      doc_comment = 0x0,

      early_binding = 4294967295,

      last_literal = 3,

      literals = 0x7ffff60030c0,

      cache_size = 0,

      run_time_cache = 0x0,

      reserved = {0x0, 0x0, 0x0, 0x0}

      }

      我想打出op_array.filename.val的具體值

      (gdb) p (op_array.filename.len)

      $12 = 40

      (gdb) p *(op_array.filename.val)@40

      $13 = "/home/xiaoju/software/php7/demo/echo.php"

      好了,我們可以順便研究下_zend_op_array這個結構:

      // opcode組成的'數組,編譯的時候就是生成這個結構

      struct _zend_op_array {

      zend_uchar type; // op array的類型,比如 ZEND_EVAL_CODE

      zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */

      uint32_t fn_flags;

      zend_string *function_name;

      zend_class_entry *scope;

      zend_function *prototype;

      uint32_t num_args; // 腳本的參數

      uint32_t required_num_args;

      zend_arg_info *arg_info;

      /* END of common elements */

      uint32_t *refcount; // 這個結構的引用次數

      uint32_t last; // opcode的個數

      zend_op *opcodes; // 存儲所有的opcode

      int last_var; // php變量的個數

      uint32_t T;

      zend_string **vars; // 被編譯的php變量的個數

      int last_live_range;

      int last_try_catch; // try_catch的個數

      zend_live_range *live_range;

      zend_try_catch_element *try_catch_array; //

      /* static variables support */

      HashTable *static_variables; // 靜態變量

      zend_string *filename; // 執行的腳本的文件

      uint32_t line_start; // 開始于第幾行

      uint32_t line_end; // 結束于第幾行

      zend_string *doc_comment; // 文檔的注釋

      uint32_t early_binding; /* the linked list of delayed declarations */

      int last_literal;

      zval *literals;

      int cache_size;

      void **run_time_cache;

      void *reserved[ZEND_MAX_RESERVED_RESOURCES]; // 保留字段

      };

    【php內核分析之opcode】相關文章:

    php內核分析之zval05-07

    php內核分析之擴展01-31

    php內核分析之zend-compile05-17

    php內核分析之do-cli05-30

    php內核分析之全局變量12-14

    php內核分析之sapi-module-struct05-23

    php內核分析之ZTS和zend-try07-18

    php學習之php配置07-15

    php學習之php預定義變量07-29

    <address id="ousso"></address>
    <form id="ousso"><track id="ousso"><big id="ousso"></big></track></form>
    1. 日日做夜狠狠爱欧美黑人