]> granicus.if.org Git - php/blob - ext/opcache/jit/zend_jit_disasm.c
Merge branch 'PHP-8.0'
[php] / ext / opcache / jit / zend_jit_disasm.c
1 /*
2    +----------------------------------------------------------------------+
3    | Zend JIT                                                             |
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    |          Hao Sun <hao.sun@arm.com>                                   |
18    +----------------------------------------------------------------------+
19 */
20
21
22 #ifdef HAVE_CAPSTONE
23 # define HAVE_DISASM 1
24 # include <capstone/capstone.h>
25 # define HAVE_CAPSTONE_ITER 1
26 #else
27 # define HAVE_DISASM 1
28 # define DISASM_INTEL_SYNTAX 0
29
30 # include "jit/libudis86/itab.c"
31 # include "jit/libudis86/decode.c"
32 # include "jit/libudis86/syn.c"
33 # if DISASM_INTEL_SYNTAX
34 #  include "jit/libudis86/syn-intel.c"
35 # else
36 #  include "jit/libudis86/syn-att.c"
37 # endif
38 # include "jit/libudis86/udis86.c"
39 #endif /* HAVE_CAPSTONE */
40
41 static void zend_jit_disasm_add_symbol(const char *name,
42                                        uint64_t    addr,
43                                        uint64_t    size);
44
45 #ifndef _WIN32
46 # include "jit/zend_elf.c"
47 #endif
48
49 #include "zend_sort.h"
50
51 #ifndef _GNU_SOURCE
52 # define _GNU_SOURCE
53 #endif
54
55 #ifndef _WIN32
56 #include <dlfcn.h>
57 #endif
58
59 struct _sym_node {
60         uint64_t          addr;
61         uint64_t          end;
62         struct _sym_node *parent;
63         struct _sym_node *child[2];
64         unsigned char     info;
65         char              name[1];
66 };
67
68 static void zend_syms_rotateleft(zend_sym_node *p) {
69         zend_sym_node *r = p->child[1];
70         p->child[1] = r->child[0];
71         if (r->child[0]) {
72                 r->child[0]->parent = p;
73         }
74         r->parent = p->parent;
75         if (p->parent == NULL) {
76                 JIT_G(symbols) = r;
77         } else if (p->parent->child[0] == p) {
78                 p->parent->child[0] = r;
79         } else {
80                 p->parent->child[1] = r;
81         }
82         r->child[0] = p;
83         p->parent = r;
84 }
85
86 static void zend_syms_rotateright(zend_sym_node *p) {
87         zend_sym_node *l = p->child[0];
88         p->child[0] = l->child[1];
89         if (l->child[1]) {
90                 l->child[1]->parent = p;
91         }
92         l->parent = p->parent;
93         if (p->parent == NULL) {
94                 JIT_G(symbols) = l;
95         } else if (p->parent->child[1] == p) {
96                 p->parent->child[1] = l;
97         } else {
98                 p->parent->child[0] = l;
99         }
100         l->child[1] = p;
101         p->parent = l;
102 }
103
104 static void zend_jit_disasm_add_symbol(const char *name,
105                                        uint64_t    addr,
106                                        uint64_t    size)
107 {
108         zend_sym_node *sym;
109         size_t len = strlen(name);
110
111         sym = malloc(sizeof(zend_sym_node) + len + 1);
112         if (!sym) {
113                 return;
114         }
115         sym->addr = addr;
116         sym->end  = (addr + size - 1);
117         memcpy((char*)&sym->name, name, len + 1);
118         sym->parent = sym->child[0] = sym->child[1] = NULL;
119         sym->info = 1;
120         if (JIT_G(symbols)) {
121                 zend_sym_node *node = JIT_G(symbols);
122
123                 /* insert it into rbtree */
124                 do {
125                         if (sym->addr > node->addr) {
126                                 ZEND_ASSERT(sym->addr > (node->end));
127                                 if (node->child[1]) {
128                                         node = node->child[1];
129                                 } else {
130                                         node->child[1] = sym;
131                                         sym->parent = node;
132                                         break;
133                                 }
134                         } else if (sym->addr < node->addr) {
135                                 if (node->child[0]) {
136                                         node = node->child[0];
137                                 } else {
138                                         node->child[0] = sym;
139                                         sym->parent = node;
140                                         break;
141                                 }
142                         } else {
143                                 ZEND_ASSERT(sym->addr == node->addr);
144                                 if (strcmp(name, node->name) == 0 && sym->end < node->end) {
145                                         /* reduce size of the existing symbol */
146                                         node->end = sym->end;
147                                 }
148                                 free(sym);
149                                 return;
150                         }
151                 } while (1);
152
153                 /* fix rbtree after instering */
154                 while (sym && sym != JIT_G(symbols) && sym->parent->info == 1) {
155                         if (sym->parent == sym->parent->parent->child[0]) {
156                                 node = sym->parent->parent->child[1];
157                                 if (node && node->info == 1) {
158                                         sym->parent->info = 0;
159                                         node->info = 0;
160                                         sym->parent->parent->info = 1;
161                                         sym = sym->parent->parent;
162                                 } else {
163                                         if (sym == sym->parent->child[1]) {
164                                                 sym = sym->parent;
165                                                 zend_syms_rotateleft(sym);
166                                         }
167                                         sym->parent->info = 0;
168                                         sym->parent->parent->info = 1;
169                                         zend_syms_rotateright(sym->parent->parent);
170                                 }
171                         } else {
172                                 node = sym->parent->parent->child[0];
173                                 if (node && node->info == 1) {
174                                         sym->parent->info = 0;
175                                         node->info = 0;
176                                         sym->parent->parent->info = 1;
177                                         sym = sym->parent->parent;
178                                 } else {
179                                         if (sym == sym->parent->child[0]) {
180                                                 sym = sym->parent;
181                                                 zend_syms_rotateright(sym);
182                                         }
183                                         sym->parent->info = 0;
184                                         sym->parent->parent->info = 1;
185                                         zend_syms_rotateleft(sym->parent->parent);
186                                 }
187                         }
188                 }
189         } else {
190                 JIT_G(symbols) = sym;
191         }
192         JIT_G(symbols)->info = 0;
193 }
194
195 static void zend_jit_disasm_destroy_symbols(zend_sym_node *n) {
196         if (n) {
197                 if (n->child[0]) {
198                         zend_jit_disasm_destroy_symbols(n->child[0]);
199                 }
200                 if (n->child[1]) {
201                         zend_jit_disasm_destroy_symbols(n->child[1]);
202                 }
203                 free(n);
204         }
205 }
206
207 static const char* zend_jit_disasm_find_symbol(uint64_t  addr,
208                                                int64_t  *offset) {
209         zend_sym_node *node = JIT_G(symbols);
210         while (node) {
211                 if (addr < node->addr) {
212                         node = node->child[0];
213                 } else if (addr > node->end) {
214                         node = node->child[1];
215                 } else {
216                         *offset = addr - node->addr;
217                         return node->name;
218                 }
219         }
220         return NULL;
221 }
222
223 #ifdef HAVE_CAPSTONE
224 static uint64_t zend_jit_disasm_branch_target(csh cs, const cs_insn *insn)
225 {
226         unsigned int i;
227
228         if (cs_insn_group(cs, insn, X86_GRP_JUMP)) {
229                 for (i = 0; i < insn->detail->x86.op_count; i++) {
230                         if (insn->detail->x86.operands[i].type == X86_OP_IMM) {
231                                 return insn->detail->x86.operands[i].imm;
232                         }
233                 }
234         }
235
236         return 0;
237 }
238 #endif
239
240 static const char* zend_jit_disasm_resolver(
241 #ifndef HAVE_CAPSTONE
242                                             struct ud *ud,
243 #endif
244                                             uint64_t   addr,
245                                             int64_t   *offset)
246 {
247 #ifndef _WIN32
248 # ifndef HAVE_CAPSTONE
249         ((void)ud);
250 # endif
251         const char *name;
252         void *a = (void*)(zend_uintptr_t)(addr);
253         Dl_info info;
254
255         name = zend_jit_disasm_find_symbol(addr, offset);
256         if (name) {
257                 return name;
258         }
259
260         if (dladdr(a, &info)
261          && info.dli_sname != NULL
262          && info.dli_saddr == a) {
263                 return info.dli_sname;
264         }
265 #else
266         const char *name;
267         name = zend_jit_disasm_find_symbol(addr, offset);
268         if (name) {
269                 return name;
270         }
271 #endif
272
273         return NULL;
274 }
275
276 static int zend_jit_cmp_labels(Bucket *b1, Bucket *b2)
277 {
278         return ((b1->h > b2->h) > 0) ? 1 : -1;
279 }
280
281 static int zend_jit_disasm(const char    *name,
282                            const char    *filename,
283                            const zend_op_array *op_array,
284                            zend_cfg      *cfg,
285                            const void    *start,
286                            size_t         size)
287 {
288         const void *end = (void *)((char *)start + size);
289         zval zv, *z;
290         zend_long n, m;
291         HashTable labels;
292         uint64_t addr;
293         int b;
294 #ifdef HAVE_CAPSTONE
295         csh cs;
296         cs_insn *insn;
297 # ifdef HAVE_CAPSTONE_ITER
298         const uint8_t *cs_code;
299         size_t cs_size;
300         uint64_t cs_addr;
301 # else
302         size_t count, i;
303 # endif
304         const char *sym;
305         int64_t offset = 0;
306         char *p, *q, *r;
307 #else
308         struct ud ud;
309         const struct ud_operand *op;
310 #endif
311
312 #ifdef HAVE_CAPSTONE
313 # if defined(__x86_64__) || defined(_WIN64)
314         if (cs_open(CS_ARCH_X86, CS_MODE_64, &cs) != CS_ERR_OK)
315                 return 0;
316         cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON);
317 #  if DISASM_INTEL_SYNTAX
318         cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
319 #  else
320         cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
321 #  endif
322 # else
323         if (cs_open(CS_ARCH_X86, CS_MODE_32, &cs) != CS_ERR_OK)
324                 return 0;
325         cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON);
326 #  if DISASM_INTEL_SYNTAX
327         cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
328 #  else
329         cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
330 #  endif
331 # endif
332 #else
333         ud_init(&ud);
334 # if defined(__x86_64__) || defined(_WIN64)
335         ud_set_mode(&ud, 64);
336 # else
337         ud_set_mode(&ud, 32);
338 # endif
339 # if DISASM_INTEL_SYNTAX
340         ud_set_syntax(&ud, UD_SYN_INTEL);
341 # else
342         ud_set_syntax(&ud, UD_SYN_ATT);
343 # endif
344         ud_set_sym_resolver(&ud, zend_jit_disasm_resolver);
345 #endif /* HAVE_CAPSTONE */
346
347         if (name) {
348                 fprintf(stderr, "%s: ; (%s)\n", name, filename ? filename : "unknown");
349         }
350
351 #ifndef HAVE_CAPSTONE
352         ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
353         ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
354 #endif
355
356         zend_hash_init(&labels, 8, NULL, NULL, 0);
357         if (op_array && cfg) {
358                 ZVAL_FALSE(&zv);
359                 for (b = 0; b < cfg->blocks_count; b++) {
360                         if (cfg->blocks[b].flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
361                                 addr = (uint64_t)(uintptr_t)op_array->opcodes[cfg->blocks[b].start].handler;
362                                 if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
363                                         zend_hash_index_add(&labels, addr, &zv);
364                                 }
365                         }
366                 }
367         }
368 #ifdef HAVE_CAPSTONE
369         ZVAL_TRUE(&zv);
370 # ifdef HAVE_CAPSTONE_ITER
371         cs_code = start;
372         cs_size = (uint8_t*)end - (uint8_t*)start;
373         cs_addr = (uint64_t)(uintptr_t)cs_code;
374         insn = cs_malloc(cs);
375         while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) {
376                 if ((addr = zend_jit_disasm_branch_target(cs, insn))) {
377 # else
378         count = cs_disasm(cs, start, (uint8_t*)end - (uint8_t*)start, (uintptr_t)start, 0, &insn);
379         for (i = 0; i < count; i++) {
380                 if ((addr = zend_jit_disasm_branch_target(cs, &(insn[i])))) {
381 # endif
382                         if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
383                                 zend_hash_index_add(&labels, addr, &zv);
384                         }
385                 }
386         }
387 #else
388         ZVAL_TRUE(&zv);
389         while (ud_disassemble(&ud)) {
390                 op = ud_insn_opr(&ud, 0);
391                 if (op && op->type == UD_OP_JIMM) {
392                         addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
393                         if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
394                                 zend_hash_index_add(&labels, addr, &zv);
395                         }
396                 }
397         }
398 #endif
399
400         zend_hash_sort(&labels, zend_jit_cmp_labels, 0);
401
402         /* label numbering */
403         n = 0; m = 0;
404         ZEND_HASH_FOREACH_VAL(&labels, z) {
405                 if (Z_TYPE_P(z) == IS_FALSE) {
406                         m--;
407                         ZVAL_LONG(z, m);
408                 } else {
409                         n++;
410                         ZVAL_LONG(z, n);
411                 }
412         } ZEND_HASH_FOREACH_END();
413
414 #ifdef HAVE_CAPSTONE
415 # ifdef HAVE_CAPSTONE_ITER
416         cs_code = start;
417         cs_size = (uint8_t*)end - (uint8_t*)start;
418         cs_addr = (uint64_t)(uintptr_t)cs_code;
419         while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) {
420                 z = zend_hash_index_find(&labels, insn->address);
421 # else
422         for (i = 0; i < count; i++) {
423                 z = zend_hash_index_find(&labels, insn[i].address);
424 # endif
425                 if (z) {
426                         if (Z_LVAL_P(z) < 0) {
427                                 fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
428                         } else {
429                                 fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
430                         }
431                 }
432
433 # ifdef HAVE_CAPSTONE_ITER
434                 fprintf(stderr, "\t%s ", insn->mnemonic);
435                 p = insn->op_str;
436 # else
437                 fprintf(stderr, "\t%s ", insn[i].mnemonic);
438                 p = insn[i].op_str;
439 # endif
440                 /* Try to replace the target addresses with a symbols */
441                 while ((q = strchr(p, 'x')) != NULL) {
442                         if (p != q && *(q-1) == '0') {
443                                 r = q + 1;
444                                 addr = 0;
445                                 while (1) {
446                                         if (*r >= '0' && *r <= '9') {
447                                                 addr = addr * 16 + (*r - '0');
448                                         } else if (*r >= 'A' && *r <= 'F') {
449                                                 addr = addr * 16 + (*r - 'A' + 10);
450                                         } else if (*r >= 'a' && *r <= 'f') {
451                                                 addr = addr * 16 + (*r - 'a' + 10);
452                                         } else {
453                                                 break;
454                                         }
455                                         r++;
456                                 }
457                                 if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
458                                         if ((z = zend_hash_index_find(&labels, addr))) {
459                                                 if (Z_LVAL_P(z) < 0) {
460                                                         fwrite(p, 1, q - p - 1, stderr);
461                                                         fprintf(stderr, ".ENTRY" ZEND_LONG_FMT, -Z_LVAL_P(z));
462                                                 } else {
463                                                         fwrite(p, 1, q - p - 1, stderr);
464                                                         fprintf(stderr, ".L" ZEND_LONG_FMT, Z_LVAL_P(z));
465                                                 }
466                                         } else {
467                                                 fwrite(p, 1, r - p, stderr);
468                                         }
469                                 } else if ((sym = zend_jit_disasm_resolver(addr, &offset))) {
470                                         fwrite(p, 1, q - p - 1, stderr);
471                                         fputs(sym, stderr);
472                                         if (offset != 0) {
473                                                 if (offset > 0) {
474                                                         fprintf(stderr, "+%" PRIx64, offset);
475                                                 } else {
476                                                         fprintf(stderr, "-%" PRIx64, offset);
477                                                 }
478                                         }
479                                 } else {
480                                         fwrite(p, 1, r - p, stderr);
481                                 }
482                                 p = r;
483                         } else {
484                                 fwrite(p, 1, q - p + 1, stderr);
485                                 p = q + 1;
486                         }
487                 }
488                 fprintf(stderr, "%s\n", p);
489         }
490 # ifdef HAVE_CAPSTONE_ITER
491         cs_free(insn, 1);
492 # else
493         cs_free(insn, count);
494 # endif
495 #else
496         ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
497         ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
498
499         while (ud_disassemble(&ud)) {
500                 addr = ud_insn_off(&ud);
501                 z = zend_hash_index_find(&labels, addr);
502                 if (z) {
503                         if (Z_LVAL_P(z) < 0) {
504                                 fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
505                         } else {
506                                 fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
507                         }
508                 }
509                 op = ud_insn_opr(&ud, 0);
510                 if (op && op->type == UD_OP_JIMM) {
511                         addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
512                         if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
513                                 z = zend_hash_index_find(&labels, addr);
514                                 if (z) {
515                                         const char *str = ud_insn_asm(&ud);
516                                         int len;
517
518                                         len = 0;
519                                         while (str[len] != 0 && str[len] != ' ' && str[len] != '\t') {
520                                                 len++;
521                                         }
522                                         if (str[len] != 0) {
523                                                 while (str[len] == ' ' || str[len] == '\t') {
524                                                         len++;
525                                                 }
526                                                 if (Z_LVAL_P(z) < 0) {
527                                                         fprintf(stderr, "\t%.*s.ENTRY" ZEND_LONG_FMT "\n", len, str, -Z_LVAL_P(z));
528                                                 } else {
529                                                         fprintf(stderr, "\t%.*s.L" ZEND_LONG_FMT "\n", len, str, Z_LVAL_P(z));
530                                                 }
531                                                 continue;
532                                         }
533                                 }
534                         }
535                 }
536                 fprintf(stderr, "\t%s\n", ud_insn_asm(&ud));
537         }
538 #endif
539         fprintf(stderr, "\n");
540
541         zend_hash_destroy(&labels);
542
543 #ifdef HAVE_CAPSTONE
544         cs_close(&cs);
545 #endif
546
547         return 1;
548 }
549
550 static int zend_jit_disasm_init(void)
551 {
552 #ifndef ZTS
553 #define REGISTER_EG(n)  \
554         zend_jit_disasm_add_symbol("EG("#n")", \
555                 (uint64_t)(uintptr_t)&executor_globals.n, sizeof(executor_globals.n))
556         REGISTER_EG(uninitialized_zval);
557         REGISTER_EG(exception);
558         REGISTER_EG(vm_interrupt);
559         REGISTER_EG(exception_op);
560         REGISTER_EG(timed_out);
561         REGISTER_EG(current_execute_data);
562         REGISTER_EG(vm_stack_top);
563         REGISTER_EG(vm_stack_end);
564         REGISTER_EG(symbol_table);
565         REGISTER_EG(jit_trace_num);
566 #undef  REGISTER_EG
567 #endif
568
569         /* Register JIT helper functions */
570 #define REGISTER_HELPER(n)  \
571         zend_jit_disasm_add_symbol(#n, \
572                 (uint64_t)(uintptr_t)n, sizeof(void*));
573         REGISTER_HELPER(memcmp);
574         REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
575         REGISTER_HELPER(zend_jit_find_func_helper);
576         REGISTER_HELPER(zend_jit_find_ns_func_helper);
577         REGISTER_HELPER(zend_jit_find_method_helper);
578         REGISTER_HELPER(zend_jit_find_method_tmp_helper);
579         REGISTER_HELPER(zend_jit_push_static_metod_call_frame);
580         REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp);
581         REGISTER_HELPER(zend_jit_invalid_method_call);
582         REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
583         REGISTER_HELPER(zend_jit_unref_helper);
584         REGISTER_HELPER(zend_jit_extend_stack_helper);
585         REGISTER_HELPER(zend_jit_int_extend_stack_helper);
586         REGISTER_HELPER(zend_jit_leave_nested_func_helper);
587         REGISTER_HELPER(zend_jit_leave_top_func_helper);
588         REGISTER_HELPER(zend_jit_leave_func_helper);
589         REGISTER_HELPER(zend_jit_symtable_find);
590         REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
591         REGISTER_HELPER(zend_jit_hash_lookup_rw);
592         REGISTER_HELPER(zend_jit_symtable_lookup_rw);
593         REGISTER_HELPER(zend_jit_symtable_lookup_w);
594         REGISTER_HELPER(zend_jit_undefined_op_helper);
595         REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
596         REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
597         REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
598         REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
599         REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
600         REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
601         REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
602         REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
603         REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
604         REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
605         REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
606         REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
607 //      REGISTER_HELPER(zend_jit_fetch_dim_obj_unset_helper);
608         REGISTER_HELPER(zend_jit_assign_dim_helper);
609         REGISTER_HELPER(zend_jit_assign_dim_op_helper);
610         REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
611         REGISTER_HELPER(zend_jit_fast_concat_helper);
612         REGISTER_HELPER(zend_jit_isset_dim_helper);
613         REGISTER_HELPER(zend_jit_free_call_frame);
614         REGISTER_HELPER(zend_jit_fetch_global_helper);
615         REGISTER_HELPER(zend_jit_verify_arg_slow);
616         REGISTER_HELPER(zend_jit_verify_return_slow);
617         REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
618         REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
619         REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
620         REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
621         REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
622         REGISTER_HELPER(zend_jit_check_array_promotion);
623         REGISTER_HELPER(zend_jit_create_typed_ref);
624         REGISTER_HELPER(zend_jit_extract_helper);
625         REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
626         REGISTER_HELPER(zend_jit_copy_extra_args_helper);
627         REGISTER_HELPER(zend_jit_deprecated_helper);
628         REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
629         REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
630         REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
631         REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
632         REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
633         REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
634         REGISTER_HELPER(zend_jit_post_inc_typed_ref);
635         REGISTER_HELPER(zend_jit_post_dec_typed_ref);
636         REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
637         REGISTER_HELPER(zend_jit_only_vars_by_reference);
638         REGISTER_HELPER(zend_jit_invalid_array_access);
639         REGISTER_HELPER(zend_jit_invalid_property_read);
640         REGISTER_HELPER(zend_jit_invalid_property_write);
641         REGISTER_HELPER(zend_jit_invalid_property_incdec);
642         REGISTER_HELPER(zend_jit_invalid_property_assign);
643         REGISTER_HELPER(zend_jit_invalid_property_assign_op);
644         REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
645         REGISTER_HELPER(zend_jit_pre_inc);
646         REGISTER_HELPER(zend_jit_pre_dec);
647         REGISTER_HELPER(zend_runtime_jit);
648         REGISTER_HELPER(zend_jit_hot_func);
649         REGISTER_HELPER(zend_jit_check_constant);
650         REGISTER_HELPER(zend_jit_get_constant);
651         REGISTER_HELPER(zend_jit_array_free);
652         REGISTER_HELPER(zend_jit_zval_array_dup);
653         REGISTER_HELPER(zend_jit_add_arrays_helper);
654         REGISTER_HELPER(zend_jit_assign_obj_helper);
655         REGISTER_HELPER(zend_jit_assign_obj_op_helper);
656         REGISTER_HELPER(zend_jit_assign_to_typed_prop);
657         REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
658         REGISTER_HELPER(zend_jit_inc_typed_prop);
659         REGISTER_HELPER(zend_jit_dec_typed_prop);
660         REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
661         REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
662         REGISTER_HELPER(zend_jit_post_inc_typed_prop);
663         REGISTER_HELPER(zend_jit_post_dec_typed_prop);
664         REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
665         REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
666         REGISTER_HELPER(zend_jit_post_inc_obj_helper);
667         REGISTER_HELPER(zend_jit_post_dec_obj_helper);
668 #if (PHP_VERSION_ID <= 80100) && (SIZEOF_SIZE_T == 4)
669         REGISTER_HELPER(zval_jit_update_constant_ex);
670 #endif
671         REGISTER_HELPER(zend_jit_free_trampoline_helper);
672 #undef  REGISTER_HELPER
673
674 #ifndef _WIN32
675         zend_elf_load_symbols();
676 #endif
677
678         if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
679                 zend_op opline;
680
681                 memset(&opline, 0, sizeof(opline));
682
683                 opline.opcode = ZEND_DO_UCALL;
684                 opline.result_type = IS_UNUSED;
685                 zend_vm_set_opcode_handler(&opline);
686                 zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
687
688                 opline.opcode = ZEND_DO_UCALL;
689                 opline.result_type = IS_VAR;
690                 zend_vm_set_opcode_handler(&opline);
691                 zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
692
693                 opline.opcode = ZEND_DO_FCALL_BY_NAME;
694                 opline.result_type = IS_UNUSED;
695                 zend_vm_set_opcode_handler(&opline);
696                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
697
698                 opline.opcode = ZEND_DO_FCALL_BY_NAME;
699                 opline.result_type = IS_VAR;
700                 zend_vm_set_opcode_handler(&opline);
701                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
702
703                 opline.opcode = ZEND_DO_FCALL;
704                 opline.result_type = IS_UNUSED;
705                 zend_vm_set_opcode_handler(&opline);
706                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
707
708                 opline.opcode = ZEND_DO_FCALL;
709                 opline.result_type = IS_VAR;
710                 zend_vm_set_opcode_handler(&opline);
711                 zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
712
713                 opline.opcode = ZEND_RETURN;
714                 opline.op1_type = IS_CONST;
715                 zend_vm_set_opcode_handler(&opline);
716                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
717
718                 opline.opcode = ZEND_RETURN;
719                 opline.op1_type = IS_TMP_VAR;
720                 zend_vm_set_opcode_handler(&opline);
721                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
722
723                 opline.opcode = ZEND_RETURN;
724                 opline.op1_type = IS_VAR;
725                 zend_vm_set_opcode_handler(&opline);
726                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
727
728                 opline.opcode = ZEND_RETURN;
729                 opline.op1_type = IS_CV;
730                 zend_vm_set_opcode_handler(&opline);
731                 zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
732
733                 zend_jit_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
734         }
735
736         return 1;
737 }
738
739 static void zend_jit_disasm_shutdown(void)
740 {
741         if (JIT_G(symbols)) {
742                 zend_jit_disasm_destroy_symbols(JIT_G(symbols));
743                 JIT_G(symbols) = NULL;
744         }
745 }