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);
32 static const uint8_t trampoline_insns
[] = {
33 /* movabs $<chain>,%r11 */
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 /* movabs $<func>,%r10 */
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 /* rex.WB jmpq *%r11 */
45 union ix86_trampoline
{
46 uint8_t insns
[sizeof(trampoline_insns
)];
48 struct __attribute__((packed
)) fields
{
57 struct tramp_ctrl_data
59 struct tramp_ctrl_data
*prev
;
63 /* This will be pointing to an executable mmap'ed page. */
64 union ix86_trampoline
*trampolines
;
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
;
76 allocate_trampoline_page (void)
80 #if defined(__gnu_linux__)
81 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
82 MAP_ANON
| MAP_PRIVATE
, 0, 0);
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);
88 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
89 MAP_ANON
| MAP_PRIVATE
, 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 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);
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);
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 */