SlideShare ist ein Scribd-Unternehmen logo
1 von 79
Understanding PHP Opcodes ,[object Object]
PHP Opcodes ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Execution path for a script php_execute_script()‏ zend_execute_scripts()‏ zend_execute()‏ user call (function/method )‏ include/require zend_compile_file()‏
zend_compile_file ,[object Object],[object Object],[object Object],[object Object],[object Object],PHP script Lexical Analyser Parser byte codes tokens
Lexical Analysis ,[object Object],[object Object],[object Object],<?php $tokens = token_get_all(&quot;<?php  echo = ‘Hello World’;   ?>&quot;); foreach($tokens as $token) { if (is_array($token)) { printf(&quot;%s  %s&quot;,  token_name($token[0]), $token[1]); } else { printf(&quot;'%s'&quot;, $token);  } } ?> T_OPEN_TAG  <?php T_ECHO  echo T_WHITESPACE T_CONSTANT_ENCAPSED_STRING  'Hello World' ';' T_CLOSE_TAG  ?> Lexical Analysis
Parsing ,[object Object],[object Object],[object Object],Parser T_OPEN_TAG  <?php T_ECHO  echo T_WHITESPACE T_CONSTANT_ENCAPSED_STRING  'Hello World' ';' T_CLOSE_TAG  ?> ZEND_OP ZEND_OP ZEND_OP ZEND_OP
Non-PHP statements  ,[object Object],[object Object],[object Object],<!-- example for PHP 5.0.0 final release --> <?php $domain = &quot;localhost&quot;; $user = &quot;root&quot;;#note &quot;MIKE&quot; is unacceptable $password = &quot;&quot;; $conn = mysql_connect( $domain, $user, $password ); if($conn)‏ { $msg = &quot;Congratulations !!!! $user, You connected to MySQL&quot;;  }  ?> <html> <head> <title>Connecting user</title> </head> <body> <h3>  <?php echo( $msg ); ?>   </h3> </body> </html>
Non-PHP statements  line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 3  0  ECHO  '%3C%21--+example+for+ PHP+5.0.0+final+release+--%3E%0D%0A%0D%0A' 5  1  ASSIGN  !0, 'localhost' 6  2  ASSIGN  !1, 'root' 7  3  ASSIGN  !2, '' 9  4  INIT_FCALL_BY_NAME  'mysql_connect' …… .. snip …. 22  ADD_STRING  ~5, ~5, 'MySQL' 23  ASSIGN  !4, ~5 14  24  JMP  ->25 26  25  ECHO  '%0D%0A%3Chtml%3E%0D%0A %0D%0A+%3Chead%3E%0D%0A++%3Ctitle%3EConnecting+user%3C%2Ftitle%3E%0D%0A+%3C%2Fhead%3E%0D %0A%0D%0A+%3Cbody%3E%0D%0A++%3Ch3%3E+%0D%0A+++' 26  ECHO  !4 30  27  ECHO  '+%0D%0A++%3C%2Fh3%3E %0D%0A+%3C%2Fbody%3E%0D%0A%0D%0A%3C%2Fhtml%3E' 28  RETURN  1 29  ZEND_HANDLE_EXCEPTION
Opcodes  ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],struct _zend_op { opcode_handler_t handler; znode result; znode op1; znode op2; ulong extended_value; uint lineno; zend_uchar opcode; };
znode ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],typedef struct _znode { int op_type; union { zval constant; zend_uint var; zend_uint opline_num;  zend_op_array *op_array; zend_op *jmp_addr; struct { zend_uint var; /*dummy */ zend_uint type; } EA; } u; } znode;
zend_compile_file()‏ ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
zend_compile_file()‏ ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],struct _zend_op_array { …… . zend_uint *refcount; zend_op *opcodes; zend_uint last, size; zend_compiled_variable *vars; int last_var, size_var; zend_uint T;zend_brk_cont_element *brk_cont_array; zend_uint last_brk_cont; zend_uint current_brk_cont; zend_try_catch_element *try_catch_array; int last_try_catch; /* static variables support */ HashTable *static_variables; … .. e.t.c ; ZEND_OP ZEND_OP ZEND_OP ZEND_OP ZEND_OP
Opcodes ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Functions and Classes ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Function table’s ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],typedef union _zend_function { zend_uchar type;  struct { zend_uchar type;  /* never used */ char *function_name; zend_class_entry *scope; ……… . <SNIP > …………. zend_bool pass_rest_by_reference; unsigned char return_reference; } common; zend_op_array op_array; zend_internal_function internal_function; } zend_function;
State of play after  compile complete opcodes zend_op_array active_oparray symbol_table active_symbol_table function_table class_table executor_globals symbol_table function_table <?php function add5($a) { return $a + 5;  } function sub5($a) { return $a - 5; } $a = add5(10); $b = sub5(15); ?> zend_op_array zend_op_array zend_internal_fucntion op_array for global scope zend_internal_fucntion GLOBALS _ENV HTTP_ENV_VARS …… . <internal func> add5 sub5 …… . <internal func>
Function tables ,[object Object],[object Object],[object Object]
Class_table ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
State of play after  compile complete :  opcodes zend_op_array active_oparray symbol_table active_smbol_table function_table class_table executor_globals symbol_table class_table <?php class Dog { function bark()‏ { print &quot;Woof!&quot;; } function sit()‏ { print “Sit!!”; } } $pooch = new Dog; $pooch ->bark(); $pooch ->sit(); ?> zend_op_array function_table function_table zend_op_array function_table zend_internal_fucntion zend_internal_fucntion GLOBALS _ENV HTTP_ENV_VARS …… . <internal class> Dog …… . bark sit …… . <internal func> <internal func> …… . <internal method> <internal method> …… .
Class table  ,[object Object],[object Object],[object Object]
Static variables ,[object Object],[object Object],[object Object],[object Object]
Examining compile results  ,[object Object],[object Object],[object Object],[object Object]
VLD ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
VLD  ,[object Object],ARG_ENABLE(&quot;vld&quot;, “Enable Vulcan Opcode decoder&quot; , &quot;no&quot;); if (PHP_VLD != &quot;no&quot;) { EXTENSION(&quot;vld&quot;, &quot;vld.c srm_oparray.c&quot;); }
VLD output line  #  op  fetch  ext  operands -------------------------------------------------------------------------- 2  0  ECHO  '%0A' 4  1  ASSIGN  !0, 5 5  2  ASSIGN  !1, 10 6  3  ADD  ~2, !0, !1 4  ADD  ~3, ~2, 99 5  ASSIGN  !2, ~3 8  6  INIT_STRING  ~5 7  ADD_STRING  ~5, ~5, 'c' 8  ADD_STRING  ~5, ~5, '%3D+' 9  ADD_VAR  ~5, ~5, !2 10  ADD_STRING  ~5, ~5, '+' 11  ADD_CHAR  ~5, ~5, 10 12  ECHO  ~5 11  13  RETURN  1 14  ZEND_HANDLE_EXCEPTION c= 114 <?php $a = 5; $b = 10; $c = $a + $b + 99; echo  &quot;c= $c &quot;; ?> php -f test.php -dvld.active=1 KEY !  == compiler variable $ == variable ~ == temporary There are TMP’s defied for results here but they are not used and VLD does not list them
Why all these “+” in VLD output for CONST’s ? <?php echo &quot;Hello World&quot;; echo &quot;Hello  World&quot;; echo &quot;Hello + World&quot;;  ?> line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 2  0  ECHO  '%0D%0A+' 4  1  ECHO  'Hello+World' 5  2  ECHO  'Hello++++++++++++++++++++++++++++++++World' 6  3  ECHO  'Hello+%2B+World' 9  4  RETURN  1 5  ZEND_HANDLE_EXCEPTION Answer:  VLD calls  php_url_encode() on the CONST to format it before output which amongst other things converts all spaces to “+”. Internally white space is stored as 0x20 as you would expect.
parsekit ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
parsekit  ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
parsekit-compile-string:   SIMPLE output <?php $oparray = parsekit_compile_string('echo &quot;HelloWorld&quot;;', $errors, PARSEKIT_SIMPLE); var_dump($oparray); ?> array(5) { [0]=> string(36) &quot;ZEND_ECHO UNUSED 'HelloWorld' UNUSED&quot; [1]=> string(30) &quot;ZEND_RETURN UNUSED NULL UNUSED&quot; [2]=> string(42) &quot;ZEND_HANDLE_EXCEPTION UNUSED UNUSED UNUSED&quot; [&quot;function_table&quot;]=> NULL [&quot;class_table&quot;]=> NULL }
parsekit-compile-file:   QUIET output  <?php $oparray = parsekit_compile_string('echo &quot;HelloWorld&quot;;', $errors, PARSEKIT_QUIET); var_dump($oparray); ?> array(20) { [&quot;type&quot;]=>  int(2)‏ [&quot;type_name&quot;]=>  string(18) &quot;ZEND_USER_FUNCTION&quot; [&quot;fn_flags&quot;]=>  int(0)‏ [&quot;num_args&quot;]=>  int(0)‏ [&quot;required_num_args&quot;]=>  int(0)‏ [&quot;pass_rest_by_reference&quot;]=>  bool(false)‏ [&quot;uses_this&quot;]=>  bool(false)‏ [&quot;line_start&quot;]=>  int(0)‏ [&quot;line_end&quot;]=>  int(0)‏ [&quot;return_reference&quot;]=>  bool(false)‏ [&quot;refcount&quot;]=>  int(1)‏ [&quot;last&quot;]=>  int(3)‏ [&quot;size&quot;]=>  int(3)‏ [&quot;T&quot;]=>  int(0)‏ [&quot;last_brk_cont&quot;]=>  int(0)‏ [&quot;current_brk_cont&quot;]=>  int(-1)‏ [&quot;backpatch_count&quot;]=>  int(0)‏ [&quot;done_pass_two&quot;]=>  bool(true)‏ [&quot;filename&quot;]=>  string(49) &quot;C:estcaseselloWorld.php&quot; [&quot;opcodes&quot;]=> array(3) { [0]=>  array(5) { [&quot;opcode&quot;]=>  int(40)‏ [&quot;opcode_name&quot;]=>  string(9) &quot;ZEND_ECHO&quot; [&quot;flags&quot;]=>  int(768)‏ [&quot;op1&quot;]=>  array(3) { [&quot;type&quot;]=>  int(1)‏ [&quot;type_name&quot;]=>  string(8) &quot;IS_CONST&quot; [&quot;constant&quot;]=>  &string(11) &quot;Hello World&quot; } [&quot;lineno&quot;]=>  int(3)‏ etc…..
parsekit-func-arginfo  <? php function foo ($a, stdClass $b, &$c) { } $oparray = parsekit_func_arginfo (‘foo’); var_dump($oparray); ?> array(3) { [0]=> array(3) { [&quot;name&quot;]=> string(1) &quot;a&quot; [&quot;allow_null&quot;]=> bool(true)‏ [&quot;pass_by_reference&quot;]=> bool(false)‏ } [1]=> array(4) { [&quot;name&quot;]=> string(1) &quot;b&quot; [&quot;class_name&quot;]=> string(8) &quot;stdClass&quot; [&quot;allow_null&quot;]=> bool(false)‏ [&quot;pass_by_reference&quot;]=> bool(false)‏ } [2]=> array(3) { [&quot;name&quot;]=> string(1) &quot;c&quot; [&quot;allow_null&quot;]=> bool(true)‏ [&quot;pass_by_reference&quot;]=> bool(true)‏ } }
parsekit-opcode-name  <?php $opname = parsekit_opcode_name (61); var_dump($opname); ?> string(21) &quot;ZEND_DO_FCALL_BY_NAME&quot; <?php $opflags = parsekit_opcode_flags (61); var_dump($opflags); ?> int(16777218)‏ flags define whether opcode takes op1 and op2,  defines EA, sets a result etc
Execution path for a script php_execute_script()‏ zend_execute_scripts()‏ zend_execute()‏ user call (function/method )‏ include/require zend_compile_file()‏
PHP Interpreter ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Interpreter generation process zend_vm_gen.php zend_vm_execute.skl zend_vm_def.h zend_vm-execute.h zend_vm_opcodes.h
zend_vm_execute.skl {%DEFINES%} ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)‏ { zend_execute_data execute_data; {%HELPER_VARS%} {%INTERNAL_LABELS%} if (EG(exception)) { return; } /* Initialize execute_data */ EX(fbc) = NULL; EX(object) = NULL; EX(old_error_reporting) = NULL; if (op_array->T < TEMP_VAR_STACK_LIMIT) { EX(Ts) = (temp_variable *) do_alloca(sizeof(temp_variable) * op_array->T); } else { EX(Ts) = (temp_variable *) safe_emalloc(sizeof(temp_variable), op_array->T, 0); } ……  etc  triggers to zend_vmg_gen.php to insert generated code
zend_vm_defs.h ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)‏ { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE(); } opcode opcode name types accepted for op1 types accepted for op2 .. although this is just a macro!  helper function triggers to php code to replace text
Interpreter generation process ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Interpreter generation process ,[object Object],[object Object],[object Object],[object Object],#line 28 &quot;C:HPDEVhp5.2-200612111130endend_vm_def.h&quot; static into ZEND_ADD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); add_function(&EX_T(opline->result.u.var).tmp_var, … . etc  ,[object Object],[object Object]
Specialization ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
zend_vm_defs.h ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)‏ { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE(); }
ZEND_ADD without specialization static int ZEND_ADD_HANDLER(ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, get_zval_ptr(&opline->op1, EX(Ts), &free_op1, BP_VAR_R), get_zval_ptr(&opline->op2, EX(Ts), &free_op2, BP_VAR_R)‏   TSRMLS_CC); FREE_OP(free_op1); FREE_OP(free_op2); ZEND_VM_NEXT_OPCODE(); } Handler calls  non-type specific  routines to get zval * for op1 and op2
ZEND_ADD with specialization static int ZEND_ADD_SPEC_CONST_CONST_HANDLER (ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); add_function(&EX_T(opline->result.u.var).tmp_var, &opline->op1.u.constant, &opline->op2.u.constant TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } static int ZEND_ADD_SPEC_CONST_TMP_HANDLER (ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); zend_free_op free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, &opline->op1.u.constant, _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)‏ TSRMLS_CC); zval_dtor(free_op2.var); ZEND_VM_NEXT_OPCODE(); } static int ZEND_ADD_SPEC_CONST_VAR_HANDLER (ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); zend_free_op free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, &opline->op1.u.constant, _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)‏ TSRMLS_CC); if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; ZEND_VM_NEXT_OPCODE(); } … . and 13 other handlers  Handlers call  type specific  routines to get zval * for op1 and op2
zend_vm_gen.php $op1_get_zval_ptr = array( &quot;ANY&quot;  => &quot;get_zval_ptr(&opline->op1, EX(Ts), &free_op1,  1 )&quot;, &quot;TMP&quot;  => &quot;_get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)&quot;, &quot;VAR&quot;  => &quot;_get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)&quot;, &quot;CONST&quot;  => &quot;&opline->op1.u.constant&quot;, &quot;UNUSED&quot; => &quot;NULL&quot;, &quot;CV&quot;  => &quot;_get_zval_ptr_cv(&opline->op1, EX(Ts), 1 TSRMLS_CC)&quot;, ); $op2_get_zval_ptr = array( &quot;ANY&quot;  => &quot;get_zval_ptr(&opline->op2, EX(Ts), &free_op2, 1)&quot;, &quot;TMP&quot;  => &quot;_get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)&quot;, &quot;VAR&quot;  => &quot;_get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)&quot;, &quot;CONST&quot;  => &quot;&opline->op2.u.constant&quot;, &quot;UNUSED&quot; => &quot;NULL&quot;, &quot;CV&quot;  => &quot;_get_zval_ptr_cv(&opline->op2, EX(Ts), 1 TSRMLS_CC)&quot;, … ..<snip> function gen_code(….)‏ …… $code = preg_replace( array( ......... &quot;/GET_OP1_ZVAL_PTR([^)]*)/&quot;, &quot;/GET_OP2_ZVAL_PTR([^)]*)/&quot;, ........ ), array( ....... ....... $op1_get_zval_ptr[$op1], $op2_get_zval_ptr[$op2], ....... ), $code);
Generated code not always the best !! static int ZEND_INIT_ARRAY_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); if (IS_CONST == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CONST != IS_UNUSED } else { return ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); #endif } } ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV)‏ { zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); if (OP1_TYPE == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if !defined(ZEND_VM_SPEC) || OP1_TYPE != IS_UNUSED } else { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_ADD_ARRAY_ELEMENT); #endif } } Input:  zend_vm-def.h Output:  zend_vm-execute.h
Mapping opcode to an handler ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
zend_execute ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],struct _zend_execute_data { struct _zend_op *opline; zend_function_state function_state; zend_function *fbc; /* Function Being Called */ zend_op_array *op_array; zval *object; union _temp_variable *Ts; zval ***CVs; zend_bool original_in_execution; HashTable *symbol_table; struct _zend_execute_data *prev_execute_data; zval *old_error_reporting; };
execute()‏ ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],zend_execute_data ……… current_execute_data …… .... executor_globals zend_execute_data null global scope foo()‏ <?php function foo() { … } …… foo(); }
Operand Types ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Temporary Variables: VAR and TMP ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],struct _zend_execute_data { struct _zend_op *opline; …… . union _temp_variable *Ts ; … .. etc }; typedef struct _znode { int op_type; union { zval constant; zend_uint var; zend_uint opline_num;  zend_op_array *op_array; zend_op *jmp_addr; struct { zend_uint var; /*dummy */ zend_uint type; } EA; } u; } znode; typedef union _temp_variable { zval tmp_var ; struct { zval **ptr_ptr; zval *ptr; zend_bool fcall_returned_reference; } var; struct { zval **ptr_ptr; zval *ptr; zend_bool fcall_returned_reference; zval *str; zend_uint offset; } str_offset; zend_class_entry *class_entry; } temp_variable;
VAR variables FETCH_W  $0, 'a'   /* Retrieve the $a variable for writing */  ASSIGN  $0, 123  /* Assign the numeric value 123 to retrieved variable 0 */  FETCH_W  $2, 'b'  /* Retrieve the $b variable for writing */  ASSIGN  $2, 456  /* Assign the numeric value 456 to retrieved variable 2 */  FETCH_R  $5, 'a'   /* Retrieve the $a variable for reading */  FETCH_R  $6, 'b'  /* Retrieve the $b variable for reading */  ADD  ~7, $5, $6  /* Add the retrieved variables (5 & 6) together and store the result in 7 */  FETCH_W  $4, 'c'  /* Retrieve the $c variable for writing */  ASSIGN  $4, ~7  /* Assign the value in temporary variable 7 into retrieved variable 4 */  FETCH_R  $9, 'c'  /* Retrieve the $c variable for reading */  ECHO  $9  /* Echo the retrieved variable 9 */  <?php  $a = 123;  $b = 456;  $c = $a + $b; echo $c;  ?>  Note: Each time $a is accessed we look it up in symbol table and store result in a different VAR
VAR variables typedef union _temp_variable { zval tmp_var; struct { zval **ptr_ptr; zval *ptr; zend_bool fcall_returned_reference; } var; …  etc } temp_variable; ZVAL typedef union _temp_variable { zval tmp_var; struct { zval **ptr_ptr; zval *ptr; zend_bool fcall_returned_reference; } var; …  etc } temp_variable; ZVAL After FETCH_R After FETCH_RW or FETCH_W pDataPtr symbol_table pDataPtr symbol_table
Compiled Variables ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Compiled Variables – compile time processing ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],struct _zend_op_array { …… zend_compiled_variable *vars; int last_var, size_var; … e.t.c }; last_var contains index of last slot used, size_var last available index typedef struct zend_compiled_variable { char *name; int name_len; ulong hash_value; } zend_compiled_variable;
Compiled Variables – At runtime ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],..... zval *** CVs … . zval ** execute_data CV cache ZVAL zval * symbol table … .. zend_uint var; … . znode pDataPtr slot of a HT bucket
Compiled variables: with regular variables  <?php  $a = 123;  $b = 456;  $c = $a + $b; echo $c;  ?>  FETCH_W  $0, 'a'  /* Retrieve the $a variable for writing */  ASSIGN  $0, 123  /* Assign the numeric value 123 to retrieved variable 0 */  FETCH_W  $2, 'b'  /* Retrieve the $b variable for writing */  ASSIGN  $2, 456  /* Assign the numeric value 456 to retrieved variable 2 */  FETCH_R  $5, 'a'  /* Retrieve the $a variable for reading */  FETCH_R  $6, 'b'  /* Retrieve the $b variable for reading */  ADD  ~7, $5, $6  /* Add the retrieved variables (5 & 6) together and store the result in 7 */  FETCH_W  $4, 'c'  /* Retrieve the $c variable for writing */  ASSIGN  $4, ~7  /* Assign the value in temporary variable 7 into retrieved variable 4 */  FETCH_R  $9, 'c'  /* Retrieve the $c variable for reading */  ECHO  $9  /* Echo the retrieved variable 9 */  ASSIGN  !0, 123  /* Assign the numeric value 123 to compiled variable 0 */  ASSIGN  !1, 456  /* Assign the numeric value 456 to compiled variable 1 */  ADD  ~2, !0, !1  /* Add compiled variable 0 to compiled variable 1 */  ASSIGN  !2, ~2  /* Assign the value of temporary variable 2 to compiled variable 2 */  ECHO  !2  /* Echo the value of compiled variable 2 */  Without CV With CV
Compiled variables :  with Object variables <?php  $f->a = 123;  $f->b = 456;  $f->c = $f->a + $F->b; echo $f->c;  ?>  ASSIGN_OBJ  !0, 'a'  /* Assign the numeric value 123 to property 'a' of compiled variable 0 object */ OP_DATA  123  /* Additional data for ASSIGN_OBJ opcode */  ASSIGN_OBJ  !0, 'b'  /* Assign the numeric value 456 to property 'b' of compiled variable 0 object */ OP_DATA  456  /* Additional data for ASSIGN_OBJ opcode */  FETCH_OBJ_R  $3, !0, 'a‘  /* Retrieve property 'a' from compiled variable 0 object */ FETCH_OBJ_R  $4, !0, 'b‘  /* Retrieve property 'b' from compiled variable 0 object */ ADD  ~5, $3, $4  /* Add those values and store the result in temp var 5 */ ASSIGN_OBJ  !0, 'c'  /* Assign the ADD result to property 'c' of compiled variable 0 object */ OP_DATA  ~5  /* Additional data for ASSIGN_OBJ opcode */  FETCH_OBJ_R  $6, !0, 'c‘  /* Retrieve property 'c' from compiled variable 0 object */  ECHO  $6  /* Echo the value */   With CV Note: Properties are re-fetched every time a read or write is performed on them which cannot be avoided due to the magic methods _get(), _set() e.t.c. which can return a different variable on different fetches
Symbol tables ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Which symbol table to use ? ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],<?php function foo() { $a = $_ENV; } foo(); ?> line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 9  0  FETCH_R  global  $0, '_ENV' 1  ASSIGN  !0, $0 10  2  RETURN  null 3  ZEND_HANDLE_EXCEPTION
Static Variables ,[object Object],[object Object],[object Object],[object Object]
Static Variables <?php function foo() { static $count = 0; $count ++; } foo(); foo(); foo(); ?> line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 5  0  FETCH_W  static  $0, 'count' 1  ASSIGN_REF  !0, $0 6  2  POST_INC  ~1, !0 3  FREE  ~1 8  4  RETURN  null 5  ZEND_HANDLE_EXCEPTION vld output for foo()‏ count value=0  is_ref=0  refount=1 zval count static_variables EG(active_symbol_table)‏ value=0  is_ref=1  refount=2 <?php function foo() { static $count = 0; $count ++; } foo(); foo(); foo(); ?> <?php function foo() { static $count = 0; $count ++; } foo(); foo(); foo(); ?> value=1  is_ref=1  refount=2
Function calling  ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],foo(&£a, $b, 100)‏ SEND_REF SEND_VAR SEND_VAL
Function calling  <?php $a= 10;  $b= 5;  foo($a, $b); function foo(&$x, &$y) { echo &quot;foo called with: $x $y&quot;;  } foo($a, $b); ?> line  #  op  fetch  ext  operands ----------------------------------------------------  ------------------- 2  0  ECHO  '%0D%0A+' 4  1  ASSIGN  !0, 10 5  2  ASSIGN  !1, 5 6  3  INIT_FCALL_BY_NAME  'foo' 4  SEND_VAR  !0 5  SEND_VAR  !1 6  DO_FCALL_BY_NAME  2  0 8  7  NOP 14  8  SEND_REF  !0 9  SEND_REF  !1 10  DO_FCALL  2  'foo', 0 17  11  RETURN  1 12  ZEND_HANDLE_EXCEPTION SEND_VAR opcode’s extended_value set when FCALL_BY_NAME to force SEND_VAR handler to check expected args at RUNTIME and if call by REF expected it re-dispatches SEND_REF handler  Uses EX(fbc) set by INIT_FCALL_BY_NAME to access required arg info. extended_value on FCALL opcode is number of arguments passed opcodes for global scope
Calling other user functions  ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Example 1:  Passing arguments by value without splitting  line  #  op  ext  operands -------------------------------------------------- 3  0  NOP 8  1  ASSIGN  !0, 10 9  2  ASSIGN  !1, 5 10  3  ASSIGN  !2, !0 12  4  SEND_VAR  !0 5  SEND_VAR  !1 6  DO_FCALL  2  'foo', 0 15  7  RETURN  1 8  ZEND_HANDLE_EXCEPTION value=10 refcount= 3 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;;  } $a= 10;  $b= 5;  $c= $a  foo($a, $b);  ?> value=5 refcount=2  is_ref= 0 a b c symbol_table After opcode #5: number of args opcodes for global scope no need to split zval for $a as its part of a “copy on write” set NULL NULL arg1 arg2 2
Example 2:  Passing arguments by value when splitting required line  #  op  ext  operands ------------------------------------------------- 3  0  NOP 8  1  ASSIGN  !0, 10 9  2  ASSIGN  !1, 5 10  3  ASSIGN  !2, !0 12  4  SEND_VAR  !0 5  SEND_VAR  !1 6  DO_FCALL  2  'foo', 0 15  7  RETURN  1 8  ZEND_HANDLE_EXCEPTION <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;;  } $a= 10;  $b= 5;  $c= &$a  foo($a, $b);  ?> After opcode #5: we have to split zval for $a  as its part of a “change on write” set opcodes for global scope NULL NULL arg1 arg2 2 value=10 refcount= 2 is_ref= 1 argument_stack value=5 refcount=2  is_ref= 0 a b c symbol_table value=10 refcount=1 is_ref= 0
Example 3: Passing arguments by reference when splitting required value=10 refcount= 1 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;;  } $a= 10;  $b= 5;  $c = $a foo(&$a, &$b);  ?> value=10 refcount=2  is_ref= 1 a b c symbol_table CV is actually in op1 not result operand line  #  op  ext  operands ------------------------------------------------ 3  0  NOP 8  1  ASSIGN  !0, 10 9  2  ASSIGN  !1, 5 10  3  ASSIGN  !2, !0 11  4  SEND_REF  !0 5  SEND_REF  !1 6  DO_FCALL  2  'foo', 0 14  7  RETURN  1 8  ZEND_HANDLE_EXCEPTION value=10 refcount= 2 is_ref= 1 After opcode #5: here we have to split zval for $a as its part of a “copy on write” set NULL NULL arg1 arg2 2
Example 4: Passing arguments by reference (compile time)‏ value=10 refcount= 1 is_ref= 0 argument_stack <?php $a= 10;  $b= 5;  $c= $a;  foo($a, $b); function foo(&$x, &$y) { echo &quot;foo called with: $x $y&quot;;  }  ?> value=10 refcount=2  is_ref= 1 a b c symbol_table line  #  op  ext  operands ---------------------------------------------------- 5  0  ASSIGN  !0, 10 6  1  ASSIGN  !1, 5 7  2  ASSIGN  !2, !0 8  3  INIT_FCALL_BY_NAME  'foo' 4  SEND_VAR  !0 5  SEND_VAR  !1 6  DO_FCALL_BY_NAME  2  0 10  7  NOP 16  8  RETURN  1 9  ZEND_HANDLE_EXCEPTION value=10 refcount= 2 is_ref= 1 After opcode #5: As its FCALL_BY_NAME extra checks in SEND_VAR kick in to check arg info for  compile time call by ref.  If so redispatch SEND_REF to do right thing ! Not shown but op2 znode is used to save argument number which is  used to index into arg info structure NULL NULL arg1 arg2 2
Receiving arguments passed by value value=10 refcount= 4 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;;  } $a= 10;  $b= 5;  $c = $a foo($a, $b);  ?> value=10 refcount=3  is_ref= 0 line  #  op  ext  operands -------------------------------------------------- 3  0  RECV  1 1  RECV  2 4  2  INIT_STRING  ~0 3  ADD_STRING  ~0, ~0, 'foo' 4  ADD_STRING  ~0, ~0, '+' 5  ADD_STRING  ~0, ~0, 'called‘ e.t.c  After opcode #1: this is argument number Result op is CV for arg NULL NULL arg1 arg2 2 a b c callers symbol_table x y callee symbol_table
Receiving arguments passed by reference value=10 refcount= 1 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;;  } $a= 10;  $b= 5;  $c = $a foo(&$a, &$b);  ?> value=10 refcount=3  is_ref= 1 line  #  op  ext  operands -------------------------------------------------- 3  0  RECV  1 1  RECV  2 4  2  INIT_STRING  ~0 3  ADD_STRING  ~0, ~0, 'foo' 4  ADD_STRING  ~0, ~0, '+' 5  ADD_STRING  ~0, ~0, 'called‘ e.t.c  value=10 refcount= 3 is_ref= 1 After opcode #1: NULL NULL arg1 arg2 2 a b c symbol_table x y symbol_table
Function binding  <?php function a() { echo &quot;called function a&quot;; } function b() { echo &quot;called fucntio b&quot;; } a(); b();  ?> line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 3  0  NOP 6  1  NOP 10  2  DO_FCALL  0  'a', 0 11  3  DO_FCALL  0  'b', 0 14  4  RETURN  1 5  ZEND_HANDLE_EXCEPTION What are these NOP’s ?
Function binding  ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Conditional Functions  ,[object Object],[object Object],[object Object],[object Object],[object Object],<?php $a= 10; if (a > 10) { function foo()‏ { echo &quot;foo has no parms&quot;; }  } else { function foo($a)‏ { echo &quot;foo has 1 parm&quot;; } }  if (a > 10) { foo();  } else { foo($a); }
Conditional Functions line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 2  0  ECHO  '%0D%0A+' 5  1  ASSIGN  !0, 10 7  2  FETCH_CONSTANT  ~1, 'a' 3  IS_SMALLER  ~2, 10, ~1 4  JMPZ  ~2, ->7 8  5  ZEND_DECLARE_FUNCTION  '%00fooC%3A%5CEclipse-PHP%5C workspace%5CTestcases%5Ctest.php0140E973', 'foo' 12  6  JMP  ->8 13  7  ZEND_DECLARE_FUNCTION   '%00fooC%3A%5CEclipse-PHP%5C workspace%5CTestcases%5Ctest.php0140E9B9', 'foo' 20  8  FETCH_CONSTANT  ~3, 'a' 9  IS_SMALLER  ~4, 10, ~3 10  JMPZ  ~4, ->14 . . . e.t.c . . .
Conditional Functions line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 10  0  ECHO  'foo+has+no+parms' 11  1  RETURN  null 2  ZEND_HANDLE_EXCEPTION line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 13  0  RECV  1 15  1  ECHO  'foo+has+1+parm' 16  2  RETURN  null 3  ZEND_HANDLE_EXCEPTION zend_op_array for foo()‏ zend_op_array for foo($a)‏
Exception Handling <?php function foo($x)‏ { if ($x > 1 ) { throw new Exception; } } try { foo(1); }  catch (Exception $e) { echo &quot;exception 1&quot;; }  try { foo(2); }  catch (Exception $e) { echo &quot;exception 2&quot;; }  ?> line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 3  0  NOP 11  1  SEND_VAL  1 2  DO_FCALL  1  'foo', 0 13  3  ZEND_FETCH_CLASS  :1, 'Exception' 4  ZEND_CATCH  null, 'e' 14  5  ECHO  'exception+1' 18  6  SEND_VAL  2 7  DO_FCALL  1  'foo', 0 20  8  ZEND_FETCH_CLASS  :3, 'Exception' 9  ZEND_CATCH  null, 'e' 21  10  ECHO  'exception+2' 25  11  RETURN  1 12  ZEND_HANDLE_EXCEPTION line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 3  0  RECV  1 5  1  IS_SMALLER  ~0, 1, !0 2  JMPZ  ~0, ->8 6  3  ZEND_FETCH_CLASS  :1, 'Exception' 4  NEW  $2, :1 5  DO_FCALL_BY_NAME  0  0 6  ZEND_THROW  $2 7  7  JMP  ->8 8  8  RETURN  null 9  ZEND_HANDLE_EXCEPTION not shown by VLD but extended value of CATCH opcode contains opcode number to branch too if exception not thrown. if no exception thrown during TRY block then we actually execute the ZEND_FETCH_CLASS and ZEND_CATCH opcodes. ZEND_CATCH on finding no exception thrown dispatches first opcode after end of catch block, i.e 6 in this case
Exception handling ,[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
Exception handling struct _zend_op_array { …… . zend_try_catch_element *try_catch_array; int last_try_catch; … .. etc }; typedef struct _zend_try_catch_element { zend_uint try_op; zend_uint catch_op;  /* ketchup! */ } zend_try_catch_element ; struct _zend_execute_data { struct _zend_op *opline; …… . zend_op_arrary *op_array … .. etc }; contains opcode number of first opcode of  try and catch blocks array is realloacted as every try/catch block found  by compiler
Exception Handling line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 3  0  NOP 11  1  SEND_VAL  1 2  DO_FCALL  1  'foo', 0 13  3  ZEND_FETCH_CLASS  :1, 'Exception' 4  ZEND_CATCH  null, 'e' 14  5  ECHO  'exception+1' 18  6  SEND_VAL  2 7  DO_FCALL  1  'foo', 0 20  8  ZEND_FETCH_CLASS  :3, 'Exception' 9  ZEND_CATCH  null, 'e' 21  10  ECHO  'exception+2' 25  11  RETURN  1 12  ZEND_HANDLE_EXCEPTION line  #  op  fetch  ext  operands ------------------------------------------------------------------------------- 3  0  RECV  1 5  1  IS_SMALLER  ~0, 1, !0 2  JMPZ  ~0, ->8 6  3  ZEND_FETCH_CLASS  :1, 'Exception' 4  NEW  $2, :1 5  DO_FCALL_BY_NAME  0  0 6  ZEND_THROW  $2 7  7  JMP  ->8 8  8  RETURN  null 9  ZEND_HANDLE_EXCEPTION try_op = 1 catch_op = 3 try_op = 6 catch_op = 8 try_catch_array last_try_catch = 2 zend_op_array try_catch_array last_try_catch = 0 zend_op_array null

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Mona cheatsheet
Mona cheatsheetMona cheatsheet
Mona cheatsheet
 
Php and threads ZTS
Php and threads ZTSPhp and threads ZTS
Php and threads ZTS
 
PHP Tips for certification - OdW13
PHP Tips for certification - OdW13PHP Tips for certification - OdW13
PHP Tips for certification - OdW13
 
Unit 4
Unit 4Unit 4
Unit 4
 
Assembler (2)
Assembler (2)Assembler (2)
Assembler (2)
 
Phpをいじり倒す10の方法
Phpをいじり倒す10の方法Phpをいじり倒す10の方法
Phpをいじり倒す10の方法
 
Falcon初印象
Falcon初印象Falcon初印象
Falcon初印象
 
Runtime Symbol Resolution
Runtime Symbol ResolutionRuntime Symbol Resolution
Runtime Symbol Resolution
 
Assembler
AssemblerAssembler
Assembler
 
Assembler
AssemblerAssembler
Assembler
 
Embedded C - Lecture 4
Embedded C - Lecture 4Embedded C - Lecture 4
Embedded C - Lecture 4
 
Unit 5
Unit 5Unit 5
Unit 5
 
C tutorial
C tutorialC tutorial
C tutorial
 
Unit 6
Unit 6Unit 6
Unit 6
 
C tutorial
C tutorialC tutorial
C tutorial
 
C
CC
C
 
Bit manipulation in atmel studio for AVR
Bit manipulation in atmel studio for AVRBit manipulation in atmel studio for AVR
Bit manipulation in atmel studio for AVR
 
Assembler
AssemblerAssembler
Assembler
 
The Php Life Cycle
The Php Life CycleThe Php Life Cycle
The Php Life Cycle
 
Multithreaded sockets c++11
Multithreaded sockets c++11Multithreaded sockets c++11
Multithreaded sockets c++11
 

Ähnlich wie Php opcodes sep2008

Android RenderScript
Android RenderScriptAndroid RenderScript
Android RenderScriptJungsoo Nam
 
Specialized Compiler for Hash Cracking
Specialized Compiler for Hash CrackingSpecialized Compiler for Hash Cracking
Specialized Compiler for Hash CrackingPositive Hack Days
 
Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaCreate your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaPatrick Allaert
 
C Programming Language Tutorial for beginners - JavaTpoint
C Programming Language Tutorial for beginners - JavaTpointC Programming Language Tutorial for beginners - JavaTpoint
C Programming Language Tutorial for beginners - JavaTpointJavaTpoint.Com
 
proxyc CSAPP Web proxy NAME IMPORTANT Giv.pdf
  proxyc  CSAPP Web proxy   NAME    IMPORTANT Giv.pdf  proxyc  CSAPP Web proxy   NAME    IMPORTANT Giv.pdf
proxyc CSAPP Web proxy NAME IMPORTANT Giv.pdfajay1317
 
C programming language tutorial
C programming language tutorial C programming language tutorial
C programming language tutorial javaTpoint s
 
Bare metal performance in Elixir
Bare metal performance in ElixirBare metal performance in Elixir
Bare metal performance in ElixirAaron Seigo
 
Pragmatic Optimization in Modern Programming - Demystifying the Compiler
Pragmatic Optimization in Modern Programming - Demystifying the CompilerPragmatic Optimization in Modern Programming - Demystifying the Compiler
Pragmatic Optimization in Modern Programming - Demystifying the CompilerMarina Kolpakova
 
C from hello world to 010101
C from hello world to 010101C from hello world to 010101
C from hello world to 010101Bellaj Badr
 
Msfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheetMsfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheetCe.Se.N.A. Security
 
Something About Dynamic Linking
Something About Dynamic LinkingSomething About Dynamic Linking
Something About Dynamic LinkingWang Hsiangkai
 
External Language Stored Procedures for MySQL
External Language Stored Procedures for MySQLExternal Language Stored Procedures for MySQL
External Language Stored Procedures for MySQLAntony T Curtis
 
Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -LynellBull52
 
Hooking signals and dumping the callstack
Hooking signals and dumping the callstackHooking signals and dumping the callstack
Hooking signals and dumping the callstackThierry Gayet
 
Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]
Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]
Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]RootedCON
 

