[newlib-cygwin/main] Cygwin: signal: Fix stabilize_sig_stack/setjmp/longjmp on AArch64

Corinna Vinschen via Cygwin-cvs <[email protected]> Wed, 11 Mar 2026 14:53:11 +0000 (GMT)
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=84a608608969523b9ef374cd0f5383bbcd020b39

commit 84a608608969523b9ef374cd0f5383bbcd020b39
Author:     Igor Podgainoi <[email protected]>
AuthorDate: Thu Feb 19 08:44:01 2026 +0000
Commit:     Corinna Vinschen <[email protected]>
CommitDate: Wed Mar 11 15:49:34 2026 +0100

    Cygwin: signal: Fix stabilize_sig_stack/setjmp/longjmp on AArch64
    
    This commit fixes the AArch64 implementation of the following three
    functions: stabilize_sig_stack, setjmp and longjmp.
    
    Changes made:
    
    * Fixed code indentation in all three functions.
    * Corrected some comments and added additional ones.
    * Added missing SEH directives.
    * Changed the locking algorithm in stabilize_sig_stack to Test and
      Test-and-Set (TTAS).
    * Stopped returning a value in x0 in stabilize_sig_stack to avoid
      unnecessary clobbering. This should make it more similar to the
      x86_64 version.
    * Using x10 instead of x0 in setjmp and longjmp where needed as per
      the previous change.
    * Fixed bug in setjmp where the SP value after the prologue was used,
      instead of the original one.
    * Fixed bug in setjmp where the stackptr was saved at the wrong offset
      into jmp_buf (should be 0).
    * Now saving and restoring x0 in setjmp and x0/x1 in longjmp around the
      call to stabilize_sig_stack. This should make it more similar to the
      x86_64 version.
    * Removed the prologue and epilogue in longjmp, as the function never
      returns.
    * Changed logic in longjmp to take the return value directly from the
      second argument. This should make it more similar to the x86_64
      version.
    * Fixed bug in longjmp where the TLS stack pointer restoration used an
      invalid base register.
    * Using zero registers instead of an immediate 0 where possible.
    
    Tests fixed on AArch64:
    winsup.api/mmaptest02.exe
    winsup.api/mmaptest03.exe
    winsup.api/ltp/mmap05.exe
    
    Signed-off-by: Igor Podgainoi <[email protected]>

Diff:
---
 winsup/cygwin/scripts/gendef | 277 ++++++++++++++++++++++---------------------
 1 file changed, 142 insertions(+), 135 deletions(-)

diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef
index fb325ea01f73..7097da2e61c6 100755
--- a/winsup/cygwin/scripts/gendef
+++ b/winsup/cygwin/scripts/gendef
@@ -624,81 +624,83 @@ _sigdelayed_end:
 	.global _sigdelayed_end
 	.seh_proc stabilize_sig_stack
 stabilize_sig_stack:
