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