1、opcode结构
在Zend/zend_compile.h文件下
1
2
3
4
5
6
7
8
9
10
11
12
|
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中查到定义
1
|
#define ZEND_ASSIGN 38
|
可以推算出 op_type为const和cv,然后就能确定handler为函数ZEND_ASSIGN_SPEC_CV_CONST_HANDLER
然后就可以定位到具体的执行函数了
1
2
3
4
5
6
7
8
9
10
11
|
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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
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;
<strong>zend_init_opcodes_handlers();</strong>
……
}
|
然后会初始化labels数组,这个数组的类型是opcode_handler_t (zend_compile.h)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
1
2
3
4
|
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函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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
1
|
zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]];
|