php-5.6.26源代码 - opcode处理器的注入

 

1、初始化 opcode处理器列表

// main实现在文件“php-5.6.26\sapi\cgi\cgi_main.c”
int main(int argc, char *argv[])
{
    if (cgi_sapi_module.startup(&cgi_sapi_module){
            // php_cgi_startup实现在文件“php-5.6.26\sapi\cgi\cgi_main.c”
        static int php_cgi_startup(sapi_module_struct *sapi_module)
        {
            if (php_module_startup(sapi_module, &cgi_module_entry, 1){
            
                // zend_startup实现在文件“php-5.6.26\sapi\cgi\cgi_main.c”
                int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules)
                {
                    // zend_startup实现在文件“php-5.6.26\Zend\zend.c”
                    zend_startup(&zuf, NULL TSRMLS_CC); // !!!!
                    {
                        int zend_startup(zend_utility_functions *utility_functions, char **extensions TSRMLS_DC) 
                        {
                            ...
                            // zend_init_opcodes_handlers实现在文件php-7.2.3\Zend\zend_vm_execute.h
                            zend_init_opcodes_handlers(); // !!! 初始化“opcodes处理器”列表 ------------ 初始化
                            {
                                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_ASSIGN_POW_SPEC_CV_TMP_HANDLER,
                                      ZEND_ASSIGN_POW_SPEC_CV_VAR_HANDLER,
                                      ZEND_ASSIGN_POW_SPEC_CV_UNUSED_HANDLER,
                                      ZEND_ASSIGN_POW_SPEC_CV_CV_HANDLER,
                                      ZEND_NULL_HANDLER
                                  };
                                  zend_opcode_handlers = (opcode_handler_t*)labels;
                            }
                            ...
                        }
                    }
                }
            } == FAILURE) {
                return FAILURE;
            }
            return SUCCESS;
        
       
        }
    } == FAILURE) {   // startup ---> php_cgi_startup ---> php_module_startup
#ifdef ZTS ---
        tsrm_shutdown();
#endif
        return FAILURE;
    }
}    
    
    
2、注入opcode处理器 & 执行opcode处理器

    // 在文件 php-5.6.26\main\main.c
    PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC)
    {
        ...
        /*
           If cli primary file has shabang line and there is a prepend file,
           the `start_lineno` will be used by prepend file but not primary file,
           save it and restore after prepend file been executed.
         */
        if (CG(start_lineno) && prepend_file_p) {
            int orig_start_lineno = CG(start_lineno);

            CG(start_lineno) = 0;
            if (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 1, prepend_file_p) == SUCCESS) {
                CG(start_lineno) = orig_start_lineno;
                retval = (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 2, primary_file, append_file_p) == SUCCESS);
            }
        } else {
            // 在文件 php-5.6.26\Zend\zend.c
            retval = (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 3, prepend_file_p, primary_file, append_file_p) == SUCCESS); // 执行primary_file的php脚本
            {
                ...
                EG(active_op_array) = zend_compile_file(file_handle, type TSRMLS_CC); // 编译PHP文件成操作码 op_code ,zend_compile_file == compile_file
                {
                    // 在文件 php-5.6.26\Zend\zend_language_scanner.c !!!编译文件,编译出opcode
                    ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
                    {
                        ...
                        if (retval) {
                            CG(active_op_array) = original_active_op_array; // 还原原来 op_code 现场(还原现场)
                            if (compilation_successful) {  // !!!汇编成功
                            
                                // 在文件 php-5.6.26\Zend\zend_opcode.c
                                pass_two(op_array TSRMLS_CC); // !!!! 给每个op_code注册“op_code处理器”
                                {
                                    ...
                                    while (opline < end) { // 迭代所有操作码 
                                        if (opline->op1_type == IS_CONST) { // 如果是是常量
                                            opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
                                        }
                                        if (opline->op2_type == IS_CONST) {
                                            opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
                                        }
                                        switch (opline->opcode) {
                                            case ZEND_GOTO:
                                                if (Z_TYPE_P(opline->op2.zv) != IS_LONG) {
                                                    zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
                                                }
                                                /* break omitted intentionally */
                                            case ZEND_JMP:
                                            case ZEND_FAST_CALL:
                                                opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
                                                break;
                                            case ZEND_JMPZ:
                                            case ZEND_JMPNZ:
                                            case ZEND_JMPZ_EX:
                                            case ZEND_JMPNZ_EX:
                                            case ZEND_JMP_SET:
                                            case ZEND_JMP_SET_VAR:
                                                opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num];
                                                break;
                                            case ZEND_RETURN:
                                            case ZEND_RETURN_BY_REF:
                                                if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
                                                    if (opline->op1_type != IS_CONST || Z_TYPE_P(opline->op1.zv) != IS_NULL) {
                                                        CG(zend_lineno) = opline->lineno;
                                                        zend_error_noreturn(E_COMPILE_ERROR, "Generators cannot return values using \"return\"");
                                                    }
                                
                                                    opline->opcode = ZEND_GENERATOR_RETURN;
                                                }
                                                break;
                                        }
                                        ZEND_VM_SET_OPCODE_HANDLER(opline); // 设置“opcode处理器” ------------ 注入
                                        {
                                            // 宏定义在文件 “php-5.6.26\Zend\zend_vm.h ”
                                            #define ZEND_VM_SET_OPCODE_HANDLER(opline) zend_vm_set_opcode_handler(opline)
                                            {
                                                // zend_vm_set_opcode_handler 实现在文件“php-5.6.26\Zend\zend_vm_execute.h”,
                                                ZEND_API void zend_vm_set_opcode_handler(zend_op* op) // 获取“opcode处理器”
                                                {
                                                    op->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);
                                                    {
                                                        // zend_vm_get_opcode_handler实现在文件“php-5.6.26\Zend\zend_vm_execute.h”,
                                                        static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op) // 获取“opcode处理器”
                                                        {
                                                                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]];
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        opline++;
                                    }
                                
                                    op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
                                    return 0;
                                    ...
                                }
                                zend_release_labels(0 TSRMLS_CC);
                            } else {
                                efree(op_array);
                                retval = NULL;
                            }
                        }
                        ...
                    }
                    
                    //  !!! 执行 opcode 列表
                    if (EG(active_op_array)) { // “操作码”数组
                        EG(return_value_ptr_ptr) = retval ? retval : NULL;
                        
                        // 在文件 php-5.6.26\Zend\zend_vm_execute.c
                        zend_execute(EG(active_op_array) TSRMLS_CC);  // 执行编译后的操作码 op_code  , zend_execute == execute_ex
                        {
                            
                            if (EG(exception)) {
                                return;
                            }
                            
                            // 在文件 php-5.6.26\Zend\zend_vm_execute.c
                            zend_execute_ex(i_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC); // zend_execute_ex = execute_ex
                            {
                                DCL_OPLINE
                                zend_bool original_in_execution;
                            
                                original_in_execution = EG(in_execution);  // 保存现场
                                EG(in_execution) = 1; // 正在执行中 
                            
                                if (0) {
                            zend_vm_enter:
                                    execute_data = i_create_execute_data_from_op_array(EG(active_op_array), 1 TSRMLS_CC);
                                }
                            
                                LOAD_REGS();
                                LOAD_OPLINE();
                            
                                while (1) {
                                    int ret;
                            #ifdef ZEND_WIN32
                                    if (EG(timed_out)) {
                                        zend_timeout(0);
                                    }
                            #endif
                            
                                    /*
                                        OPLINE->handler(execute_data TSRMLS_CC)
                                        EX(opline)->handler(execute_data TSRMLS_CC)
                                        execute_data.opline->handler(execute_data TSRMLS_CC)
                                     */
                                    if ((ret = OPLINE->handler(execute_data TSRMLS_CC)) > 0) {  // execute_data.opline->handler(execute_data TSRMLS_CC) //   调用“opcode对应的处理函数” ------------调用
                                        switch (ret) {
                                            case 1:
                                                EG(in_execution) = original_in_execution; // 还原现场
                                                return;
                                            case 2:
                                                goto zend_vm_enter; // 进入虚拟机
                                                break;
                                            case 3:
                                                execute_data = EG(current_execute_data);  // 当前正在执行的数据 
                                                break;
                                            default:
                                                break;
                                        }
                                    }
                            
                                }
                                zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
                            }
                        }
                        ...
                    }
                    ...
                }
                ...
            }
        }
        ...
    }

 

posted on 2018-03-23 10:35  周~~  阅读(248)  评论(0编辑  收藏  举报

导航