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.phpzend_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: <?php
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 <?php23 $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 '\002', arg_flags = "\000\000", 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 '\002',arg_flags = "\000\000",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_CODEzend_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;  // 存儲所有的opcodeint 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]; // 保留字段
};本文轉自軒脈刃博客園博客,原文鏈接:http://www.cnblogs.com/yjf512/p/6112634.html,如需轉載請自行聯系原作者

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/278659.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/278659.shtml
英文地址,請注明出處:http://en.pswp.cn/news/278659.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vue 監聽路由變化

一.watch監聽$route&#xff08;$router的對象&#xff09; // 監聽,當路由發生變化的時候執行 watch:{$route(to,from){console.log(to.path);} },// 監聽,當路由發生變化的時候執行 watch: {$route: {handler: function(val, oldVal){console.log(val);},// 深度觀察監聽dee…

音頻剪切_音頻編輯入門指南:剪切,修剪和排列

音頻剪切Audacity novices often start with lofty project ideas, but sometimes they lack the basics. Knowing how to cut and trim tracks is basic audio editing and is a fundamental starting point for making more elaborate arrangements. 大膽的新手通常從崇高的項…

Mybatis自定義SQL攔截器

本博客介紹的是繼承Mybatis提供的Interface接口&#xff0c;自定義攔截器&#xff0c;然后將項目中的sql攔截一下&#xff0c;打印到控制臺。 先自定義一個攔截器 package com.muses.taoshop.common.core.database.config;import org.apache.commons.lang3.StringUtils; import…

搭建spring boot環境并測試一個controller

Idea搭建spring boot環境一、新建項目二、起步依賴三、編寫SpringBoot引導類四、編寫Controller五、熱部署一、新建項目 1.新建project 2.選擇SpringInitializr&#xff0c;選擇jdk&#xff0c;沒有則需要下載并配置(若選擇Maven工程則需要自己添加pom.xml所需依賴坐標和Java…

音頻噪聲抑制_音頻編輯入門指南:基本噪聲消除

音頻噪聲抑制Laying down some vocals? Starting your own podcast? Here’s how to remove noise from a messy audio track in Audacity quickly and easily. 放下人聲&#xff1f; 開始自己的播客&#xff1f; 這是在Audacity中快速輕松地消除雜亂音軌中噪聲的方法。 Th…

Dubbo集群容錯

轉自dubbo官網文檔http://dubbo.apache.org/zh-cn/blog/dubbo-cluster-error-handling.html Design For failure 在分布式系統中&#xff0c;集群某個某些節點出現問題是大概率事件&#xff0c;因此在設計分布式RPC框架的過程中&#xff0c;必須要把失敗作為設計的一等公民來對…

Linux基礎(day53)

2019獨角獸企業重金招聘Python工程師標準>>> 12.21 php-fpm的pool php-fpm的pool目錄概要 vim /usr/local/php/etc/php-fpm.conf//在[global]部分增加include etc/php-fpm.d/*.confmkdir /usr/local/php/etc/php-fpm.d/cd /usr/local/php/etc/php-fpm.d/vim www.co…

Mysql+Navicat for Mysql

一、mysql 1.下載安裝 Mysql官網下載地址 下載后解壓 .zip &#xff08;或安裝.msi&#xff09; 2.可加入全局變量mysqld &#xff08;可選&#xff09; 我的電腦->屬性->高級->環境變量->Path(系統變量)&#xff0c;添加mysql下的bin目錄&#xff0c;如 D:\Pr…

公鑰,私鑰和數字簽名

一、公鑰加密 假設一下&#xff0c;我找了兩個數字&#xff0c;一個是1&#xff0c;一個是2。我喜歡2這個數字&#xff0c;就保留起來&#xff0c;不告訴你們(私鑰&#xff09;&#xff0c;然后我告訴大家&#xff0c;1是我的公鑰。 我有一個文件&#xff0c;不能讓別人看&…

MySQL中的日志類型(二)-General query log

簡介 General query log記錄客戶端的連接和斷開&#xff0c;以及從客戶端發來的每一個SQL語句。 日志內容格式 General query log可以記錄在文件中&#xff0c;也可以記錄在表中&#xff0c;格式如下&#xff1a;在文件中會記錄時間、線程ID、命令類型以及執行的語句示例如下&a…

android wi-fi_如何在Android手機上查找3G或Wi-Fi速度

android wi-fiAre you curious about what kind of connection speed you are getting with your Android phone? Today we’ll take a look at how to easily check your Wi-Fi or 3G speeds with Speedtest.net’s Speed Test app. 您是否對Android手機的連接速度感到好奇&a…

vue引入全局less實現全局變量的控制

vue引入全局less1.設置全局樣式變量的好處&#xff1a;2.以less為例&#xff08;sass等同原理&#xff09;1.vue-cli2搭建的項目&#xff08;1&#xff09;2.vue-cli2搭建的項目&#xff08;2&#xff09;3.vue-cli3、vue-cli43.vue-cli2和vue-cli3的區別4.vue-cli3和vue-cli4的…

如何在eclipse中對項目進行重新編譯

有時由于eclipse異常關閉&#xff0c;當我們重啟Eclipse&#xff0c;在啟動項目時&#xff0c;會報錯&#xff0c;說&#xff1a;ClassNotFound類似的錯誤&#xff0c;引起這種問題的原因可能是由于&#xff0c;Eclipse異常關閉引起的。 解決&#xff1a;在一個項目中&#xff…

SQL 查詢數據庫中包含指定字符串的相關表和相關記錄

declare str varchar(100)set str我要找的 --要搜索的字符串declare s varchar(8000)declare tb cursor local forselect if exists(select 1 from [b.name] where [a.name] like %str%)print [b.name].[a.name]from syscolumns a join sysobjects b on a.idb.idwhere b.xtype…

如何在Gmail的圖片中插入超鏈接

Adding hyperlinks is an efficient way of getting your reader to the intended web page. Though it’s no secret that you can add hyperlinks to text, Gmail also lets you add hyperlinks to images in the body of the email. Here’s how to make it happen. 添加超鏈…

內聯元素居中

父元素&#xff1a; height:100px; line-height:100px; // 與高相同 text-align:center; 子元素: display:inline; vertical-align: middle; 適用圖片、文字 <div><div class"wrapper"><span>我是文字</span></div><div class&qu…

防止html標簽轉義

function htmlDecode ( str ) {var ele document.createElement(span);ele.innerHTML str;return ele.textContent;} 例如body下邊所有的p標簽都防止轉義&#xff1a; $.each($("body").find(p),function(){this.innerHTML htmlDecode(this.innerHTML);}); 轉載于…

新垣結衣自拍照_如何阻止自拍照出現在iPhone的自拍照專輯中

新垣結衣自拍照Khamosh PathakKhamosh PathakThe Photos app on your iPhone automatically populates all photos from the front-facing camera in the Selfies album. But what if you don’t want a photo to appear there? Here are a couple of solutions. iPhone上的“…

前端個人筆記

前端個人筆記1.vue項目安裝依賴/插件時忘記--save&#xff0c;再次install出問題并且沒有報錯。2.margin移動元素不顯示背景色3.新知識&#xff1a;media 條件樣式4.入坑&#xff1a;row和col不能分離&#xff0c;span24不能不寫5.聚焦實現滾動到指定元素1.vue項目安裝依賴/插件…

kernel中對文件的讀寫【學習筆記】【原創】

/*1. 頭文件 */ #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/fs.h> #include <linux/uaccess.h>MODULE_PARM_DESC(iva…