PHP源代码分析-zend最终调用函数分析
原文出处:http://jackywdx.cn/2009/05/notes_of_zend_kernel
在追踪zend 内核的时候发现最终调用的函数都在zend_vm_execute.h文件里面定义了,也就是说基本每一个PHP的语句,比如定义一个函数、echo一个表达式等任何一个语句最后的实现都是在zend_vm_execute.h里面定义了,
在zend.c文件zend_startup()函数里面调用了zend_init_opcodes_handlers(),初始化了labels数组,这个数组的类型是opcode_handler_t,这个类型在zend_compile.h文件里面定义了:
opcode_handler_t是函数指针,指定一个用来处理每一个opcode的函数的入口地址,这些地址都保存在labels数组里面了。
这个结构体包含了近3776个成员,这些成员都是函数名称,每次执行一个opcode的时候都要到这个labels里面找对应的handler处理函数。
在zend_vm_execute.h文件最后的有两个函数:
如果想知道每个opcode是交给哪个handler处理,可以在
return zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]];
这条语句前面打印出索引值:
然后再重新 make && make install
编写一个test.php文件:
<?php
$a = "test";
?>
再运行/usr/local/php5.2.9/bin/php test.php
输出的结果如下:
zend_opcode_handlers_index:970
zend_opcode_handlers_index:1553
zend_opcode_handlers_index:3743
简单的一个赋值语句,最后执行了三个函数,这三个数字代表在labels里面的偏移量,找到labels里面第970个值:
ZEND_ASSIGN_SPEC_CV_CONST_HANDLER
再找到这个函数:
这个函数主要是对变量进行赋值,把值存进opline->result里面。后面1553和3743偏移值分别是
ZEND_RETURN_SPEC_CONST_HANDLER
ZEND_HANDLE_EXCEPTION_SPEC_HANDLER
分别是用来处理函数返回和异常,每个PHP文件执行到最后都会自动执行这两个函数。
另外想要快速查找每个偏移量对应的是哪个函数,可以先把 static const opcode_handler_t labels[] 里面的3776个成员保存在一个文件opcode_handler.txt,然后写个函数来智能处理:
编译:gcc -g -o gethandler gethandler.c
然后把gethandler 放入/bin/gethandler就可以了,比如我想查询偏移量为970的handler:
gethandler 970
结果:opcode handler: ZEND_ASSIGN_SPEC_CV_CONST_HANDLER,
再去找到这个函数的实现就好了。
写完之后发现用shell写更加快:
#gethandler_awk
#!/bin/bash
awk 'NR == offset {print "opcode handler:"$0} offset=$1 /home/dexin/op_code_handler.txt
chmod+x gethandler_awk
放入/bin/gethandler_awk
gethandler_awk 970
同样可以得出结果
opcode handler: ZEND_ASSIGN_SPEC_CV_CONST_HANDLER, 此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/67201.html
原文出处:http://jackywdx.cn/2009/05/notes_of_zend_kernel
在追踪zend 内核的时候发现最终调用的函数都在zend_vm_execute.h文件里面定义了,也就是说基本每一个PHP的语句,比如定义一个函数、echo一个表达式等任何一个语句最后的实现都是在zend_vm_execute.h里面定义了,
在zend.c文件zend_startup()函数里面调用了zend_init_opcodes_handlers(),初始化了labels数组,这个数组的类型是opcode_handler_t,这个类型在zend_compile.h文件里面定义了:
opcode_handler_t是函数指针,指定一个用来处理每一个opcode的函数的入口地址,这些地址都保存在labels数组里面了。
这个结构体包含了近3776个成员,这些成员都是函数名称,每次执行一个opcode的时候都要到这个labels里面找对应的handler处理函数。
在zend_vm_execute.h文件最后的有两个函数:
如果想知道每个opcode是交给哪个handler处理,可以在
return zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]];
这条语句前面打印出索引值:
然后再重新 make && make install
编写一个test.php文件:
<?php
$a = "test";
?>
再运行/usr/local/php5.2.9/bin/php test.php
输出的结果如下:
zend_opcode_handlers_index:970
zend_opcode_handlers_index:1553
zend_opcode_handlers_index:3743
简单的一个赋值语句,最后执行了三个函数,这三个数字代表在labels里面的偏移量,找到labels里面第970个值:
ZEND_ASSIGN_SPEC_CV_CONST_HANDLER
再找到这个函数:
这个函数主要是对变量进行赋值,把值存进opline->result里面。后面1553和3743偏移值分别是
ZEND_RETURN_SPEC_CONST_HANDLER
ZEND_HANDLE_EXCEPTION_SPEC_HANDLER
分别是用来处理函数返回和异常,每个PHP文件执行到最后都会自动执行这两个函数。
另外想要快速查找每个偏移量对应的是哪个函数,可以先把 static const opcode_handler_t labels[] 里面的3776个成员保存在一个文件opcode_handler.txt,然后写个函数来智能处理:
编译:gcc -g -o gethandler gethandler.c
然后把gethandler 放入/bin/gethandler就可以了,比如我想查询偏移量为970的handler:
gethandler 970
结果:opcode handler: ZEND_ASSIGN_SPEC_CV_CONST_HANDLER,
再去找到这个函数的实现就好了。
写完之后发现用shell写更加快:
#gethandler_awk
#!/bin/bash
awk 'NR == offset {print "opcode handler:"$0} offset=$1 /home/dexin/op_code_handler.txt
chmod+x gethandler_awk
放入/bin/gethandler_awk
gethandler_awk 970
同样可以得出结果
opcode handler: ZEND_ASSIGN_SPEC_CV_CONST_HANDLER, 此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/67201.html