Add setjmp support for aarch64-linux-musl

The MUSL libc setjmp/longjmp handling differs from the GNU libc
setjmp/longjmp handling. It may not be possible to properly support
sigsetjmp/siglongjmp on MUSL libc.
This commit is contained in:
Stephen M. Webb
2025-08-29 13:29:11 -04:00
parent 3c4658cb97
commit bf6ee1169a
4 changed files with 24 additions and 11 deletions

View File

@@ -35,7 +35,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#define _JB_STK_SHIFT 0
#else
#define JB_SP 13
#define JB_RP 14
# if defined(__GLIBC__)
# define JB_RP 14
# else /* assume MUSL */
# define JB_RP 11
# endif
#define JB_MASK_SAVED 15
#define JB_MASK 16
#endif

View File

@@ -25,9 +25,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
.global _UI_longjmp_cont
.type _UI_longjmp_cont, @function
_UI_longjmp_cont:
#if defined(__linux__) || defined(__QNX__)
#if defined(__GLIBC__) || defined(__QNX__)
ret
#elif defined(__FreeBSD__)
#elif defined(__FreeBSD__) || defined(__linux__)
.cfi_startproc
/*
* x0 - return address

View File

@@ -90,17 +90,24 @@ siglongjmp (sigjmp_buf env, int val)
/* default to resuming without restoring signal-mask */
cont = &_UI_longjmp_cont;
#if defined(__aarch64__) && defined(__linux__) && !defined(__GLIBC__)
if (unw_set_reg (&c, UNW_REG_EH + 0, wp[22]) < 0
|| unw_set_reg (&c, UNW_REG_EH + 1, val) < 0
|| unw_set_reg (&c, UNW_REG_EH + 19, wp[24]) < 0
|| unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) cont))
abort ();
#else /* !defined(__linux__) || defined(__GLIBC__) */
/* Order of evaluation is important here: if unw_resume()
restores signal mask, we must set it up appropriately, even
if wp[JB_MASK_SAVED] is FALSE. */
#ifdef __FreeBSD__
# ifdef __FreeBSD__
if ((wp[JB_MASK_SAVED] & 0x1) == 0x1)
#else
# else
if (!resume_restores_sigmask (&c, wp) && wp[JB_MASK_SAVED])
#endif
# endif
{
/* sigmask was saved */
#if defined(__linux__) || defined(__sun)
# if defined(__linux__) || defined(__sun)
if (UNW_NUM_EH_REGS < 4 || _NSIG > 16 * sizeof (unw_word_t))
/* signal mask doesn't fit into EH arguments and we can't
put it on the stack without overwriting something
@@ -111,12 +118,12 @@ siglongjmp (sigjmp_buf env, int val)
|| (_NSIG > 8 * sizeof (unw_word_t)
&& unw_set_reg (&c, UNW_REG_EH + 3, wp[JB_MASK + 1]) < 0))
abort ();
#elif defined(__FreeBSD__)
# elif defined(__FreeBSD__)
if (unw_set_reg (&c, UNW_REG_EH + 2, (unw_word_t)&wp[JB_MASK]) < 0)
abort();
#else
#error Port me
#endif
# else
# error Port me
# endif
cont = &_UI_siglongjmp_cont;
}
@@ -124,6 +131,7 @@ siglongjmp (sigjmp_buf env, int val)
|| unw_set_reg (&c, UNW_REG_EH + 1, val) < 0
|| unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) cont))
abort ();
#endif /* defined(__linux__) && !defined(__GLIBC__) */
unw_resume (&c);

View File

@@ -209,6 +209,7 @@ main (int argc, char **argv UNUSED)
}
/* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
memset (sigjbuf, 0, sizeof(*sigjbuf));
sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
if (sigsetjmp (sigjbuf, 0))
{