1、opcode结构

在Zend/zend_compile.h文件下

struct _zend_op {
opcode_handler_t handler;
znode_op op1;
znode_op op2;
znode_op result;
ulong extended_value;
uint lineno;
zend_uchar opcode;
zend_uchar op1_type;
zend_uchar op2_type;
zend_uchar result_type;
};

opcode_handler_t是函数指针为opcode定义了执行方式,每一种opcode都对应一个的handler,也就是函数的入口地址,这些地址都保存在labels数组里面

比如赋值:$a = 1

通过vld可以看到

op = ASSIGN 那么对应到zend engine  操作为ZEND_ASSIGN ,对应的编号为38的  可以在Zend/zend_vm_opcodes.h中查到定义

#define ZEND_ASSIGN                           38

可以推算出 op_type为const和cv,然后就能确定handler为函数ZEND_ASSIGN_SPEC_CV_CONST_HANDLER

然后就可以定位到具体的执行函数了

static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE zval *value;
zval **variable_ptr_ptr; SAVE_OPLINE();
value = opline->op2.zv;
……

zend engine在执行的是首先会调用 zend_startup() 位于(zend.c中),然后初始化zend_init_opcodes_handlers()

int zend_startup(zend_utility_functions *utility_functions, char **extensions TSRMLS_DC) /* {{{ */
{
#ifdef ZTS
zend_compiler_globals *compiler_globals;
zend_executor_globals *executor_globals;
extern ZEND_API ts_rsrc_id ini_scanner_globals_id;
extern ZEND_API ts_rsrc_id language_scanner_globals_id;
#else
extern zend_ini_scanner_globals ini_scanner_globals;
extern zend_php_scanner_globals language_scanner_globals;
#endif start_memory_manager(TSRMLS_C); virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */ #if defined(__FreeBSD__) || defined(__DragonFly__)
/* FreeBSD and DragonFly floating point precision fix */
fpsetmask(0);
#endif zend_startup_strtod();
zend_startup_extensions_mechanism(); /* Set up utility functions and values */
zend_error_cb = utility_functions->error_function;
zend_printf = utility_functions->printf_function;
zend_write = (zend_write_func_t) utility_functions->write_function;
zend_fopen = utility_functions->fopen_function;
if (!zend_fopen) {
zend_fopen = zend_fopen_wrapper;
}
zend_stream_open_function = utility_functions->stream_open_function;
zend_message_dispatcher_p = utility_functions->message_handler;
#ifndef ZEND_SIGNALS
zend_block_interruptions = utility_functions->block_interruptions;
zend_unblock_interruptions = utility_functions->unblock_interruptions;
#endif
zend_get_configuration_directive_p = utility_functions->get_configuration_directive;
zend_ticks_function = utility_functions->ticks_function;
zend_on_timeout = utility_functions->on_timeout;
zend_unblock_interruptions = utility_functions->unblock_interruptions;
#endif
zend_get_configuration_directive_p = utility_functions->get_configuration_directive;
zend_ticks_function = utility_functions->ticks_function;
zend_on_timeout = utility_functions->on_timeout;
zend_vspprintf = utility_functions->vspprintf_function;
zend_getenv = utility_functions->getenv_function;
zend_resolve_path = utility_functions->resolve_path_function; #if HAVE_DTRACE
/* build with dtrace support */
zend_compile_file = dtrace_compile_file;
zend_execute_ex = dtrace_execute_ex;
zend_execute_internal = dtrace_execute_internal;
#else
zend_compile_file = compile_file;
zend_execute_ex = execute_ex;
zend_execute_internal = NULL;
#endif /* HAVE_SYS_SDT_H */
zend_compile_string = compile_string;
zend_throw_exception_hook = NULL; zend_init_opcodes_handlers();
……

 

然后会初始化labels数组,这个数组的类型是opcode_handler_t (zend_compile.h)

void zend_init_opcodes_handlers(void)
{
static const opcode_handler_t labels[] = {
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
ZEND_NOP_SPEC_HANDLER,
……

zend_opcode_handlers = (opcode_handler_t*)labels;

//Zend/zend_vm_execute.h

opcode_handler_t

typedef int (*user_opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
typedef int (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS); extern ZEND_API opcode_handler_t *zend_opcode_handlers;

这个结构体包含了近4000个成员,这些成员都是函数名称,每次执行一个opcode的时候都要到这个labels里面找对应的handler处理函数

op_type函数

static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op)
{
static const int zend_vm_decode[] = {
_UNUSED_CODE, /* 0 */
_CONST_CODE, /* 1 = IS_CONST */
_TMP_CODE, /* 2 = IS_TMP_VAR */
_UNUSED_CODE, /* 3 */
_VAR_CODE, /* 4 = IS_VAR */
_UNUSED_CODE, /* 5 */
_UNUSED_CODE, /* 6 */
_UNUSED_CODE, /* 7 */
_UNUSED_CODE, /* 8 = IS_UNUSED */
_UNUSED_CODE, /* 9 */
_UNUSED_CODE, /* 10 */
_UNUSED_CODE, /* 11 */
_UNUSED_CODE, /* 12 */
_UNUSED_CODE, /* 13 */
_UNUSED_CODE, /* 14 */
_UNUSED_CODE, /* 15 */
_CV_CODE /* 16 = IS_CV */
};
return zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1_type] * 5 + zend_vm_decode[op->op2_type]];
} ZEND_API void zend_vm_set_opcode_handler(zend_op* op)
{
op->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);
}

