1 /* Copyright The GNU Toolchain Authors. */
3 /* libc is required to allocate trampolines. */
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);
32 #if defined(__gnu_linux__)
33 static const uint32_t aarch64_trampoline_insns
[] = {
34 0xd503245f, /* hint 34 */
35 0x580000b1, /* ldr x17, .+20 */
36 0x580000d2, /* ldr x18, .+24 */
37 0xd61f0220, /* br x17 */
38 0xd5033f9f, /* dsb sy */
43 static const uint32_t aarch64_trampoline_insns
[] = {
44 0xd503245f, /* hint 34 */
45 0x580000b1, /* ldr x17, .+20 */
46 0x580000d0, /* ldr x16, .+24 */
47 0xd61f0220, /* br x17 */
48 0xd5033f9f, /* dsb sy */
53 #error "Unsupported AArch64 platform for heap trampolines"
56 struct aarch64_trampoline
{
62 struct tramp_ctrl_data
64 struct tramp_ctrl_data
*prev
;
68 /* This will be pointing to an executable mmap'ed page. */
69 struct aarch64_trampoline
*trampolines
;
73 get_trampolines_per_page (void)
75 return getpagesize() / sizeof(struct aarch64_trampoline
);
78 static _Thread_local
struct tramp_ctrl_data
*tramp_ctrl_curr
= NULL
;
81 allocate_trampoline_page (void)
85 #if defined(__gnu_linux__)
86 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
87 MAP_ANON
| MAP_PRIVATE
, 0, 0);
89 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
90 MAP_ANON
| MAP_PRIVATE
| MAP_JIT
, 0, 0);
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
));
105 p
->trampolines
= allocate_trampoline_page ();
107 if (p
->trampolines
== MAP_FAILED
)
111 p
->free_trampolines
= get_trampolines_per_page();
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
)
127 if (tramp_ctrl_curr
->free_trampolines
== 0)
129 void *tramp_ctrl
= allocate_tramp_ctrl (tramp_ctrl_curr
);
133 tramp_ctrl_curr
= tramp_ctrl
;
136 struct aarch64_trampoline
*trampoline
137 = &tramp_ctrl_curr
->trampolines
[get_trampolines_per_page ()
138 - tramp_ctrl_curr
->free_trampolines
];
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);
146 memcpy (trampoline
->insns
, aarch64_trampoline_insns
,
147 sizeof(aarch64_trampoline_insns
));
148 trampoline
->func_ptr
= func
;
149 trampoline
->chain_ptr
= chain
;
152 /* Re-enable write protection. */
153 pthread_jit_write_protect_np (1);
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
;
166 __gcc_nested_func_ptr_deleted (void)
168 if (tramp_ctrl_curr
== NULL
)
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
)
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 */