<delect id="sj01t"></delect>
  1. <em id="sj01t"><label id="sj01t"></label></em>
  2. <div id="sj01t"></div>
    1. <em id="sj01t"></em>

            <div id="sj01t"></div>
            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

            <delect id="sj01t"></delect>
            1. <em id="sj01t"><label id="sj01t"></label></em>
            2. <div id="sj01t"></div>
              1. <em id="sj01t"></em>

                      <div id="sj01t"></div>
                      黄色视频在线观看