返回对应的handler

zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]];

深入PHP内核之opcode handler的更多相关文章

  1. FrameWork内核解析之Handler消息机制(二)

    阿里P7Android高级架构进阶视频(内含Handler视频讲解)免费学习请点击:https://space.bilibili.com/474380680 一.Handler 在Android开发的 ...

  2. 关于PHP中的opcode

    简介 1.当Zend engine解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode),opcode是一个四元组,(opcode, ...

  3. Linux驱动设计—— 中断与时钟@request_irq参数详解

    request_irq函数定义 /*include <linux/interrupt.h>*/ int request_irq(unsigned int irq, irq_handler_ ...

  4. 再一次, 不要使用(include/require)_once

    本文地址: http://www.laruence.com/2012/09/12/2765.html 最近关于apc.include_once_override的去留, 我们做了几次讨论, 这个APC ...

  5. [转]再识Cortex-M3之堆栈

    原地址https://blog.csdn.net/liaoxu02/article/details/48107651 Cortex-M3拥有通用寄存器R0-R15以及一些特殊功能寄存器.R0-R12是 ...

  6. 请远离include_once和require_once

    尽量使用include, 而不是include_once, 理由是 include_once需要查询一遍已加载的文件列表, 确认是否存在, 然后再加载. 诚然, 这个理由是对的, 不过, 我今天要说的 ...

  7. php中的foreach问题(1)

    前言 php4中引入了foreach结构,这是一种遍历数组的简单方式.相比传统的for循环,foreach能够更加便捷的获取键值对.在php5之前,foreach仅能用于数组:php5之后,利用for ...

  8. 深入解析php中的foreach问题

    本篇文章是对php中的foreach问题进行了详细的分析介绍,需要的朋友参考下   前言:php4中引入了foreach结构,这是一种遍历数组的简单方式.相比传统的for循环,foreach能够更加便 ...

  9. Attacking JavaScript Engines: A case study of JavaScriptCore and CVE-2016-4622(转)

    转:http://phrack.org/papers/attacking_javascript_engines.html Title : Attacking JavaScript Engines: A ...

随机推荐

  1. C标准库 二

    http://www.utas.edu.au/infosys/info/documentation/C/CStdLib.html现在C语言(C99)标准库函数的24个头文件列表如下: assert.h ...

  2. POP按钮动画

    POP按钮动画 效果 源码 https://github.com/YouXianMing/Animations // // ButtonPressViewController.m // Faceboo ...

  3. cron表达式举例

    1.quartz定时任务时间设置描述(2011-03-03 16:23:50)转载▼标签: quartz时间it 分类: 凌乱小记 这些星号由左到右按顺序代表 : * * * * * * * 格式: ...

  4. hue解决timed out(code THRIFTSOCKET):None

    报错栈: Traceback (most recent call last): File , in decorator return func(*args, **kwargs) File , in e ...

  5. 数据库实例: STOREBOOK > 用户 > 编辑 用户: DBSNMP

    ylbtech-Oracle:数据库实例: STOREBOOK  >  用户  >  编辑 用户: DBSNMP 编辑 用户: DBSNMP 1. 一般信息返回顶部 1.1, 1.2, 2 ...

  6. 一个巧妙的方法实现elementUI的table的行选中

    问题背景:点击上面的框,选中下面对象的行数据 刚开始考虑使用的是table的事件:toggleRowSelection,但是发现一个奇怪的现象 <div v-if="orderData ...

  7. Back Track 5 之 网络踩点

    DNS记录探测 dnsenum 针对NDS信息收集的工具 格式: ./dnsenum.pl dbsserver (域名) 请原谅我拿freestu.net这个学校团委的域名做的测试,求不黑!! dns ...

  8. 申请红帽企业版Linux开发者订阅

    导读 注册成为开发者计划的成员现在可以得到一套免费的 Red Hat Enterprise Linux 许可证,RHEL 开发套件将为程序员提供一个构建企业应用的稳定发展平台.红帽开发订阅成员还可以免 ...

  9. (转)UnityVS(Visual Studio Tools For Unity)的安装与使用

    UnityVS(Visual Studio Tools For Unity)的安装与使用   一些废话 Unity 的开发者们,尤其是微软系的Unity开发者们,用Mono是不是烦死了?你是不是跟我一 ...

  10. WIN32 SDK对COM的支持