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 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 static const uint8_t trampoline_insns
[] = {
27 /* movabs $<chain>,%r11 */
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 /* movabs $<func>,%r10 */
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 /* rex.WB jmpq *%r11 */
39 union ix86_trampoline
{
40 uint8_t insns
[sizeof(trampoline_insns
)];
42 struct __attribute__((packed
)) fields
{
51 struct tramp_ctrl_data
53 struct tramp_ctrl_data
*prev
;
57 /* This will be pointing to an executable mmap'ed page. */
58 union ix86_trampoline
*trampolines
;
62 get_trampolines_per_page (void)
64 return getpagesize() / sizeof(union ix86_trampoline
);
67 static _Thread_local
struct tramp_ctrl_data
*tramp_ctrl_curr
= NULL
;
70 allocate_trampoline_page (void)
74 #if defined(__gnu_linux__)
75 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
76 MAP_ANON
| MAP_PRIVATE
, 0, 0);
78 # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
79 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
80 MAP_ANON
| MAP_PRIVATE
| MAP_JIT
, 0, 0);
82 page
= mmap (0, getpagesize (), PROT_WRITE
| PROT_EXEC
,
83 MAP_ANON
| MAP_PRIVATE
, 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 union ix86_trampoline
*trampoline
130 = &tramp_ctrl_curr
->trampolines
[get_trampolines_per_page ()
131 - tramp_ctrl_curr
->free_trampolines
];
133 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
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
, trampoline_insns
,
140 sizeof(trampoline_insns
));
141 trampoline
->fields
.func_ptr
= func
;
142 trampoline
->fields
.chain_ptr
= chain
;
144 #if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
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 */