PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。
首先,下载PHP源码以供编译, 我现在使用的是PHP5.3 alpha2
进入源码目录:
./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql --with-config-file-path=/etc/
./make
./make install
最后,记得要将生成的libphp5.so复制到运行时库的目录,我直接拷贝到了/lib/, 否则会在运行你自己的embed程序的时候报错:
./embed: error while loading shared libraries: libphp5.so: cannot open shared object file: No such file or directory
如果你对PHP的SAPI还不熟悉的话,我建议你看看我的这篇文章:深入理解Zend SAPIs(Zend SAPI Internals)
这个时候,你就可以在你的C代码中,嵌入PHP脚本解析器了, 我的例子:
#include "sapi/embed/php_embed.h" int main(int argc, char * argv[]){ PHP_EMBED_START_BLOCK(argc,argv); char * script = " print 'Hello World!';"; zend_eval_string(script, NULL, "Simple Hello World App" TSRMLS_CC); PHP_EMBED_END_BLOCK(); return 0; }
然后就是要指明include path了,一个简单的Makefile
CC = gcc CFLAGS = -I/usr/local/include/php/ -I/usr/local/include/php/main -I/usr/local/include/php/Zend -I/usr/local/include/php/TSRM -Wall -g LDFLAGS = -lstdc++ -L/usr/local/lib -lphp5 ALL: $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)
编译成功以后, 运行,我们可以看到, stdout输出 Hello World!
基于这个,我们就可以很容易的实现一个类似于vld的Opcodes dumper:
首先我们定义opcode的转换函数(全部的opcodes可以查看Zend/zend_vm_opcodes.h);
char *opname(zend_uchar opcode){ switch(opcode) { case ZEND_NOP: return "ZEND_NOP"; break; case ZEND_ADD: return "ZEND_ADD"; break; case ZEND_SUB: return "ZEND_SUB"; break; case ZEND_MUL: return "ZEND_MUL"; break; case ZEND_DIV: return "ZEND_DIV"; break; case ZEND_MOD: return "ZEND_MOD"; break; case ZEND_SL: return "ZEND_SL"; break; case ZEND_SR: return "ZEND_SR"; break; case ZEND_CONCAT: return "ZEND_CONCAT"; break; case ZEND_BW_OR: return "ZEND_BW_OR"; break; case ZEND_BW_AND: return "ZEND_BW_AND"; break; case ZEND_BW_XOR: return "ZEND_BW_XOR"; break; case ZEND_BW_NOT: return "ZEND_BW_NOT"; break; /*...省略 ....*/ default : return "UNKNOW"; break;
然后定义zval和znode的输出函数:
char *format_zval(zval *z) { static char buffer[BUFFER_LEN]; int len; switch(z->type) { case IS_NULL: return "NULL"; case IS_LONG: case IS_BOOL: snprintf(buffer, BUFFER_LEN, "%d", z->value.lval); return buffer; case IS_DOUBLE: snprintf(buffer, BUFFER_LEN, "%f", z->value.dval); return buffer; case IS_STRING: snprintf(buffer, BUFFER_LEN, "\"%s\"", z->value.str.val); return buffer; case IS_ARRAY: case IS_OBJECT: case IS_RESOURCE: case IS_CONSTANT: case IS_CONSTANT_ARRAY: return ""; default: return "unknown"; } } char * format_znode(znode *n){ static char buffer[BUFFER_LEN]; switch (n->op_type) { case IS_CONST: return format_zval(&n->u.constant); break; case IS_VAR: snprintf(buffer, BUFFER_LEN, "$%d", n->u.var/sizeof(temp_variable)); return buffer; break; case IS_TMP_VAR: snprintf(buffer, BUFFER_LEN, "~%d", n->u.var/sizeof(temp_variable)); return buffer; break; default: return ""; break; } }
然后定义op_array的输出函数:
void dump_op(zend_op *op, int num){ printf("%5d %5d %30s %040s %040s %040s\n", num, op->lineno, opname(op->opcode), format_znode(&op->op1), format_znode(&op->op2), format_znode(&op->result)) ; } void dump_op_array(zend_op_array *op_array){ if(op_array) { int i; printf("%5s %5s %30s %040s %040s %040s\n", "opnum", "line", "opcode", "op1", "op2", "result"); for(i = 0; i < op_array->last; i++) { dump_op(&op_array->opcodes[i], i); } } }
最后,就是程序的主函数了:
int main(int argc, char **argv){ zend_op_array *op_array; zend_file_handle file_handle; if(argc != 2) { printf("usage: op_dumper <script>\n"); return 1; } PHP_EMBED_START_BLOCK(argc,argv); printf("Script: %s\n", argv[1]); file_handle.filename = argv[1]; file_handle.free_filename = 0; file_handle.type = ZEND_HANDLE_FILENAME; file_handle.opened_path = NULL; op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC); if(!op_array) { printf("Error parsing script: %s\n", file_handle.filename); return 1; } dump_op_array(op_array); PHP_EMBED_END_BLOCK(); return 0; }
编译,运行测试脚本(sample.php):
复制代码 代码如下:
sample.php:
echo "laruence";
命令:
复制代码 代码如下:
./opcodes_dumper sample.php
得到输出结果(如果你对下面的结果很迷惑,那么建议你再看看我的这篇文章:深入理解PHP原理之Opcodes):
Script: sample.php
opnum line opcode op1 op2 result
0 2 ZEND_ECHO "laruence"
1 4 ZEND_RETURN 1
呵呵,怎么样,是不是很好玩呢?
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 齐豫.2003-THE.UNHEARD.OF.CHYI.3CD【苏活音乐】【WAV+CUE】
- 黄乙玲1986-讲什么山盟海誓[日本东芝版][WAV+CUE]
- 曾庆瑜1991-柔情陷阱[台湾派森东芝版][WAV+CUE]
- 陈建江《享受男声》DTS-ES6.1【WAV】
- 群星《闪光的夏天 第5期》[FLAC/分轨][392.38MB]
- 徐小凤《三洋母带》1:1母盘直刻[WAV+CUE][981M]
- 王菲1995《菲靡靡之音》[香港首版][WAV+CUE][1G]
- 《双城之战》主题小游戏现已上线 扮演金克丝探索秘密基地
- 《霍格沃茨之遗》PS5Pro画面对比:光追性能显著提升
- 《怪猎荒野》PS5Pro主机版对比:B测性能都不稳定
- 黄宝欣.1992-黄宝欣金装精选2CD【HOMERUN】【WAV+CUE】
- 群星.1996-宝丽金流行爆弹精丫宝丽金】【WAV+CUE】
- 杜德伟.2005-独领风骚新歌精选辑3CD【滚石】【WAV+CUE】
- 安与骑兵《心无疆界》[低速原抓WAV+CUE]
- 柏菲唱片-群星〈胭花四乐〉2CD[原抓WAV+CUE]