Ähnlich wie Php opcodes sep2008 (20)

Android RenderScript
Android RenderScriptAndroid RenderScript
Android RenderScript
 
Qe Reference
Qe ReferenceQe Reference
Qe Reference
 
GCC RTL and Machine Description
GCC RTL and Machine DescriptionGCC RTL and Machine Description
GCC RTL and Machine Description
 
Specialized Compiler for Hash Cracking
Specialized Compiler for Hash CrackingSpecialized Compiler for Hash Cracking
Specialized Compiler for Hash Cracking
 
C++ Functions
C++ FunctionsC++ Functions
C++ Functions
 
Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaCreate your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 Verona
 
C Programming Language Tutorial for beginners - JavaTpoint
C Programming Language Tutorial for beginners - JavaTpointC Programming Language Tutorial for beginners - JavaTpoint
C Programming Language Tutorial for beginners - JavaTpoint
 
proxyc CSAPP Web proxy NAME IMPORTANT Giv.pdf
  proxyc  CSAPP Web proxy   NAME    IMPORTANT Giv.pdf  proxyc  CSAPP Web proxy   NAME    IMPORTANT Giv.pdf
proxyc CSAPP Web proxy NAME IMPORTANT Giv.pdf
 
C programming language tutorial
C programming language tutorial C programming language tutorial
C programming language tutorial
 
