libgcc: Avoid warnings on __gcc_nested_func_ptr_created [PR113402]
[official-gcc.git] / libgcc / config / i386 / heap-trampoline.c
blob657b344c10c3593c4231ec7b271b70ad2c4daef4
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 /* HEAP_T_ATTR is provided to allow targets to build the exported functions
19 as weak definitions. */
20 #ifndef HEAP_T_ATTR
21 # define HEAP_T_ATTR
22 #endif
24 void *allocate_trampoline_page (void);
25 int get_trampolines_per_page (void);
26 struct tramp_ctrl_data *allocate_tramp_ctrl (struct tramp_ctrl_data *parent);
27 void *allocate_trampoline_page (void);
29 void __gcc_nested_func_ptr_created (void *chain, void *func, void *dst);
30 void __gcc_nested_func_ptr_deleted (void);
32 static const uint8_t trampoline_insns[] = {
33 /* movabs $<chain>,%r11 */
34 0x49, 0xbb,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 /* movabs $<func>,%r10 */
38 0x49, 0xba,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 /* rex.WB jmpq *%r11 */
42 0x41, 0xff, 0xe3
45 union ix86_trampoline {
46 uint8_t insns[sizeof(trampoline_insns)];
48 struct __attribute__((packed)) fields {
49 uint8_t insn_0[2];
50 void *func_ptr;
51 uint8_t insn_1[2];
52 void *chain_ptr;
53 uint8_t insn_2[3];
54 } fields;
57 struct tramp_ctrl_data
59 struct tramp_ctrl_data *prev;
61 int free_trampolines;
63 /* This will be pointing to an executable mmap'ed page. */
64 union ix86_trampoline *trampolines;
67 int
68 get_trampolines_per_page (void)
70 return getpagesize() / sizeof(union ix86_trampoline);
73 static _Thread_local struct tramp_ctrl_data *tramp_ctrl_curr = NULL;
75 void *
76 allocate_trampoline_page (void)
78 void *page;
80 #if defined(__gnu_linux__)
81 page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
82 MAP_ANON | MAP_PRIVATE, 0, 0);
83 #elif __APPLE__
84 # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
85 page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
86 MAP_ANON | MAP_PRIVATE | MAP_JIT, 0, 0);
87 # else
88 page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC,
89 MAP_ANON | MAP_PRIVATE, 0, 0);
90 # endif
91 #else
92 page = MAP_FAILED;
93 #endif
95 return page;
98 struct tramp_ctrl_data *
99 allocate_tramp_ctrl (struct tramp_ctrl_data *parent)
101 struct tramp_ctrl_data *p = malloc (sizeof (struct tramp_ctrl_data));
102 if (p == NULL)
103 return NULL;
105 p->trampolines = allocate_trampoline_page ();
107 if (p->trampolines == MAP_FAILED)
108 return NULL;
110 p->prev = parent;
111 p->free_trampolines = get_trampolines_per_page();
113 return p;
116 HEAP_T_ATTR
117 void
118 __gcc_nested_func_ptr_created (void *chain, void *func, void *dst)
120 if (tramp_ctrl_curr == NULL)
122 tramp_ctrl_curr = allocate_tramp_ctrl (NULL);
123 if (tramp_ctrl_curr == NULL)
124 abort ();
127 if (tramp_ctrl_curr->free_trampolines == 0)
129 void *tramp_ctrl = allocate_tramp_ctrl (tramp_ctrl_curr);
130 if (!tramp_ctrl)
131 abort ();
133 tramp_ctrl_curr = tramp_ctrl;
136 union ix86_trampoline *trampoline
137 = &tramp_ctrl_curr->trampolines[get_trampolines_per_page ()
138 - tramp_ctrl_curr->free_trampolines];
140 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
141 /* Disable write protection for the MAP_JIT regions in this thread (see
142 https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon) */
143 pthread_jit_write_protect_np (0);
144 #endif
146 memcpy (trampoline->insns, trampoline_insns,
147 sizeof(trampoline_insns));
148 trampoline->fields.func_ptr = func;
149 trampoline->fields.chain_ptr = chain;
151 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
152 /* Re-enable write protection. */
153 pthread_jit_write_protect_np (1);
154 #endif
156 tramp_ctrl_curr->free_trampolines -= 1;
158 __builtin___clear_cache ((void *)trampoline->insns,
159 ((void *)trampoline->insns + sizeof(trampoline->insns)));
161 *(void **) dst = &trampoline->insns;
164 HEAP_T_ATTR
165 void
166 __gcc_nested_func_ptr_deleted (void)
168 if (tramp_ctrl_curr == NULL)
169 abort ();
171 tramp_ctrl_curr->free_trampolines += 1;
173 if (tramp_ctrl_curr->free_trampolines == get_trampolines_per_page ())
175 if (tramp_ctrl_curr->prev == NULL)
176 return;
178 munmap (tramp_ctrl_curr->trampolines, getpagesize());
179 struct tramp_ctrl_data *prev = tramp_ctrl_curr->prev;
180 free (tramp_ctrl_curr);
181 tramp_ctrl_curr = prev;
185 #endif /* !inhibit_libc */