Skip gcc.dg/analyzer/pr94688.c on hppa*64*-*-*
[official-gcc.git] / libgcc / config / i386 / heap-trampoline.c
blob4b9f436586890eff866ef8c99812a0694cd75efa
1 /* Copyright The GNU Toolchain Authors. */
3 /* libc is required to allocate trampolines. */
4 #ifndef inhibit_libc
6 #include <unistd.h>
7 #include <sys/mman.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
13 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
14 /* For pthread_jit_write_protect_np */
15 #include <pthread.h>
16 #endif
18 void *allocate_trampoline_page (void);
19 int get_trampolines_per_page (void);
20 struct tramp_ctrl_data *allocate_tramp_ctrl (struct tramp_ctrl_data *parent);
21 void *allocate_trampoline_page (void);
23 void __builtin_nested_func_ptr_created (void *chain, void *func, void **dst);
24 void __builtin_nested_func_ptr_deleted (void);
26 static const uint8_t trampoline_insns[] = {
27 /* movabs $<chain>,%r11 */
28 0x49, 0xbb,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 /* movabs $<func>,%r10 */
32 0x49, 0xba,
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 /* rex.WB jmpq *%r11 */
36 0x41, 0xff, 0xe3
39 union ix86_trampoline {
40 uint8_t insns[sizeof(trampoline_insns)];
42 struct __attribute__((packed)) fields {
43 uint8_t insn_0[2];
44 void *func_ptr;
45 uint8_t insn_1[2];
46 void *chain_ptr;
47 uint8_t insn_2[3];
48 } fields;
51 struct tramp_ctrl_data
53 struct tramp_ctrl_data *prev;
55 int free_trampolines;
57 /* This will be pointing to an executable mmap'ed page. */
58 union ix86_trampoline *trampolines;
61 int
62 get_trampolines_per_page (void)
64 return getpagesize() / sizeof(union ix86_trampoline);
67 static _Thread_local struct tramp_ctrl_data *tramp_ctrl_curr = NULL;
69 void *
70 allocate_trampoline_page (void)
72 void *page;
74 #if defined(__gnu_linux__)
75 page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
76 MAP_ANON | MAP_PRIVATE, 0, 0);
77 #elif __APPLE__
78 # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
79 page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
80 MAP_ANON | MAP_PRIVATE | MAP_JIT, 0, 0);
81 # else
82 page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
83 MAP_ANON | MAP_PRIVATE, 0, 0);
84 # endif
85 #else
86 page = MAP_FAILED;
87 #endif
89 return page;
92 struct tramp_ctrl_data *
93 allocate_tramp_ctrl (struct tramp_ctrl_data *parent)
95 struct tramp_ctrl_data *p = malloc (sizeof (struct tramp_ctrl_data));
96 if (p == NULL)
97 return NULL;
99 p->trampolines = allocate_trampoline_page ();
101 if (p->trampolines == MAP_FAILED)
102 return NULL;
104 p->prev = parent;
105 p->free_trampolines = get_trampolines_per_page();
107 return p;
110 void
111 __builtin_nested_func_ptr_created (void *chain, void *func, void **dst)
113 if (tramp_ctrl_curr == NULL)
115 tramp_ctrl_curr = allocate_tramp_ctrl (NULL);
116 if (tramp_ctrl_curr == NULL)
117 abort ();
120 if (tramp_ctrl_curr->free_trampolines == 0)
122 void *tramp_ctrl = allocate_tramp_ctrl (tramp_ctrl_curr);
123 if (!tramp_ctrl)
124 abort ();
126 tramp_ctrl_curr = tramp_ctrl;
129 union ix86_trampoline *trampoline
130 = &tramp_ctrl_curr->trampolines[get_trampolines_per_page ()
131 - tramp_ctrl_curr->free_trampolines];
133 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
134 /* Disable write protection for the MAP_JIT regions in this thread (see
135 https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon) */
136 pthread_jit_write_protect_np (0);
137 #endif
139 memcpy (trampoline->insns, trampoline_insns,
140 sizeof(trampoline_insns));
141 trampoline->fields.func_ptr = func;
142 trampoline->fields.chain_ptr = chain;
144 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
145 /* Re-enable write protection. */
146 pthread_jit_write_protect_np (1);
147 #endif
149 tramp_ctrl_curr->free_trampolines -= 1;
151 __builtin___clear_cache ((void *)trampoline->insns,
152 ((void *)trampoline->insns + sizeof(trampoline->insns)));
154 *dst = &trampoline->insns;
157 void
158 __builtin_nested_func_ptr_deleted (void)
160 if (tramp_ctrl_curr == NULL)
161 abort ();
163 tramp_ctrl_curr->free_trampolines += 1;
165 if (tramp_ctrl_curr->free_trampolines == get_trampolines_per_page ())
167 if (tramp_ctrl_curr->prev == NULL)
168 return;
170 munmap (tramp_ctrl_curr->trampolines, getpagesize());
171 struct tramp_ctrl_data *prev = tramp_ctrl_curr->prev;
172 free (tramp_ctrl_curr);
173 tramp_ctrl_curr = prev;
177 #endif /* !inhibit_libc */