2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Dmitry Stogov <dmitry@php.net> |
16 | Xinchen Hui <laruence@php.net> |
17 +----------------------------------------------------------------------+
21 #define DISASM_INTEL_SYNTAX 0
23 #include "jit/libudis86/itab.c"
24 #include "jit/libudis86/decode.c"
25 #include "jit/libudis86/syn.c"
26 #if DISASM_INTEL_SYNTAX
27 # include "jit/libudis86/syn-intel.c"
29 # include "jit/libudis86/syn-att.c"
31 #include "jit/libudis86/udis86.c"
33 static void zend_jit_disasm_add_symbol(const char *name,
38 # include "jit/zend_elf.c"
41 #include "zend_sort.h"
56 struct _sym_node *parent;
57 struct _sym_node *child[2];
62 static void zend_syms_rotateleft(zend_sym_node *p) {
63 zend_sym_node *r = p->child[1];
64 p->child[1] = r->child[0];
66 r->child[0]->parent = p;
68 r->parent = p->parent;
69 if (p->parent == NULL) {
71 } else if (p->parent->child[0] == p) {
72 p->parent->child[0] = r;
74 p->parent->child[1] = r;
80 static void zend_syms_rotateright(zend_sym_node *p) {
81 zend_sym_node *l = p->child[0];
82 p->child[0] = l->child[1];
84 l->child[1]->parent = p;
86 l->parent = p->parent;
87 if (p->parent == NULL) {
89 } else if (p->parent->child[1] == p) {
90 p->parent->child[1] = l;
92 p->parent->child[0] = l;
98 static void zend_jit_disasm_add_symbol(const char *name,
103 size_t len = strlen(name);
105 sym = malloc(sizeof(zend_sym_node) + len + 1);
110 sym->end = (addr + size - 1);
111 memcpy((char*)&sym->name, name, len + 1);
112 sym->parent = sym->child[0] = sym->child[1] = NULL;
114 if (JIT_G(symbols)) {
115 zend_sym_node *node = JIT_G(symbols);
117 /* insert it into rbtree */
119 if (sym->addr > node->addr) {
120 ZEND_ASSERT(sym->addr > (node->end));
121 if (node->child[1]) {
122 node = node->child[1];
124 node->child[1] = sym;
128 } else if (sym->addr < node->addr) {
129 if (node->child[0]) {
130 node = node->child[0];
132 node->child[0] = sym;
137 ZEND_ASSERT(sym->addr == node->addr);
138 if (strcmp(name, node->name) == 0 && sym->end < node->end) {
139 /* reduce size of the existing symbol */
140 node->end = sym->end;
147 /* fix rbtree after instering */
148 while (sym && sym != JIT_G(symbols) && sym->parent->info == 1) {
149 if (sym->parent == sym->parent->parent->child[0]) {
150 node = sym->parent->parent->child[1];
151 if (node && node->info == 1) {
152 sym->parent->info = 0;
154 sym->parent->parent->info = 1;
155 sym = sym->parent->parent;
157 if (sym == sym->parent->child[1]) {
159 zend_syms_rotateleft(sym);
161 sym->parent->info = 0;
162 sym->parent->parent->info = 1;
163 zend_syms_rotateright(sym->parent->parent);
166 node = sym->parent->parent->child[0];
167 if (node && node->info == 1) {
168 sym->parent->info = 0;
170 sym->parent->parent->info = 1;
171 sym = sym->parent->parent;
173 if (sym == sym->parent->child[0]) {
175 zend_syms_rotateright(sym);
177 sym->parent->info = 0;
178 sym->parent->parent->info = 1;
179 zend_syms_rotateleft(sym->parent->parent);
184 JIT_G(symbols) = sym;
186 JIT_G(symbols)->info = 0;
189 static void zend_jit_disasm_destroy_symbols(zend_sym_node *n) {
192 zend_jit_disasm_destroy_symbols(n->child[0]);
195 zend_jit_disasm_destroy_symbols(n->child[1]);
201 static const char* zend_jit_disasm_find_symbol(uint64_t addr,
203 zend_sym_node *node = JIT_G(symbols);
205 if (addr < node->addr) {
206 node = node->child[0];
207 } else if (addr > node->end) {
208 node = node->child[1];
210 *offset = addr - node->addr;
217 static const char* zend_jit_disasm_resolver(struct ud *ud,
224 void *a = (void*)(zend_uintptr_t)(addr);
227 name = zend_jit_disasm_find_symbol(addr, offset);
233 && info.dli_sname != NULL
234 && info.dli_saddr == a) {
235 return info.dli_sname;
239 name = zend_jit_disasm_find_symbol(addr, offset);
248 static int zend_jit_cmp_labels(Bucket *b1, Bucket *b2)
250 return ((b1->h > b2->h) > 0) ? 1 : -1;
253 static int zend_jit_disasm(const char *name,
254 const char *filename,
255 const zend_op_array *op_array,
260 const void *end = (void *)((char *)start + size);
264 const struct ud_operand *op;
269 fprintf(stderr, "%s: ; (%s)\n", name, filename ? filename : "unknown");
272 ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
273 ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
275 zend_hash_init(&labels, 8, NULL, NULL, 0);
276 if (op_array && cfg) {
278 for (b = 0; b < cfg->blocks_count; b++) {
279 if (cfg->blocks[b].flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
280 addr = (uint64_t)(uintptr_t)op_array->opcodes[cfg->blocks[b].start].handler;
281 if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
282 zend_hash_index_add(&labels, addr, &zv);
288 while (ud_disassemble(&ud)) {
289 op = ud_insn_opr(&ud, 0);
290 if (op && op->type == UD_OP_JIMM) {
291 addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
292 if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
293 zend_hash_index_add(&labels, addr, &zv);
298 zend_hash_sort(&labels, zend_jit_cmp_labels, 0);
300 /* label numbering */
302 ZEND_HASH_FOREACH_VAL(&labels, z) {
303 if (Z_TYPE_P(z) == IS_FALSE) {
310 } ZEND_HASH_FOREACH_END();
312 ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
313 ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
315 while (ud_disassemble(&ud)) {
316 addr = ud_insn_off(&ud);
317 z = zend_hash_index_find(&labels, addr);
319 if (Z_LVAL_P(z) < 0) {
320 fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
322 fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
325 op = ud_insn_opr(&ud, 0);
326 if (op && op->type == UD_OP_JIMM) {
327 addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
328 if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
329 z = zend_hash_index_find(&labels, addr);
331 const char *str = ud_insn_asm(&ud);
335 while (str[len] != 0 && str[len] != ' ' && str[len] != '\t') {
339 while (str[len] == ' ' || str[len] == '\t') {
342 if (Z_LVAL_P(z) < 0) {
343 fprintf(stderr, "\t%.*s.ENTRY" ZEND_LONG_FMT "\n", len, str, -Z_LVAL_P(z));
345 fprintf(stderr, "\t%.*s.L" ZEND_LONG_FMT "\n", len, str, Z_LVAL_P(z));
352 fprintf(stderr, "\t%s\n", ud_insn_asm(&ud));
354 fprintf(stderr, "\n");
356 zend_hash_destroy(&labels);
361 static int zend_jit_disasm_init(void)
364 #if defined(__x86_64__) || defined(_WIN64)
365 ud_set_mode(&ud, 64);
367 ud_set_mode(&ud, 32);
369 #if DISASM_INTEL_SYNTAX
370 ud_set_syntax(&ud, UD_SYN_INTEL);
372 ud_set_syntax(&ud, UD_SYN_ATT);
374 ud_set_sym_resolver(&ud, zend_jit_disasm_resolver);
377 #define REGISTER_EG(n) \
378 zend_jit_disasm_add_symbol("EG("#n")", \
379 (uint64_t)(uintptr_t)&executor_globals.n, sizeof(executor_globals.n))
380 REGISTER_EG(uninitialized_zval);
381 REGISTER_EG(exception);
382 REGISTER_EG(vm_interrupt);
383 REGISTER_EG(exception_op);
384 REGISTER_EG(timed_out);
385 REGISTER_EG(current_execute_data);
386 REGISTER_EG(vm_stack_top);
387 REGISTER_EG(vm_stack_end);
388 REGISTER_EG(symbol_table);
389 REGISTER_EG(jit_trace_num);
393 /* Register JIT helper functions */
394 #define REGISTER_HELPER(n) \
395 zend_jit_disasm_add_symbol(#n, \
396 (uint64_t)(uintptr_t)n, sizeof(void*));
397 REGISTER_HELPER(memcmp);
398 REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
399 REGISTER_HELPER(zend_jit_find_func_helper);
400 REGISTER_HELPER(zend_jit_find_ns_func_helper);
401 REGISTER_HELPER(zend_jit_find_method_helper);
402 REGISTER_HELPER(zend_jit_find_method_tmp_helper);
403 REGISTER_HELPER(zend_jit_push_static_metod_call_frame);
404 REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp);
405 REGISTER_HELPER(zend_jit_invalid_method_call);
406 REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
407 REGISTER_HELPER(zend_jit_unref_helper);
408 REGISTER_HELPER(zend_jit_extend_stack_helper);
409 REGISTER_HELPER(zend_jit_int_extend_stack_helper);
410 REGISTER_HELPER(zend_jit_leave_nested_func_helper);
411 REGISTER_HELPER(zend_jit_leave_top_func_helper);
412 REGISTER_HELPER(zend_jit_leave_func_helper);
413 REGISTER_HELPER(zend_jit_symtable_find);
414 REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
415 REGISTER_HELPER(zend_jit_hash_lookup_rw);
416 REGISTER_HELPER(zend_jit_symtable_lookup_rw);
417 REGISTER_HELPER(zend_jit_symtable_lookup_w);
418 REGISTER_HELPER(zend_jit_undefined_op_helper);
419 REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
420 REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
421 REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
422 REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
423 REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
424 REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
425 REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
426 REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
427 REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
428 REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
429 REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
430 REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
431 // REGISTER_HELPER(zend_jit_fetch_dim_obj_unset_helper);
432 REGISTER_HELPER(zend_jit_assign_dim_helper);
433 REGISTER_HELPER(zend_jit_assign_dim_op_helper);
434 REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
435 REGISTER_HELPER(zend_jit_fast_concat_helper);
436 REGISTER_HELPER(zend_jit_isset_dim_helper);
437 REGISTER_HELPER(zend_jit_free_call_frame);
438 REGISTER_HELPER(zend_jit_fetch_global_helper);
439 REGISTER_HELPER(zend_jit_verify_arg_slow);
440 REGISTER_HELPER(zend_jit_verify_return_slow);
441 REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
442 REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
443 REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
444 REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
445 REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
446 REGISTER_HELPER(zend_jit_check_array_promotion);
447 REGISTER_HELPER(zend_jit_create_typed_ref);
448 REGISTER_HELPER(zend_jit_extract_helper);
449 REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
450 REGISTER_HELPER(zend_jit_copy_extra_args_helper);
451 REGISTER_HELPER(zend_jit_deprecated_helper);
452 REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
453 REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
454 REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
455 REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
456 REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
457 REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
458 REGISTER_HELPER(zend_jit_post_inc_typed_ref);
459 REGISTER_HELPER(zend_jit_post_dec_typed_ref);
460 REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
461 REGISTER_HELPER(zend_jit_only_vars_by_reference);
462 REGISTER_HELPER(zend_jit_invalid_array_access);
463 REGISTER_HELPER(zend_jit_invalid_property_read);
464 REGISTER_HELPER(zend_jit_invalid_property_write);
465 REGISTER_HELPER(zend_jit_invalid_property_incdec);
466 REGISTER_HELPER(zend_jit_invalid_property_assign);
467 REGISTER_HELPER(zend_jit_invalid_property_assign_op);
468 REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
469 REGISTER_HELPER(zend_jit_pre_inc);
470 REGISTER_HELPER(zend_jit_pre_dec);
471 REGISTER_HELPER(zend_runtime_jit);
472 REGISTER_HELPER(zend_jit_hot_func);
473 REGISTER_HELPER(zend_jit_check_constant);
474 REGISTER_HELPER(zend_jit_get_constant);
475 REGISTER_HELPER(zend_jit_array_free);
476 REGISTER_HELPER(zend_jit_zval_array_dup);
477 REGISTER_HELPER(zend_jit_add_arrays_helper);
478 REGISTER_HELPER(zend_jit_assign_obj_helper);
479 REGISTER_HELPER(zend_jit_assign_obj_op_helper);
480 REGISTER_HELPER(zend_jit_assign_to_typed_prop);
481 REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
482 REGISTER_HELPER(zend_jit_inc_typed_prop);
483 REGISTER_HELPER(zend_jit_dec_typed_prop);
484 REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
485 REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
486 REGISTER_HELPER(zend_jit_post_inc_typed_prop);
487 REGISTER_HELPER(zend_jit_post_dec_typed_prop);
488 REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
489 REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
490 REGISTER_HELPER(zend_jit_post_inc_obj_helper);
491 REGISTER_HELPER(zend_jit_post_dec_obj_helper);
492 #if (PHP_VERSION_ID <= 80100) && (SIZEOF_SIZE_T == 4)
493 REGISTER_HELPER(zval_jit_update_constant_ex);
495 REGISTER_HELPER(zend_jit_free_trampoline_helper);
496 #undef REGISTER_HELPER
499 zend_elf_load_symbols();
502 if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
505 memset(&opline, 0, sizeof(opline));
507 opline.opcode = ZEND_DO_UCALL;
508 opline.result_type = IS_UNUSED;
509 zend_vm_set_opcode_handler(&opline);
510 zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
512 opline.opcode = ZEND_DO_UCALL;
513 opline.result_type = IS_VAR;
514 zend_vm_set_opcode_handler(&opline);
515 zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
517 opline.opcode = ZEND_DO_FCALL_BY_NAME;
518 opline.result_type = IS_UNUSED;
519 zend_vm_set_opcode_handler(&opline);
520 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
522 opline.opcode = ZEND_DO_FCALL_BY_NAME;
523 opline.result_type = IS_VAR;
524 zend_vm_set_opcode_handler(&opline);
525 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
527 opline.opcode = ZEND_DO_FCALL;
528 opline.result_type = IS_UNUSED;
529 zend_vm_set_opcode_handler(&opline);
530 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
532 opline.opcode = ZEND_DO_FCALL;
533 opline.result_type = IS_VAR;
534 zend_vm_set_opcode_handler(&opline);
535 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
537 opline.opcode = ZEND_RETURN;
538 opline.op1_type = IS_CONST;
539 zend_vm_set_opcode_handler(&opline);
540 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
542 opline.opcode = ZEND_RETURN;
543 opline.op1_type = IS_TMP_VAR;
544 zend_vm_set_opcode_handler(&opline);
545 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
547 opline.opcode = ZEND_RETURN;
548 opline.op1_type = IS_VAR;
549 zend_vm_set_opcode_handler(&opline);
550 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
552 opline.opcode = ZEND_RETURN;
553 opline.op1_type = IS_CV;
554 zend_vm_set_opcode_handler(&opline);
555 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
557 zend_jit_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
563 static void zend_jit_disasm_shutdown(void)
565 if (JIT_G(symbols)) {
566 zend_jit_disasm_destroy_symbols(JIT_G(symbols));
567 JIT_G(symbols) = NULL;