Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions winsup/cygwin/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ if TARGET_X86_64
AM_CCASFLAGS=-D_WIN64
endif

if TARGET_AARCH64
AM_CCASFLAGS=-Wa,-march=armv8.1-a
endif

target_builddir=@target_builddir@
newlib_build=$(target_builddir)/newlib

Expand Down
127 changes: 126 additions & 1 deletion winsup/cygwin/scripts/gendef
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,48 @@ _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 16
stp x19, x20, [sp, #-0x10]!
.seh_save_regp_x x19, 16
.seh_endprologue

ldr x9, [x18, #0x8] // load thread local storage base address
mov x19, #_cygtls.current_sig // load the _cygtls.current_sig offset
add x19, x9, x19 // final address of current_sig
mov x20, #_cygtls.incyg // load the _cygtls.incyg offset
add x20, x9, x20 // final address of incyg

1:
// check if there is a current signal to handle
ldr w9, [x19] // load current_sig
cbz w9, 2f // if no current signal, jump to cleanup

mov w9, #1 // specify increment
staddl w9, [x20] // atomically increment incyg with a lock

// prepare arguments and call signal handler
mov x0, #_cygtls.start_offset // load the _cygtls.start_offset offset
add x0, x10, x0 // final address of start_offset
bl _ZN7_cygtls19call_signal_handlerEv

// decrement incyg counter
mov w9, #-1 // specify decrement
staddl w9, [x20] // atomically decrement incyg with a lock

// go to the beginning to handle another signal
b 1b
2:
ldr x0, [x18, #0x8] // return TLS address in x0 (return value)

// epilogue
.seh_startepilogue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.seh commands are not needed here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thanks. I believe that you know far more about this topic. Could you possibly share link to some documentation where I can learn why?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only available documentation is https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=msvc-170#unwind-codes
and binutils/gcc source code.

in short, for a single instruction like this, not having seh_endepilogue or duplicating seh commands is not changing anything. Both options are acceptable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From this answer I'd deduce that the fact that it has no effect is an implementation detail of GCC/binutils so it makes sense to keep it for consistency with the prologue and accross the compilers (Regardled that Cygwin is build only with GCC, one never know who will copy&paste this code elsewhere).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming back to this thread, it is worth mentioning again that .seh_startepilogue is not needed here and unwinding should be fully covered by prolog. Current implementation emits duplicated unwinding codes.

ldp x19, x20, [sp], #0x10
.seh_save_regp_x x19, 16
ldp fp, lr, [sp], #0x10
.seh_save_fplr_x 16
.seh_endepilogue
ret
.seh_endproc
EOF
Expand Down Expand Up @@ -555,8 +596,43 @@ sigsetjmp:
.globl setjmp
.seh_proc setjmp
setjmp:
// prologue
stp fp, lr, [sp, #-0x10]! // save FP and LR registers
.seh_endprologue
mov x0, 0

// save callee-saved registers from jump buffer
stp x19, x20, [x0, #0x08] // save x19 and x20
stp x21, x22, [x0, #0x18] // save x21 and x22
stp x23, x24, [x0, #0x28] // save x23 and x24
stp x25, x26, [x0, #0x38] // save x25 and x26
stp x27, x28, [x0, #0x48] // save x27 and x28
stp fp, lr, [x0, #0x58] // save x29 (frame pointer) and x30 (link register)
mov x1, sp // get the current stack pointer
str x1, [x0, #0x68] // save SP
mrs x1, fpcr // get floating-point control register
str x1, [x0, #0x70] // save FPCR
mrs x1, fpsr // get floating-point status register
str x1, [x0, #0x78] // save FPSR


// save floating-point registers (d8-d15)
stp d8, d9, [x0, #0x80]
stp d10, d11, [x0, #0x90]
stp d12, d13, [x0, #0xA0]
stp d14, d15, [x0, #0xB0]

bl stabilize_sig_stack // call stabilize_sig_stack (returns TLS in x0)

// store the stack pointer to ...
ldr x2, =_cygtls.stackptr
add x2, x0, x2
ldr x3, [x2]
// TODO: Save the value somewhere.

mov w0, #0 // return 0

// epilogue
ldp fp, lr, [sp], #0x10 // restore saved FP and LR registers
ret
.seh_endproc

Expand All @@ -570,7 +646,56 @@ siglongjmp:
.globl longjmp
.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

// restore stack pointer in TLS
ldr x11, =_cygtls.stackptr
add x11, x0, x11
str x10, [x11]

// we're not in cygwin anymore, clear "in cygwin" flag
ldr x11, =_cygtls.incyg
add x11, x0, x11
mov w12, #0
str w12, [x11]

// get saved return value before SP is restored
ldr x0, [sp, #0x10]

// 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

// 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]

// ensure return value is non-zero (C standard requirement)
cbnz x0, 0f
mov x0, #1
0:
// epilogue
add sp, sp, #0x10 // FP and LR are already restored, just restore SP as it would be popped
ret
.seh_endproc
EOF
Expand Down