[newlib-cygwin/main] Cygwin: signal: Fix stabilize_sig_stack/setjmp/longjmp on AArch64
Corinna Vinschen
corinna@sourceware.org
Wed Mar 11 14:53:11 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=84a608608969523b9ef374cd0f5383bbcd020b39
commit 84a608608969523b9ef374cd0f5383bbcd020b39
Author: Igor Podgainoi <Igor.Podgainoi@arm.com>
AuthorDate: Thu Feb 19 08:44:01 2026 +0000
Commit: Corinna Vinschen <corinna@vinschen.de>
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 <igor.podgainoi@arm.com>
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
More information about the Cygwin-cvs
mailing list