Quiz 9
Quiz 9Quiz 9
Quiz 9
 
Bare metal performance in Elixir
Bare metal performance in ElixirBare metal performance in Elixir
Bare metal performance in Elixir
 
Pragmatic Optimization in Modern Programming - Demystifying the Compiler
Pragmatic Optimization in Modern Programming - Demystifying the CompilerPragmatic Optimization in Modern Programming - Demystifying the Compiler
Pragmatic Optimization in Modern Programming - Demystifying the Compiler
 
C from hello world to 010101
C from hello world to 010101C from hello world to 010101
C from hello world to 010101
 
Msfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheetMsfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheet
 
Something About Dynamic Linking
Something About Dynamic LinkingSomething About Dynamic Linking
Something About Dynamic Linking
 
External Language Stored Procedures for MySQL
External Language Stored Procedures for MySQLExternal Language Stored Procedures for MySQL
External Language Stored Procedures for MySQL
 
Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -Compiler Design and Construction COSC 5353Project Instructions -
Compiler Design and Construction COSC 5353Project Instructions -
 
Hooking signals and dumping the callstack
Hooking signals and dumping the callstackHooking signals and dumping the callstack
Hooking signals and dumping the callstack
 
Writing MySQL UDFs
Writing MySQL UDFsWriting MySQL UDFs
Writing MySQL UDFs
 
Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]
Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]
Sergi Álvarez & Roi Martín - Radare2 Preview [RootedCON 2010]
 

