標籤:
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