1 /* Copyright The GNU Toolchain Authors. */
3 /* libc is required to allocate trampolines. */
14 /* For pthread_jit_write_protect_np */
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 #if defined(__gnu_linux__)
27 static const uint32_t aarch64_trampoline_insns
[] = {
28 0xd503245f, /* hint 34 */
29 0x580000b1, /* ldr x17, .+20 */
30 0x580000d2, /* ldr x18, .+24 */
31 0xd61f0220, /* br x17 */
32 0xd5033f9f, /* dsb sy */
37 static const uint32_t aarch64_trampoline_insns
[] = {
38 0xd503245f, /* hint 34 */
39 0x580000b1, /* ldr x17, .+20 */
40 0x580000d0, /* ldr x16, .+24 */
41 0xd61f0220, /* br x17 */
42 0xd5033f9f, /* dsb sy */
47 #error "Unsupported AArch64 platform for heap trampolines"
50 struct aarch64_trampoline
{
56 struct tramp_ctrl_data
58 struct tramp_ctrl_data
*prev
;
62 /* This will be pointing to an executable mmap'ed page. */
63 struct aarch64_trampoline
*trampolines
;
67 get_trampolines_per_page (void)
69 return getpagesize() / sizeof(struct aarch64_trampoline
);
72 static _Thread_local
struct tramp_ctrl_data
*tramp_ctrl_curr
= NULL
;
75 allocate_trampoline_page (void)
79 #if defined(__gnu_linux__)
80 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
81 MAP_ANON
| MAP_PRIVATE
, 0, 0);
83 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
84 MAP_ANON
| MAP_PRIVATE
| MAP_JIT
, 0, 0);
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
));
99 p
->trampolines
= allocate_trampoline_page ();
101 if (p
->trampolines
== MAP_FAILED
)
105 p
->free_trampolines
= get_trampolines_per_page();
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
)
120 if (tramp_ctrl_curr
->free_trampolines
== 0)
122 void *tramp_ctrl
= allocate_tramp_ctrl (tramp_ctrl_curr
);
126 tramp_ctrl_curr
= tramp_ctrl
;
129 struct aarch64_trampoline
*trampoline
130 = &tramp_ctrl_curr
->trampolines
[get_trampolines_per_page ()
131 - tramp_ctrl_curr
->free_trampolines
];
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);
139 memcpy (trampoline
->insns
, aarch64_trampoline_insns
,
140 sizeof(aarch64_trampoline_insns
));
141 trampoline
->func_ptr
= func
;
142 trampoline
->chain_ptr
= chain
;
145 /* Re-enable write protection. */
146 pthread_jit_write_protect_np (1);
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
;
158 __builtin_nested_func_ptr_deleted (void)
160 if (tramp_ctrl_curr
== NULL
)
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
)
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 */