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. 玩转kafka

    http://zookeeper.apache.org/releases.html#download http://kafka.apache.org/downloads.html(下载最新 二进制版本 ...

  2. openshift 添加cron定时任务

    一般linux添加cron任务是在/etc/crontab,但是由于openshift的权限木有这么开放,所以如果需要设置定时任务的话,需要在如下的文件夹下添加你的sh文件,因为我需要的是每天运行一次 ...

  3. poj 3041 Asteroids 题解

    Asteroids Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20686   Accepted: 11239 Descr ...

  4. 使用DBCA工具创建自己的数据库

    ylbtech-Oracle:使用DBCA工具创建自己的数据库  DBCA创建数据库 默认安装的Oracle数据库一般不能满足实际应用的需求,例如数据库名称.数据库块的大小等都需要修改,那么我们应该自 ...

  5. C语言文件打开方式及说明

    ANSI C规定文件打开用函数fopen,关闭为fclose. 1.调用方式通常为: FILE *fp; fp=fopen(文件名, 打开方式);   2.参数说明: 文件名: 形如"myf ...

  6. 如何在脚本中执行SQL语句并获得结果输出?

    这里需要用到的工具叫做sqlcmd.exe, 它随SQL server的安装而安装. 该可执行程序的位置在: C:\Program Files\Microsoft SQL Server\xxx\Too ...

  7. Minimum Window Substring leetcode java

    题目: Given a string S and a string T, find the minimum window in S which will contain all the charact ...

  8. 7 个 Bootstrap 在线编辑器用于快速开发响应式网站

    Bootstrap 已经使响应式网站开发变得简单很多. 但是如果你不必手动写全部代码,事情会如何呢? 如果你可以自由地选择你想要使用的Bootstrap 组件.并可以把它们拖拽到画布中,事情会如何呢? ...

  9. css美化、优化、合并工具推荐

    其实很多时候,我们写完css规则之后,我们思考的无非就是3件事情: 验证 美化 压缩 当然无论是我们自己做这样的工具还是寻找一些比较好的成熟的工具,都有几个期望: 是否支持一些ie下的hack方式: ...

  10. GridControl 获取某分组的第一个孩子

    int iGroupRowHandle = this.gridControlView.FocusedRowHandle; ) { int iChildCount = this.gridControl. ...