@@ -68,6 +68,82 @@ static void jl_exit_thread0(int signo, jl_bt_element_t *bt_data, size_t bt_size)
6868
6969int jl_simulate_longjmp (jl_jmp_buf mctx , bt_context_t * c ) JL_NOTSAFEPOINT ;
7070static void jl_longjmp_in_ctx (int sig , void * _ctx , jl_jmp_buf jmpbuf );
71+ extern void jl_fake_signal_return (void );
72+
73+ // create a fake function that describes the variable manipulations in jl_call_in_ctx/jl_call_in_state
74+ #if defined(_OS_LINUX_ ) && defined(_CPU_X86_64_ )
75+ __asm__(
76+ " .type jl_fake_signal_return, @function\n"
77+ "jl_fake_signal_return:\n"
78+ " .cfi_startproc\n"
79+ " .cfi_signal_frame\n"
80+ " .cfi_def_cfa %rsp, 0\n" // CFA here uses %rsp directly
81+ " .cfi_offset %rip, 0\n" // previous value of %rip at CFA
82+ " .cfi_offset %rsp, 8\n" // previous value of %rsp at CFA
83+ " nop\n"
84+ " .cfi_endproc\n"
85+ " .size jl_fake_signal_return, .-jl_fake_signal_return\n"
86+ );
87+ #elif defined(_OS_DARWIN_ ) && defined(_CPU_X86_64_ )
88+ __asm__(
89+ "_jl_fake_signal_return:\n"
90+ " .cfi_startproc\n"
91+ " .cfi_signal_frame\n"
92+ " .cfi_def_cfa %rsp, 0\n" // CFA here uses %rsp directly
93+ " .cfi_offset %rip, 0\n" // previous value of %rip at CFA
94+ " .cfi_offset %rsp, 8\n" // previous value of %rsp at CFA
95+ " nop\n"
96+ " .cfi_endproc\n"
97+ );
98+ #elif defined(_OS_LINUX_ ) && defined(_CPU_X86_ )
99+ __asm__(
100+ " .type jl_fake_signal_return, @function\n"
101+ "jl_fake_signal_return:\n"
102+ " .cfi_startproc\n"
103+ " .cfi_signal_frame\n"
104+ " .cfi_def_cfa %esp, 0\n" // CFA here uses %esp directly
105+ " .cfi_offset %eip, 0\n" // previous value of %eip at CFA
106+ " .cfi_offset %esp, 4\n" // previous value of %esp at CFA
107+ " nop\n"
108+ " .cfi_endproc\n"
109+ " .size jl_fake_signal_return, .-jl_fake_signal_return\n"
110+ );
111+ #elif defined(_OS_LINUX_ ) && defined(_CPU_AARCH64_ )
112+ __asm__(
113+ " .type jl_fake_signal_return, @function\n"
114+ "jl_fake_signal_return:\n"
115+ " .cfi_startproc\n"
116+ " .cfi_signal_frame\n"
117+ " .cfi_def_cfa sp, 0\n" // use sp as fp here
118+ " .cfi_offset lr, 0\n"
119+ " .cfi_offset sp, 8\n"
120+ // Anything else got smashed, since we didn't explicitly copy all of the
121+ // state object to the stack (to build a real sigreturn frame).
122+ // This is also not quite valid, since the AArch64 DWARF spec lacks the ability to define how to restore the LR register correctly,
123+ // so normally libunwind implementations on linux detect this function specially and hack around the invalid info:
124+ // https://github.com/llvm/llvm-project/commit/c82deed6764cbc63966374baf9721331901ca958
125+ " nop\n"
126+ " .cfi_endproc\n"
127+ " .size jl_fake_signal_return, .-jl_fake_signal_return\n"
128+ );
129+ #elif defined(_OS_DARWIN_ ) && defined(_CPU_AARCH64_ )
130+ __asm__(
131+ "_jl_fake_signal_return:\n"
132+ " .cfi_startproc\n"
133+ " .cfi_signal_frame\n"
134+ " .cfi_def_cfa sp, 0\n" // use sp as fp here
135+ " .cfi_offset lr, 0\n"
136+ " .cfi_offset sp, 8\n"
137+ " nop\n"
138+ " .cfi_endproc\n"
139+ );
140+ #else
141+ extern void JL_NORETURN jl_fake_signal_return (void )
142+ {
143+ CFI_NORETURN
144+ abort ();
145+ }
146+ #endif
71147
72148#if !defined(_OS_DARWIN_ )
73149static inline uintptr_t jl_get_rsp_from_ctx (const void * _ctx )
@@ -123,12 +199,25 @@ JL_NO_ASAN static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int si
123199 // will not be part of the validation...
124200 uintptr_t rsp = jl_get_rsp_from_ctx (_ctx );
125201 rsp = (rsp - 256 ) & ~(uintptr_t )15 ; // redzone and re-alignment
202+ assert (rsp % 16 == 0 );
126203#if defined(_OS_LINUX_ ) && defined(_CPU_X86_64_ )
127204 ucontext_t * ctx = (ucontext_t * )_ctx ;
205+ // set return address to NULL
206+ rsp -= sizeof (void * );
207+ * (uintptr_t * )rsp = 0 ;
128208 rsp -= sizeof (void * );
129209 * (uintptr_t * )rsp = 0 ;
130- ctx -> uc_mcontext .gregs [REG_RSP ] = rsp ;
131- ctx -> uc_mcontext .gregs [REG_RIP ] = (uintptr_t )fptr ;
210+ // pushq %rsp
211+ rsp -= sizeof (void * );
212+ * (uintptr_t * )rsp = ctx -> uc_mcontext .gregs [REG_RSP ];
213+ // pushq %rip
214+ rsp -= sizeof (void * );
215+ * (uintptr_t * )rsp = ctx -> uc_mcontext .gregs [REG_RIP ];
216+ // pushq .jl_fake_signal_return + 1; aka call from jl_fake_signal_return
217+ rsp -= sizeof (void * );
218+ * (uintptr_t * )rsp = (uintptr_t )& jl_fake_signal_return + 1 ;
219+ ctx -> uc_mcontext .gregs [REG_RSP ] = rsp ; // set stack pointer
220+ ctx -> uc_mcontext .gregs [REG_RIP ] = (uintptr_t )fptr ; // "call" the function
132221#elif defined(_OS_FREEBSD_ ) && defined(_CPU_X86_64_ )
133222 ucontext_t * ctx = (ucontext_t * )_ctx ;
134223 rsp -= sizeof (void * );
@@ -137,10 +226,22 @@ JL_NO_ASAN static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int si
137226 ctx -> uc_mcontext .mc_rip = (uintptr_t )fptr ;
138227#elif defined(_OS_LINUX_ ) && defined(_CPU_X86_ )
139228 ucontext_t * ctx = (ucontext_t * )_ctx ;
229+ // set return address to NULL
230+ rsp -= sizeof (void * );
231+ * (uintptr_t * )rsp = 0 ;
140232 rsp -= sizeof (void * );
141233 * (uintptr_t * )rsp = 0 ;
142- ctx -> uc_mcontext .gregs [REG_ESP ] = rsp ;
143- ctx -> uc_mcontext .gregs [REG_EIP ] = (uintptr_t )fptr ;
234+ // pushl %esp
235+ rsp -= sizeof (void * );
236+ * (uintptr_t * )rsp = ctx -> uc_mcontext .gregs [REG_ESP ];
237+ // pushl %eip
238+ rsp -= sizeof (void * );
239+ * (uintptr_t * )rsp = ctx -> uc_mcontext .gregs [REG_EIP ];
240+ // pushl .jl_fake_signal_return + 1; aka call from jl_fake_signal_return
241+ rsp -= sizeof (void * );
242+ * (uintptr_t * )rsp = (uintptr_t )& jl_fake_signal_return + 1 ;
243+ ctx -> uc_mcontext .gregs [REG_ESP ] = rsp ; // set stack pointer
244+ ctx -> uc_mcontext .gregs [REG_EIP ] = (uintptr_t )fptr ; // "call" the function
144245#elif defined(_OS_FREEBSD_ ) && defined(_CPU_X86_ )
145246 ucontext_t * ctx = (ucontext_t * )_ctx ;
146247 rsp -= sizeof (void * );
@@ -155,13 +256,19 @@ JL_NO_ASAN static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int si
155256 ctx -> sc_rip = fptr ;
156257#elif defined(_OS_LINUX_ ) && defined(_CPU_AARCH64_ )
157258 ucontext_t * ctx = (ucontext_t * )_ctx ;
158- ctx -> uc_mcontext .sp = rsp ;
159- ctx -> uc_mcontext .regs [29 ] = 0 ; // Clear link register (x29)
160- ctx -> uc_mcontext .pc = (uintptr_t )fptr ;
259+ // push {%sp, %pc}
260+ rsp -= sizeof (void * );
261+ * (uintptr_t * )rsp = ctx -> uc_mcontext .sp ;
262+ rsp -= sizeof (void * );
263+ * (uintptr_t * )rsp = (uintptr_t )ctx -> uc_mcontext .pc ;
264+ ctx -> uc_mcontext .sp = rsp ; // sp
265+ ctx -> uc_mcontext .pc = (uint64_t )fptr ; // pc
266+ ctx -> uc_mcontext .regs [30 ] = (uintptr_t )& jl_fake_signal_return + 4 ; // lr (x30)
161267#elif defined(_OS_FREEBSD_ ) && defined(_CPU_AARCH64_ )
162268 ucontext_t * ctx = (ucontext_t * )_ctx ;
163269 ctx -> uc_mcontext .mc_gpregs .gp_sp = rsp ;
164- ctx -> uc_mcontext .mc_gpregs .gp_x [29 ] = 0 ; // Clear link register (x29)
270+ ctx -> uc_mcontext .mc_gpregs .gp_x [29 ] = 0 ; // Clear frame pointer (x29)
271+ ctx -> uc_mcontext .mc_gpregs .gp_lr = 0 ; // Clear link register (x30)
165272 ctx -> uc_mcontext .mc_gpregs .gp_elr = (uintptr_t )fptr ;
166273#elif defined(_OS_LINUX_ ) && defined(_CPU_ARM_ )
167274 ucontext_t * ctx = (ucontext_t * )_ctx ;
@@ -549,9 +656,8 @@ static void jl_try_deliver_sigint(void)
549656// Write only by signal handling thread, read only by main thread
550657// no sync necessary.
551658static int thread0_exit_signo = 0 ;
552- static void JL_NORETURN jl_exit_thread0_cb (void )
659+ static void jl_exit_thread0_cb (void )
553660{
554- CFI_NORETURN
555661 jl_atomic_fetch_add (& jl_gc_disable_counter , -1 );
556662 jl_fprint_critical_error (ios_safe_stderr , thread0_exit_signo , 0 , NULL , jl_current_task );
557663 jl_atexit_hook (128 );
0 commit comments