1 /* Copyright The GNU Toolchain Authors. */
3 /* libc is required to allocate trampolines. */
13 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
14 /* For pthread_jit_write_protect_np */
18 /* HEAP_T_ATTR is provided to allow targets to build the exported functions
19 as weak definitions. */
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);
35 static const uint8_t trampoline_insns
[] = {
36 #if defined __CET__ && (__CET__ & 1) != 0
38 0xf3, 0x0f, 0x1e, 0xfa,
41 /* movabsq $<func>,%r11 */
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 /* movabsq $<chain>,%r10 */
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 /* rex.WB jmpq *%r11 */
52 /* Pad to the multiple of 4 bytes. */
56 static const uint8_t trampoline_insns
[] = {
57 #if defined __CET__ && (__CET__ & 1) != 0
59 0xf3, 0x0f, 0x1e, 0xfa,
62 /* movl $<func>,%r11d */
64 0x00, 0x00, 0x00, 0x00,
66 /* movl $<chain>,%r10d */
68 0x00, 0x00, 0x00, 0x00,
70 /* rex.WB jmpq *%r11 */
73 /* Pad to the multiple of 4 bytes. */
78 union ix86_trampoline
{
79 uint8_t insns
[sizeof(trampoline_insns
)];
81 struct __attribute__((packed
)) fields
{
82 #if defined __CET__ && (__CET__ & 1) != 0
96 static const uint8_t trampoline_insns
[] = {
97 /* movl $<chain>,%ecx */
99 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00,
106 union ix86_trampoline
{
107 uint8_t insns
[sizeof(trampoline_insns
)];
109 struct __attribute__((packed
)) fields
{
113 uintptr_t func_offset
;
118 #error unsupported architecture/ABI
121 struct tramp_ctrl_data
123 struct tramp_ctrl_data
*prev
;
125 int free_trampolines
;
127 /* This will be pointing to an executable mmap'ed page. */
128 union ix86_trampoline
*trampolines
;
132 get_trampolines_per_page (void)
134 return getpagesize() / sizeof(union ix86_trampoline
);
137 static _Thread_local
struct tramp_ctrl_data
*tramp_ctrl_curr
= NULL
;
140 allocate_trampoline_page (void)
144 #if defined(__gnu_linux__)
145 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
146 MAP_ANON
| MAP_PRIVATE
, 0, 0);
148 # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
149 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
150 MAP_ANON
| MAP_PRIVATE
| MAP_JIT
, 0, 0);
152 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
153 MAP_ANON
| MAP_PRIVATE
, 0, 0);
162 struct tramp_ctrl_data
*
163 allocate_tramp_ctrl (struct tramp_ctrl_data
*parent
)
165 struct tramp_ctrl_data
*p
= malloc (sizeof (struct tramp_ctrl_data
));
169 p
->trampolines
= allocate_trampoline_page ();
171 if (p
->trampolines
== MAP_FAILED
)
175 p
->free_trampolines
= get_trampolines_per_page();
182 __gcc_nested_func_ptr_created (void *chain
, void *func
, void *dst
)
184 if (tramp_ctrl_curr
== NULL
)
186 tramp_ctrl_curr
= allocate_tramp_ctrl (NULL
);
187 if (tramp_ctrl_curr
== NULL
)
191 if (tramp_ctrl_curr
->free_trampolines
== 0)
193 void *tramp_ctrl
= allocate_tramp_ctrl (tramp_ctrl_curr
);
197 tramp_ctrl_curr
= tramp_ctrl
;
200 union ix86_trampoline
*trampoline
201 = &tramp_ctrl_curr
->trampolines
[get_trampolines_per_page ()
202 - tramp_ctrl_curr
->free_trampolines
];
204 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
205 /* Disable write protection for the MAP_JIT regions in this thread (see
206 https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon) */
207 pthread_jit_write_protect_np (0);
210 memcpy (trampoline
->insns
, trampoline_insns
,
211 sizeof(trampoline_insns
));
212 trampoline
->fields
.chain_ptr
= chain
;
214 trampoline
->fields
.func_ptr
= func
;
216 uintptr_t off_add
= (uintptr_t) &trampoline
->fields
.func_offset
;
218 trampoline
->fields
.func_offset
= (uintptr_t)func
- off_add
;
221 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
222 /* Re-enable write protection. */
223 pthread_jit_write_protect_np (1);
226 tramp_ctrl_curr
->free_trampolines
-= 1;
228 __builtin___clear_cache ((void *)trampoline
->insns
,
229 ((void *)trampoline
->insns
+ sizeof(trampoline
->insns
)));
231 *(void **) dst
= &trampoline
->insns
;
236 __gcc_nested_func_ptr_deleted (void)
238 if (tramp_ctrl_curr
== NULL
)
241 tramp_ctrl_curr
->free_trampolines
+= 1;
243 if (tramp_ctrl_curr
->free_trampolines
== get_trampolines_per_page ())
245 if (tramp_ctrl_curr
->prev
== NULL
)
248 munmap (tramp_ctrl_curr
->trampolines
, getpagesize());
249 struct tramp_ctrl_data
*prev
= tramp_ctrl_curr
->prev
;
250 free (tramp_ctrl_curr
);
251 tramp_ctrl_curr
= prev
;
255 #endif /* !inhibit_libc */