-    // prologue
-    stp     fp, lr, [sp, #-0x10]!        // save FP and LR registers
-    .seh_save_fplr_x 0x10
-    mov     fp, sp                       // set frame pointer for unwinder
-    .seh_set_fp
-    .seh_endprologue
+	// prologue
+	stp	fp, lr, [sp, #-0x10]!		// save FP and LR registers
+	.seh_save_fplr_x 0x10
+	mov	fp, sp				// set frame pointer for unwinder
+	.seh_set_fp
+	.seh_endprologue
 
-    ldr     x10, [x18, #0x8]             // load TLS block base pointer into x10
+	ldr	x10, [x18, #0x8]		// load TLS block base pointer into x10
 
-    // try to acquire the lock
-    mov     w9, #1                       // value to store (1 == locked)
-    ldr     x11, =_cygtls.stacklock      // load the symbol offset
-    add     x12, x10, x11                // x12 = tls_base + &stacklock
+	// try to acquire the lock
+	mov	w9, #1				// value to store (1 == locked)
+	ldr	x11, =_cygtls.stacklock		// load the symbol offset
+	add	x12, x10, x11			// x12 = tls_base + &stacklock
 1:
-    ldaxr   w13, [x12]                   // load old lock value
-    stlxr   w14, w9, [x12]               // attempt to store 1
-    cbnz    w14, 1b                      // if store failed, retry
-    cbz     w13, 2f                      // if lock was acquired, continue
-    yield                                // yield to allow other threads to run
-    b       1b                           // retry acquiring the lock
+	ldaxr	w13, [x12]			// load old lock value
+	cbnz	w13, 2f				// if already locked, wait
+	stxr	w14, w9, [x12]			// attempt to acquire the lock
+	cbnz	w14, 1b				// if locking failed, retry
+	b	3f				// lock acquired, continue
 
 2:
-    // lock acquired, increment incyg counter
-    ldr     x11, =_cygtls.incyg          // load the symbol offset
-    add     x12, x10, x11                // x12 = tls_base + &incyg
-    ldr     w9, [x12]                    // load current value of incyg
-    add     w9, w9, #1                   // increment incyg counter
-    str     w9, [x12]                    // store back incremented value
-
-    // check current_sig
-    ldr     x11, =_cygtls.current_sig    // load the symbol offset
-    ldr     w9, [x10, x11]               // load current value of current_sig
-    cbz     w9, 3f                       // if no current signal, jump to cleanup
-
-    // release lock before calling signal handler
-    ldr     x11, =_cygtls.stacklock      // load the symbol offset
-    add     x12, x10, x11                // x12 = tls_base + &stacklock
-    ldr     w9, [x12]                    // load current value of stacklock
-    sub     w9, w9, #1                   // decrement stacklock
-    stlr    w9, [x12]                    // store with release semantics
-
-    // prepare arg and call handler
-    ldr     x0, =_cygtls.start_offset    // load the symbol offset
-    add     x0, x10, x0                  // x0 = tls_base + &start_offset
-    bl      _ZN7_cygtls19call_signal_handlerEv
-
-    // call may clobber x10, restore TLS base
-    ldr     x10, [x18, #0x8]             // reload tls_base
-
-    // decrement incyg
-    ldr     x11, =_cygtls.incyg
-    add     x12, x10, x11
-    ldr     w9, [x12]
-    sub     w9, w9, #1
-    str     w9, [x12]
-
-    // loop to handle another signal
-    b       1b
+	yield					// yield to allow other threads to run
+	b	1b				// retry acquiring the lock
 
 3:
-    // no signal to handle, decrement incyg counter
-    ldr     x11, =_cygtls.incyg
-    add     x12, x10, x11
-    ldr     w9, [x12]
-    sub     w9, w9, #1
-    str     w9, [x12]
-
-    mov     x0, x10                      // return TLS address in x0 (return register)
-
-    // epilogue
-    .seh_startepilogue
-    ldp     fp, lr, [sp], #0x10
-    .seh_endepilogue
-    ret
-    .seh_endproc
+	// lock acquired, increment incyg counter
+	ldr	x11, =_cygtls.incyg		// load the symbol offset
+	add	x12, x10, x11			// x12 = tls_base + &incyg
+	ldr	w9, [x12]			// load current value of incyg
+	add	w9, w9, #1			// increment incyg counter
+	str	w9, [x12]			// store back incremented value
+
+	// check current_sig
+	ldr	x11, =_cygtls.current_sig	// load the symbol offset
+	ldr	w9, [x10, x11]			// load current value of current_sig
+	cbz	w9, 4f				// if no current signal, jump to cleanup
+
+	// release lock before calling signal handler
+	ldr	x11, =_cygtls.stacklock		// load the symbol offset
+	add	x12, x10, x11			// x12 = tls_base + &stacklock
+	ldr	w9, [x12]			// load current value of stacklock
+	sub	w9, w9, #1			// decrement stacklock
+	stlr	w9, [x12]			// store with release semantics
+
+	// prepare arg and call handler
+	ldr	x0, =_cygtls.start_offset	// load the symbol offset
+	add	x0, x10, x0			// x0 = tls_base + &start_offset
+	bl	_ZN7_cygtls19call_signal_handlerEv
+
+	// call may clobber x10, restore TLS base
+	ldr	x10, [x18, #0x8]		// reload tls_base, use as return value
+
+	// decrement incyg
+	ldr	x11, =_cygtls.incyg		// load the symbol offset
+	add	x12, x10, x11			// x12 = tls_base + &incyg
+	ldr	w9, [x12]			// load current value of incyg
+	sub	w9, w9, #1			// decrement incyg counter
+	str	w9, [x12]			// store back decremented value
+
+	// loop to handle another signal
+	b	1b
+
+4:
+	// no signal to handle, decrement incyg counter
+	ldr	x11, =_cygtls.incyg		// load the symbol offset
+	add	x12, x10, x11			// x12 = tls_base + &incyg
+	ldr	w9, [x12]			// load current value of incyg
+	sub	w9, w9, #1			// decrement incyg counter
+	str	w9, [x12]			// store back decremented value
+
+	// epilogue
+	.seh_startepilogue
+	ldp	fp, lr, [sp], #0x10		// restore FP and LR registers
+	.seh_save_fplr_x 0x10
+	.seh_endepilogue
+	ret
+	.seh_endproc
 EOF
 	}
     }
@@ -867,19 +869,21 @@ sigsetjmp:
 	.seh_proc setjmp
 setjmp:
 	// prologue
-	stp	fp, lr, [sp, #-0x10]!      	// push frame pointer (x29) and link register (x30)
-	mov	fp, sp                      	// set frame pointer
+	stp	fp, lr, [sp, #-0x10]!		// save FP and LR registers
+	.seh_save_fplr_x 0x10
+	mov	fp, sp				// set frame pointer for unwinder
+	.seh_set_fp
 	.seh_endprologue
 
 	// save callee-saved registers from jump buffer
-	stp	x19, x20, [x0, #0x08]       	// save x19, x20
-	stp	x21, x22, [x0, #0x18]       	// save x21, x22
-	stp	x23, x24, [x0, #0x28]       	// save x23, x24
-	stp	x25, x26, [x0, #0x38]       	// save x25, x26
-	stp	x27, x28, [x0, #0x48]       	// save x27, x28
-	stp	x29, x30, [x0, #0x58]       	// save frame ptr (x29) and return addr (x30)
-
-	mov	x1, sp				// get the current stack pointer
+	stp	x19, x20, [x0, #0x08]		// save x19, x20
+	stp	x21, x22, [x0, #0x18]		// save x21, x22
+	stp	x23, x24, [x0, #0x28]		// save x23, x24
+	stp	x25, x26, [x0, #0x38]		// save x25, x26
+	stp	x27, x28, [x0, #0x48]		// save x27, x28
+	stp	x29, x30, [x0, #0x58]		// save x29 (FP) and x30 (LR)
+
+	add	x1, sp, #0x10			// get the old stack pointer
 	str	x1, [x0, #0x68]			// save SP
 
 	mrs	x1, fpcr			// get fp control register
@@ -888,35 +892,39 @@ setjmp:
 	str	x1, [x0, #0x78]			// save FPSR
 
 	// save fp registers (d8-d15)
-	stp	d8,  d9,  [x0, #0x80]        	// save d8, d9
-	stp	d10, d11, [x0, #0x90]        	// save d10, d11
-	stp	d12, d13, [x0, #0xA0]        	// save d12, d13
-	stp	d14, d15, [x0, #0xB0]        	// save d14, d15
+	stp	d8,  d9,  [x0, #0x80]		// save d8, d9
+	stp	d10, d11, [x0, #0x90]		// save d10, d11
+	stp	d12, d13, [x0, #0xA0]		// save d12, d13
+	stp	d14, d15, [x0, #0xB0]		// save d14, d15
 
-	mov x9, x0 				// save jmp_buf pointer in x9
-	# // save TLS stack pointer
-	# ldr	x1, [sp]
-	# str	x1, [x0, #0xB8]
+	// save TLS stack pointer
+	ldr	x1, [sp, #0x10]			// get the TLS stack pointer
+	str	x1, [x0, #0xB8]			// save TLS stack pointer
 
-	bl	stabilize_sig_stack		// call stabilize_sig_stack (returns TLS in x0)
+	str	x0, [sp, #-0x10]!		// save jmp_buf before call
+	bl	stabilize_sig_stack		// call stabilize_sig_stack (returns TLS in x10)
+	ldr	x0, [sp], #0x10			// restore jmp_buf after call
 
 	// store the stack pointer to jump_buf
-	ldr	x2, =_cygtls.stackptr		// load the symbol address/offset
-	add	x2, x0, x2			// Final address of stackptr
+	ldr	x2, =_cygtls.stackptr		// load the symbol offset
+	add	x2, x10, x2			// x2 = tls_base + &stackptr
 	ldr	x3, [x2]			// load current value of stackptr
-	str x3, [x0, #0xB8]           		// store stackptr into jmp_buf
+	str	x3, [x0]			// store stackptr into jmp_buf
 
 	// decrement the stack lock
-	ldr	x2, =_cygtls.stacklock 		// load the symbol address/offset
-	add	x2, x0, x2			// Final address of stacklock
+	ldr	x2, =_cygtls.stacklock		// load the symbol offset
+	add	x2, x10, x2			// x2 = tls_base + &stacklock
 	ldr	w3, [x2]			// load current stacklock value
 	sub	w3, w3, #1			// decrement
-	str	w3, [x2]			//store back
+	str	w3, [x2]			// store back
 
-	mov	w0, #0				// return 0
+	mov	w0, wzr				// return 0
 
 	// epilogue
+	.seh_startepilogue
 	ldp	fp, lr, [sp], #0x10		// restore saved FP and LR registers
+	.seh_save_fplr_x 0x10
+	.seh_endepilogue
 	ret
 	.seh_endproc
 
@@ -952,66 +960,65 @@ siglongjmp:
 	.seh_proc longjmp
 longjmp:
 	// prologue
-	stp	fp, lr, [sp, #-0x20]!			// save FP and LR registers, allocate additional 16 bytes for function arguments
-	stp	x0, x1, [sp, #0x10]			// save function arguments (jump buffer and return value)
-	mov	fp, sp					// establishing frame chain
 	.seh_endprologue
 1:
-	bl	stabilize_sig_stack			// call stabilize_sig_stack which returns TLS pointer in x0
-	ldr	x2, [sp, #0x10]				// get jump buffer pointer from stack
-	ldr	x10, [x2]				// get old signal stack from jump buffer
+	stp	x0, x1, [sp, #-0x10]!		// save function args (jmp_buf and return value)
+	bl	stabilize_sig_stack		// call stabilize_sig_stack (returns TLS in x10)
+	ldp	x2, x3, [sp], #0x10		// restore jmp_buf and return value to x2 and x3
+	ldr	x9, [x2]			// get old signal stack from jump buffer
 
 	// restore stack pointer in TLS
-	ldr	x11, =_cygtls.stackptr
-	add	x11, x0, x11
-	str	x10, [x11]
+	ldr	x11, =_cygtls.stackptr		// load the symbol offset
+	add	x11, x10, x11			// x11 = tls_base + &stackptr
+	str	x9, [x11]			// store signal stack into stackptr
 
 	// release lock by decrementing counter
-	ldr	x11, =_cygtls.stacklock
-	add	x11, x0, x11
-	ldr	w12, [x11]
-	sub	w12, w12, #1
-	str	w12, [x11]
+	ldr	x11, =_cygtls.stacklock		// load the symbol offset
+	add	x11, x10, x11			// x11 = tls_base + &stacklock
+	ldr	w12, [x11]			// load current stacklock value
+	sub	w12, w12, #1			// decrement
+	str	w12, [x11]			// store back
 
 	// we're not in cygwin anymore, clear "in cygwin" flag
-	ldr	x11, =_cygtls.incyg
-	add	x11, x0, x11
-	mov	w12, #0
-	str	w12, [x11]
+	ldr	x11, =_cygtls.incyg		// load the symbol offset
+	add	x11, x10, x11			// x11 = tls_base + &incyg
+	mov	w12, wzr			// clear the incyg counter
+	str	w12, [x11]			// store back the new value
 
-	// get saved return value before SP is restored
-	ldr	x0, [sp, #0x10]
+	// use second argument as the return value
+	mov	x0, x3				// move saved return value to x0
 
 	// restore callee-saved registers from jump buffer
-	ldp	x19, x20, [x2, #0x08]			// restore x19, x20
-	ldp	x21, x22, [x2, #0x18]			// restore x21, x22
-	ldp	x23, x24, [x2, #0x28]			// restore x23, x24
-	ldp	x25, x26, [x2, #0x38]			// restore x25, x26
-	ldp	x27, x28, [x2, #0x48]			// restore x27, x28
-	ldp	fp, lr, [x2, #0x58]			// restore x29 (frame pointer) and x30 (link register)
-	ldr	x10, [x2, #0x68]			// get saved stack pointer
-	mov	sp, x10					// restore stack pointer
-	ldr	x10, [x2, #0x70]			// load floating-point control register
-	msr	fpcr, x10				// restore FPCR
-	ldr	x10, [x2, #0x78]			// load floating-point status register
-	msr	fpsr, x10				// restore FPSR
+	ldp	x19, x20, [x2, #0x08]		// restore x19, x20
+	ldp	x21, x22, [x2, #0x18]		// restore x21, x22
+	ldp	x23, x24, [x2, #0x28]		// restore x23, x24
+	ldp	x25, x26, [x2, #0x38]		// restore x25, x26
+	ldp	x27, x28, [x2, #0x48]		// restore x27, x28
+	ldp	x29, x30, [x2, #0x58]		// restore x29 (FP) and x30 (LR)
+	ldr	x10, [x2, #0x68]		// get saved stack pointer
+	mov	sp, x10				// restore stack pointer
+	ldr	x10, [x2, #0x70]		// load floating-point control register
+	msr	fpcr, x10			// restore FPCR
+	ldr	x10, [x2, #0x78]		// load floating-point status register
+	msr	fpsr, x10			// restore FPSR
 
 	// restore floating-point registers (d8-d15)
-	ldp	d8, d9, [x2, #0x80]
-	ldp	d10, d11, [x2, #0x90]
-	ldp	d12, d13, [x2, #0xA0]
-	ldp	d14, d15, [x2, #0xB0]
+	ldp	d8, d9, [x2, #0x80]		// restore d8, d9
+	ldp	d10, d11, [x2, #0x90]		// restore d10, d11
+	ldp	d12, d13, [x2, #0xA0]		// restore d12, d13
+	ldp	d14, d15, [x2, #0xB0]		// restore d14, d15
 
 	// restore TLS stack pointer
-	ldr	x1, [x0, #0xB8]
-	str	x1, [sp]
+	ldr	x1, [x2, #0xB8]			// get the saved TLS stack pointer
+	str	x1, [sp]			// restore TLS stack pointer
 
 	// ensure return value is non-zero (C standard requirement)
-	cbnz	x0, 0f
-	mov	x0, #1
+	cbnz	x0, 0f				// if return value non-zero, return
+	mov	x0, #1				// set return value to 1
 0:
 	// epilogue
-	add	sp, sp, #0x10				// FP and LR are already restored, just restore SP as it would be popped
+	.seh_startepilogue
+	.seh_endepilogue
 	ret
 	.seh_endproc
 EOF