Php opcodes sep2008

  • 1.
  • 2.
  • 3. Execution path for a script php_execute_script()‏ zend_execute_scripts()‏ zend_execute()‏ user call (function/method )‏ include/require zend_compile_file()‏
  • 4.
  • 5.
  • 6.
  • 7.
  • 8. Non-PHP statements line # op fetch ext operands ------------------------------------------------------------------------------- 3 0 ECHO '%3C%21--+example+for+ PHP+5.0.0+final+release+--%3E%0D%0A%0D%0A' 5 1 ASSIGN !0, 'localhost' 6 2 ASSIGN !1, 'root' 7 3 ASSIGN !2, '' 9 4 INIT_FCALL_BY_NAME 'mysql_connect' …… .. snip …. 22 ADD_STRING ~5, ~5, 'MySQL' 23 ASSIGN !4, ~5 14 24 JMP ->25 26 25 ECHO '%0D%0A%3Chtml%3E%0D%0A %0D%0A+%3Chead%3E%0D%0A++%3Ctitle%3EConnecting+user%3C%2Ftitle%3E%0D%0A+%3C%2Fhead%3E%0D %0A%0D%0A+%3Cbody%3E%0D%0A++%3Ch3%3E+%0D%0A+++' 26 ECHO !4 30 27 ECHO '+%0D%0A++%3C%2Fh3%3E %0D%0A+%3C%2Fbody%3E%0D%0A%0D%0A%3C%2Fhtml%3E' 28 RETURN 1 29 ZEND_HANDLE_EXCEPTION
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16. State of play after compile complete opcodes zend_op_array active_oparray symbol_table active_symbol_table function_table class_table executor_globals symbol_table function_table <?php function add5($a) { return $a + 5; } function sub5($a) { return $a - 5; } $a = add5(10); $b = sub5(15); ?> zend_op_array zend_op_array zend_internal_fucntion op_array for global scope zend_internal_fucntion GLOBALS _ENV HTTP_ENV_VARS …… . <internal func> add5 sub5 …… . <internal func>
  • 17.
  • 18.
  • 19. State of play after compile complete : opcodes zend_op_array active_oparray symbol_table active_smbol_table function_table class_table executor_globals symbol_table class_table <?php class Dog { function bark()‏ { print &quot;Woof!&quot;; } function sit()‏ { print “Sit!!”; } } $pooch = new Dog; $pooch ->bark(); $pooch ->sit(); ?> zend_op_array function_table function_table zend_op_array function_table zend_internal_fucntion zend_internal_fucntion GLOBALS _ENV HTTP_ENV_VARS …… . <internal class> Dog …… . bark sit …… . <internal func> <internal func> …… . <internal method> <internal method> …… .
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25. VLD output line # op fetch ext operands -------------------------------------------------------------------------- 2 0 ECHO '%0A' 4 1 ASSIGN !0, 5 5 2 ASSIGN !1, 10 6 3 ADD ~2, !0, !1 4 ADD ~3, ~2, 99 5 ASSIGN !2, ~3 8 6 INIT_STRING ~5 7 ADD_STRING ~5, ~5, 'c' 8 ADD_STRING ~5, ~5, '%3D+' 9 ADD_VAR ~5, ~5, !2 10 ADD_STRING ~5, ~5, '+' 11 ADD_CHAR ~5, ~5, 10 12 ECHO ~5 11 13 RETURN 1 14 ZEND_HANDLE_EXCEPTION c= 114 <?php $a = 5; $b = 10; $c = $a + $b + 99; echo &quot;c= $c &quot;; ?> php -f test.php -dvld.active=1 KEY ! == compiler variable $ == variable ~ == temporary There are TMP’s defied for results here but they are not used and VLD does not list them
  • 26. Why all these “+” in VLD output for CONST’s ? <?php echo &quot;Hello World&quot;; echo &quot;Hello World&quot;; echo &quot;Hello + World&quot;; ?> line # op fetch ext operands ------------------------------------------------------------------------------- 2 0 ECHO '%0D%0A+' 4 1 ECHO 'Hello+World' 5 2 ECHO 'Hello++++++++++++++++++++++++++++++++World' 6 3 ECHO 'Hello+%2B+World' 9 4 RETURN 1 5 ZEND_HANDLE_EXCEPTION Answer: VLD calls php_url_encode() on the CONST to format it before output which amongst other things converts all spaces to “+”. Internally white space is stored as 0x20 as you would expect.
  • 27.
  • 28.
  • 29. parsekit-compile-string: SIMPLE output <?php $oparray = parsekit_compile_string('echo &quot;HelloWorld&quot;;', $errors, PARSEKIT_SIMPLE); var_dump($oparray); ?> array(5) { [0]=> string(36) &quot;ZEND_ECHO UNUSED 'HelloWorld' UNUSED&quot; [1]=> string(30) &quot;ZEND_RETURN UNUSED NULL UNUSED&quot; [2]=> string(42) &quot;ZEND_HANDLE_EXCEPTION UNUSED UNUSED UNUSED&quot; [&quot;function_table&quot;]=> NULL [&quot;class_table&quot;]=> NULL }
  • 30. parsekit-compile-file: QUIET output <?php $oparray = parsekit_compile_string('echo &quot;HelloWorld&quot;;', $errors, PARSEKIT_QUIET); var_dump($oparray); ?> array(20) { [&quot;type&quot;]=> int(2)‏ [&quot;type_name&quot;]=> string(18) &quot;ZEND_USER_FUNCTION&quot; [&quot;fn_flags&quot;]=> int(0)‏ [&quot;num_args&quot;]=> int(0)‏ [&quot;required_num_args&quot;]=> int(0)‏ [&quot;pass_rest_by_reference&quot;]=> bool(false)‏ [&quot;uses_this&quot;]=> bool(false)‏ [&quot;line_start&quot;]=> int(0)‏ [&quot;line_end&quot;]=> int(0)‏ [&quot;return_reference&quot;]=> bool(false)‏ [&quot;refcount&quot;]=> int(1)‏ [&quot;last&quot;]=> int(3)‏ [&quot;size&quot;]=> int(3)‏ [&quot;T&quot;]=> int(0)‏ [&quot;last_brk_cont&quot;]=> int(0)‏ [&quot;current_brk_cont&quot;]=> int(-1)‏ [&quot;backpatch_count&quot;]=> int(0)‏ [&quot;done_pass_two&quot;]=> bool(true)‏ [&quot;filename&quot;]=> string(49) &quot;C:estcaseselloWorld.php&quot; [&quot;opcodes&quot;]=> array(3) { [0]=> array(5) { [&quot;opcode&quot;]=> int(40)‏ [&quot;opcode_name&quot;]=> string(9) &quot;ZEND_ECHO&quot; [&quot;flags&quot;]=> int(768)‏ [&quot;op1&quot;]=> array(3) { [&quot;type&quot;]=> int(1)‏ [&quot;type_name&quot;]=> string(8) &quot;IS_CONST&quot; [&quot;constant&quot;]=> &string(11) &quot;Hello World&quot; } [&quot;lineno&quot;]=> int(3)‏ etc…..
  • 31. parsekit-func-arginfo <? php function foo ($a, stdClass $b, &$c) { } $oparray = parsekit_func_arginfo (‘foo’); var_dump($oparray); ?> array(3) { [0]=> array(3) { [&quot;name&quot;]=> string(1) &quot;a&quot; [&quot;allow_null&quot;]=> bool(true)‏ [&quot;pass_by_reference&quot;]=> bool(false)‏ } [1]=> array(4) { [&quot;name&quot;]=> string(1) &quot;b&quot; [&quot;class_name&quot;]=> string(8) &quot;stdClass&quot; [&quot;allow_null&quot;]=> bool(false)‏ [&quot;pass_by_reference&quot;]=> bool(false)‏ } [2]=> array(3) { [&quot;name&quot;]=> string(1) &quot;c&quot; [&quot;allow_null&quot;]=> bool(true)‏ [&quot;pass_by_reference&quot;]=> bool(true)‏ } }
  • 32. parsekit-opcode-name <?php $opname = parsekit_opcode_name (61); var_dump($opname); ?> string(21) &quot;ZEND_DO_FCALL_BY_NAME&quot; <?php $opflags = parsekit_opcode_flags (61); var_dump($opflags); ?> int(16777218)‏ flags define whether opcode takes op1 and op2, defines EA, sets a result etc
  • 33. Execution path for a script php_execute_script()‏ zend_execute_scripts()‏ zend_execute()‏ user call (function/method )‏ include/require zend_compile_file()‏
  • 34.
  • 35. Interpreter generation process zend_vm_gen.php zend_vm_execute.skl zend_vm_def.h zend_vm-execute.h zend_vm_opcodes.h
  • 36. zend_vm_execute.skl {%DEFINES%} ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)‏ { zend_execute_data execute_data; {%HELPER_VARS%} {%INTERNAL_LABELS%} if (EG(exception)) { return; } /* Initialize execute_data */ EX(fbc) = NULL; EX(object) = NULL; EX(old_error_reporting) = NULL; if (op_array->T < TEMP_VAR_STACK_LIMIT) { EX(Ts) = (temp_variable *) do_alloca(sizeof(temp_variable) * op_array->T); } else { EX(Ts) = (temp_variable *) safe_emalloc(sizeof(temp_variable), op_array->T, 0); } …… etc triggers to zend_vmg_gen.php to insert generated code
  • 37. zend_vm_defs.h ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)‏ { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE(); } opcode opcode name types accepted for op1 types accepted for op2 .. although this is just a macro! helper function triggers to php code to replace text
  • 38.
  • 39.
  • 40.
  • 41. zend_vm_defs.h ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)‏ { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); ZEND_VM_NEXT_OPCODE(); }
  • 42. ZEND_ADD without specialization static int ZEND_ADD_HANDLER(ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, get_zval_ptr(&opline->op1, EX(Ts), &free_op1, BP_VAR_R), get_zval_ptr(&opline->op2, EX(Ts), &free_op2, BP_VAR_R)‏ TSRMLS_CC); FREE_OP(free_op1); FREE_OP(free_op2); ZEND_VM_NEXT_OPCODE(); } Handler calls non-type specific routines to get zval * for op1 and op2
  • 43. ZEND_ADD with specialization static int ZEND_ADD_SPEC_CONST_CONST_HANDLER (ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); add_function(&EX_T(opline->result.u.var).tmp_var, &opline->op1.u.constant, &opline->op2.u.constant TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); } static int ZEND_ADD_SPEC_CONST_TMP_HANDLER (ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); zend_free_op free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, &opline->op1.u.constant, _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)‏ TSRMLS_CC); zval_dtor(free_op2.var); ZEND_VM_NEXT_OPCODE(); } static int ZEND_ADD_SPEC_CONST_VAR_HANDLER (ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); zend_free_op free_op2; add_function(&EX_T(opline->result.u.var).tmp_var, &opline->op1.u.constant, _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)‏ TSRMLS_CC); if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; ZEND_VM_NEXT_OPCODE(); } … . and 13 other handlers Handlers call type specific routines to get zval * for op1 and op2
  • 44. zend_vm_gen.php $op1_get_zval_ptr = array( &quot;ANY&quot; => &quot;get_zval_ptr(&opline->op1, EX(Ts), &free_op1, 1 )&quot;, &quot;TMP&quot; => &quot;_get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)&quot;, &quot;VAR&quot; => &quot;_get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)&quot;, &quot;CONST&quot; => &quot;&opline->op1.u.constant&quot;, &quot;UNUSED&quot; => &quot;NULL&quot;, &quot;CV&quot; => &quot;_get_zval_ptr_cv(&opline->op1, EX(Ts), 1 TSRMLS_CC)&quot;, ); $op2_get_zval_ptr = array( &quot;ANY&quot; => &quot;get_zval_ptr(&opline->op2, EX(Ts), &free_op2, 1)&quot;, &quot;TMP&quot; => &quot;_get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)&quot;, &quot;VAR&quot; => &quot;_get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)&quot;, &quot;CONST&quot; => &quot;&opline->op2.u.constant&quot;, &quot;UNUSED&quot; => &quot;NULL&quot;, &quot;CV&quot; => &quot;_get_zval_ptr_cv(&opline->op2, EX(Ts), 1 TSRMLS_CC)&quot;, … ..<snip> function gen_code(….)‏ …… $code = preg_replace( array( ......... &quot;/GET_OP1_ZVAL_PTR([^)]*)/&quot;, &quot;/GET_OP2_ZVAL_PTR([^)]*)/&quot;, ........ ), array( ....... ....... $op1_get_zval_ptr[$op1], $op2_get_zval_ptr[$op2], ....... ), $code);
  • 45. Generated code not always the best !! static int ZEND_INIT_ARRAY_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)‏ { zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); if (IS_CONST == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if 0 || IS_CONST != IS_UNUSED } else { return ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); #endif } } ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV)‏ { zend_op *opline = EX(opline); array_init(&EX_T(opline->result.u.var).tmp_var); if (OP1_TYPE == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if !defined(ZEND_VM_SPEC) || OP1_TYPE != IS_UNUSED } else { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_ADD_ARRAY_ELEMENT); #endif } } Input: zend_vm-def.h Output: zend_vm-execute.h
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51. VAR variables FETCH_W $0, 'a' /* Retrieve the $a variable for writing */ ASSIGN $0, 123 /* Assign the numeric value 123 to retrieved variable 0 */ FETCH_W $2, 'b' /* Retrieve the $b variable for writing */ ASSIGN $2, 456 /* Assign the numeric value 456 to retrieved variable 2 */ FETCH_R $5, 'a' /* Retrieve the $a variable for reading */ FETCH_R $6, 'b' /* Retrieve the $b variable for reading */ ADD ~7, $5, $6 /* Add the retrieved variables (5 & 6) together and store the result in 7 */ FETCH_W $4, 'c' /* Retrieve the $c variable for writing */ ASSIGN $4, ~7 /* Assign the value in temporary variable 7 into retrieved variable 4 */ FETCH_R $9, 'c' /* Retrieve the $c variable for reading */ ECHO $9 /* Echo the retrieved variable 9 */ <?php $a = 123; $b = 456; $c = $a + $b; echo $c; ?> Note: Each time $a is accessed we look it up in symbol table and store result in a different VAR
  • 52. VAR variables typedef union _temp_variable { zval tmp_var; struct { zval **ptr_ptr; zval *ptr; zend_bool fcall_returned_reference; } var; … etc } temp_variable; ZVAL typedef union _temp_variable { zval tmp_var; struct { zval **ptr_ptr; zval *ptr; zend_bool fcall_returned_reference; } var; … etc } temp_variable; ZVAL After FETCH_R After FETCH_RW or FETCH_W pDataPtr symbol_table pDataPtr symbol_table
  • 53.
  • 54.
  • 55.
  • 56. Compiled variables: with regular variables <?php $a = 123; $b = 456; $c = $a + $b; echo $c; ?> FETCH_W $0, 'a' /* Retrieve the $a variable for writing */ ASSIGN $0, 123 /* Assign the numeric value 123 to retrieved variable 0 */ FETCH_W $2, 'b' /* Retrieve the $b variable for writing */ ASSIGN $2, 456 /* Assign the numeric value 456 to retrieved variable 2 */ FETCH_R $5, 'a' /* Retrieve the $a variable for reading */ FETCH_R $6, 'b' /* Retrieve the $b variable for reading */ ADD ~7, $5, $6 /* Add the retrieved variables (5 & 6) together and store the result in 7 */ FETCH_W $4, 'c' /* Retrieve the $c variable for writing */ ASSIGN $4, ~7 /* Assign the value in temporary variable 7 into retrieved variable 4 */ FETCH_R $9, 'c' /* Retrieve the $c variable for reading */ ECHO $9 /* Echo the retrieved variable 9 */ ASSIGN !0, 123 /* Assign the numeric value 123 to compiled variable 0 */ ASSIGN !1, 456 /* Assign the numeric value 456 to compiled variable 1 */ ADD ~2, !0, !1 /* Add compiled variable 0 to compiled variable 1 */ ASSIGN !2, ~2 /* Assign the value of temporary variable 2 to compiled variable 2 */ ECHO !2 /* Echo the value of compiled variable 2 */ Without CV With CV
  • 57. Compiled variables : with Object variables <?php $f->a = 123; $f->b = 456; $f->c = $f->a + $F->b; echo $f->c; ?> ASSIGN_OBJ !0, 'a' /* Assign the numeric value 123 to property 'a' of compiled variable 0 object */ OP_DATA 123 /* Additional data for ASSIGN_OBJ opcode */ ASSIGN_OBJ !0, 'b' /* Assign the numeric value 456 to property 'b' of compiled variable 0 object */ OP_DATA 456 /* Additional data for ASSIGN_OBJ opcode */ FETCH_OBJ_R $3, !0, 'a‘ /* Retrieve property 'a' from compiled variable 0 object */ FETCH_OBJ_R $4, !0, 'b‘ /* Retrieve property 'b' from compiled variable 0 object */ ADD ~5, $3, $4 /* Add those values and store the result in temp var 5 */ ASSIGN_OBJ !0, 'c' /* Assign the ADD result to property 'c' of compiled variable 0 object */ OP_DATA ~5 /* Additional data for ASSIGN_OBJ opcode */ FETCH_OBJ_R $6, !0, 'c‘ /* Retrieve property 'c' from compiled variable 0 object */ ECHO $6 /* Echo the value */ With CV Note: Properties are re-fetched every time a read or write is performed on them which cannot be avoided due to the magic methods _get(), _set() e.t.c. which can return a different variable on different fetches
  • 58.
  • 59.
  • 60.
  • 61. Static Variables <?php function foo() { static $count = 0; $count ++; } foo(); foo(); foo(); ?> line # op fetch ext operands ------------------------------------------------------------------------------- 5 0 FETCH_W static $0, 'count' 1 ASSIGN_REF !0, $0 6 2 POST_INC ~1, !0 3 FREE ~1 8 4 RETURN null 5 ZEND_HANDLE_EXCEPTION vld output for foo()‏ count value=0 is_ref=0 refount=1 zval count static_variables EG(active_symbol_table)‏ value=0 is_ref=1 refount=2 <?php function foo() { static $count = 0; $count ++; } foo(); foo(); foo(); ?> <?php function foo() { static $count = 0; $count ++; } foo(); foo(); foo(); ?> value=1 is_ref=1 refount=2
  • 62.
  • 63. Function calling <?php $a= 10; $b= 5; foo($a, $b); function foo(&$x, &$y) { echo &quot;foo called with: $x $y&quot;; } foo($a, $b); ?> line # op fetch ext operands ---------------------------------------------------- ------------------- 2 0 ECHO '%0D%0A+' 4 1 ASSIGN !0, 10 5 2 ASSIGN !1, 5 6 3 INIT_FCALL_BY_NAME 'foo' 4 SEND_VAR !0 5 SEND_VAR !1 6 DO_FCALL_BY_NAME 2 0 8 7 NOP 14 8 SEND_REF !0 9 SEND_REF !1 10 DO_FCALL 2 'foo', 0 17 11 RETURN 1 12 ZEND_HANDLE_EXCEPTION SEND_VAR opcode’s extended_value set when FCALL_BY_NAME to force SEND_VAR handler to check expected args at RUNTIME and if call by REF expected it re-dispatches SEND_REF handler Uses EX(fbc) set by INIT_FCALL_BY_NAME to access required arg info. extended_value on FCALL opcode is number of arguments passed opcodes for global scope
  • 64.
  • 65. Example 1: Passing arguments by value without splitting line # op ext operands -------------------------------------------------- 3 0 NOP 8 1 ASSIGN !0, 10 9 2 ASSIGN !1, 5 10 3 ASSIGN !2, !0 12 4 SEND_VAR !0 5 SEND_VAR !1 6 DO_FCALL 2 'foo', 0 15 7 RETURN 1 8 ZEND_HANDLE_EXCEPTION value=10 refcount= 3 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;; } $a= 10; $b= 5; $c= $a foo($a, $b); ?> value=5 refcount=2 is_ref= 0 a b c symbol_table After opcode #5: number of args opcodes for global scope no need to split zval for $a as its part of a “copy on write” set NULL NULL arg1 arg2 2
  • 66. Example 2: Passing arguments by value when splitting required line # op ext operands ------------------------------------------------- 3 0 NOP 8 1 ASSIGN !0, 10 9 2 ASSIGN !1, 5 10 3 ASSIGN !2, !0 12 4 SEND_VAR !0 5 SEND_VAR !1 6 DO_FCALL 2 'foo', 0 15 7 RETURN 1 8 ZEND_HANDLE_EXCEPTION <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;; } $a= 10; $b= 5; $c= &$a foo($a, $b); ?> After opcode #5: we have to split zval for $a as its part of a “change on write” set opcodes for global scope NULL NULL arg1 arg2 2 value=10 refcount= 2 is_ref= 1 argument_stack value=5 refcount=2 is_ref= 0 a b c symbol_table value=10 refcount=1 is_ref= 0
  • 67. Example 3: Passing arguments by reference when splitting required value=10 refcount= 1 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;; } $a= 10; $b= 5; $c = $a foo(&$a, &$b); ?> value=10 refcount=2 is_ref= 1 a b c symbol_table CV is actually in op1 not result operand line # op ext operands ------------------------------------------------ 3 0 NOP 8 1 ASSIGN !0, 10 9 2 ASSIGN !1, 5 10 3 ASSIGN !2, !0 11 4 SEND_REF !0 5 SEND_REF !1 6 DO_FCALL 2 'foo', 0 14 7 RETURN 1 8 ZEND_HANDLE_EXCEPTION value=10 refcount= 2 is_ref= 1 After opcode #5: here we have to split zval for $a as its part of a “copy on write” set NULL NULL arg1 arg2 2
  • 68. Example 4: Passing arguments by reference (compile time)‏ value=10 refcount= 1 is_ref= 0 argument_stack <?php $a= 10; $b= 5; $c= $a; foo($a, $b); function foo(&$x, &$y) { echo &quot;foo called with: $x $y&quot;; } ?> value=10 refcount=2 is_ref= 1 a b c symbol_table line # op ext operands ---------------------------------------------------- 5 0 ASSIGN !0, 10 6 1 ASSIGN !1, 5 7 2 ASSIGN !2, !0 8 3 INIT_FCALL_BY_NAME 'foo' 4 SEND_VAR !0 5 SEND_VAR !1 6 DO_FCALL_BY_NAME 2 0 10 7 NOP 16 8 RETURN 1 9 ZEND_HANDLE_EXCEPTION value=10 refcount= 2 is_ref= 1 After opcode #5: As its FCALL_BY_NAME extra checks in SEND_VAR kick in to check arg info for compile time call by ref. If so redispatch SEND_REF to do right thing ! Not shown but op2 znode is used to save argument number which is used to index into arg info structure NULL NULL arg1 arg2 2
  • 69. Receiving arguments passed by value value=10 refcount= 4 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;; } $a= 10; $b= 5; $c = $a foo($a, $b); ?> value=10 refcount=3 is_ref= 0 line # op ext operands -------------------------------------------------- 3 0 RECV 1 1 RECV 2 4 2 INIT_STRING ~0 3 ADD_STRING ~0, ~0, 'foo' 4 ADD_STRING ~0, ~0, '+' 5 ADD_STRING ~0, ~0, 'called‘ e.t.c After opcode #1: this is argument number Result op is CV for arg NULL NULL arg1 arg2 2 a b c callers symbol_table x y callee symbol_table
  • 70. Receiving arguments passed by reference value=10 refcount= 1 is_ref= 0 argument_stack <?php function foo($x, $y) { echo &quot;foo called with: $x $y&quot;; } $a= 10; $b= 5; $c = $a foo(&$a, &$b); ?> value=10 refcount=3 is_ref= 1 line # op ext operands -------------------------------------------------- 3 0 RECV 1 1 RECV 2 4 2 INIT_STRING ~0 3 ADD_STRING ~0, ~0, 'foo' 4 ADD_STRING ~0, ~0, '+' 5 ADD_STRING ~0, ~0, 'called‘ e.t.c value=10 refcount= 3 is_ref= 1 After opcode #1: NULL NULL arg1 arg2 2 a b c symbol_table x y symbol_table
  • 71. Function binding <?php function a() { echo &quot;called function a&quot;; } function b() { echo &quot;called fucntio b&quot;; } a(); b(); ?> line # op fetch ext operands ------------------------------------------------------------------------------- 3 0 NOP 6 1 NOP 10 2 DO_FCALL 0 'a', 0 11 3 DO_FCALL 0 'b', 0 14 4 RETURN 1 5 ZEND_HANDLE_EXCEPTION What are these NOP’s ?
  • 72.
  • 73.
  • 74. Conditional Functions line # op fetch ext operands ------------------------------------------------------------------------------- 2 0 ECHO '%0D%0A+' 5 1 ASSIGN !0, 10 7 2 FETCH_CONSTANT ~1, 'a' 3 IS_SMALLER ~2, 10, ~1 4 JMPZ ~2, ->7 8 5 ZEND_DECLARE_FUNCTION '%00fooC%3A%5CEclipse-PHP%5C workspace%5CTestcases%5Ctest.php0140E973', 'foo' 12 6 JMP ->8 13 7 ZEND_DECLARE_FUNCTION '%00fooC%3A%5CEclipse-PHP%5C workspace%5CTestcases%5Ctest.php0140E9B9', 'foo' 20 8 FETCH_CONSTANT ~3, 'a' 9 IS_SMALLER ~4, 10, ~3 10 JMPZ ~4, ->14 . . . e.t.c . . .
  • 75. Conditional Functions line # op fetch ext operands ------------------------------------------------------------------------------- 10 0 ECHO 'foo+has+no+parms' 11 1 RETURN null 2 ZEND_HANDLE_EXCEPTION line # op fetch ext operands ------------------------------------------------------------------------------- 13 0 RECV 1 15 1 ECHO 'foo+has+1+parm' 16 2 RETURN null 3 ZEND_HANDLE_EXCEPTION zend_op_array for foo()‏ zend_op_array for foo($a)‏
  • 76. Exception Handling <?php function foo($x)‏ { if ($x > 1 ) { throw new Exception; } } try { foo(1); } catch (Exception $e) { echo &quot;exception 1&quot;; } try { foo(2); } catch (Exception $e) { echo &quot;exception 2&quot;; } ?> line # op fetch ext operands ------------------------------------------------------------------------------- 3 0 NOP 11 1 SEND_VAL 1 2 DO_FCALL 1 'foo', 0 13 3 ZEND_FETCH_CLASS :1, 'Exception' 4 ZEND_CATCH null, 'e' 14 5 ECHO 'exception+1' 18 6 SEND_VAL 2 7 DO_FCALL 1 'foo', 0 20 8 ZEND_FETCH_CLASS :3, 'Exception' 9 ZEND_CATCH null, 'e' 21 10 ECHO 'exception+2' 25 11 RETURN 1 12 ZEND_HANDLE_EXCEPTION line # op fetch ext operands ------------------------------------------------------------------------------- 3 0 RECV 1 5 1 IS_SMALLER ~0, 1, !0 2 JMPZ ~0, ->8 6 3 ZEND_FETCH_CLASS :1, 'Exception' 4 NEW $2, :1 5 DO_FCALL_BY_NAME 0 0 6 ZEND_THROW $2 7 7 JMP ->8 8 8 RETURN null 9 ZEND_HANDLE_EXCEPTION not shown by VLD but extended value of CATCH opcode contains opcode number to branch too if exception not thrown. if no exception thrown during TRY block then we actually execute the ZEND_FETCH_CLASS and ZEND_CATCH opcodes. ZEND_CATCH on finding no exception thrown dispatches first opcode after end of catch block, i.e 6 in this case
  • 77.
  • 78. Exception handling struct _zend_op_array { …… . zend_try_catch_element *try_catch_array; int last_try_catch; … .. etc }; typedef struct _zend_try_catch_element { zend_uint try_op; zend_uint catch_op; /* ketchup! */ } zend_try_catch_element ; struct _zend_execute_data { struct _zend_op *opline; …… . zend_op_arrary *op_array … .. etc }; contains opcode number of first opcode of try and catch blocks array is realloacted as every try/catch block found by compiler
  • 79. Exception Handling line # op fetch ext operands ------------------------------------------------------------------------------- 3 0 NOP 11 1 SEND_VAL 1 2 DO_FCALL 1 'foo', 0 13 3 ZEND_FETCH_CLASS :1, 'Exception' 4 ZEND_CATCH null, 'e' 14 5 ECHO 'exception+1' 18 6 SEND_VAL 2 7 DO_FCALL 1 'foo', 0 20 8 ZEND_FETCH_CLASS :3, 'Exception' 9 ZEND_CATCH null, 'e' 21 10 ECHO 'exception+2' 25 11 RETURN 1 12 ZEND_HANDLE_EXCEPTION line # op fetch ext operands ------------------------------------------------------------------------------- 3 0 RECV 1 5 1 IS_SMALLER ~0, 1, !0 2 JMPZ ~0, ->8 6 3 ZEND_FETCH_CLASS :1, 'Exception' 4 NEW $2, :1 5 DO_FCALL_BY_NAME 0 0 6 ZEND_THROW $2 7 7 JMP ->8 8 8 RETURN null 9 ZEND_HANDLE_EXCEPTION try_op = 1 catch_op = 3 try_op = 6 catch_op = 8 try_catch_array last_try_catch = 2 zend_op_array try_catch_array last_try_catch = 0 zend_op_array null