On Sun, May 14, 2023 at 5:11 PM Bruno Haible <br...@clisp.org> wrote: > But another thing appears to be wrong: The role of sc_rsp versus sc_ursp > in glibc/sysdeps/mach/hurd/x86_64/bits/sigcontext.h. > > What glibc/sysdeps/mach/hurd/x86/trampoline.c does for x86_64 is: > > _hurd_setup_sighandler (...) > { > ... > state->basic.rsp = state->basic.ursp; > ... > sigsp = <appropriate new stack pointer for invoking the signal handler>; > ... > /* Push the arguments to call `trampoline' on the stack. */ > sigsp -= sizeof (*stackframe); > ... > state->basic.ursp = (uintptr_t) sigsp; > ... > } > > But glibc/sysdeps/mach/hurd/x86_64/bits/sigcontext.h has these comments: > > struct sigcontext > { > ... > long sc_rsp; /* Not used; sc_ursp is used instead. */ > ... > long sc_ursp; /* This stack pointer is used. */
Notice that it's state->basic.{rsp,ursp} being modified, not the sigcontext structure (ctx / scp) passed to the handler (and to sigreturn). state->basic is the Mach i386_thread_state structure; the signal handling machinery first initializes it using thread_get_state ()) to describe the state that the thread had at the time it was interrupted. It then initializes the sigcontext based on this state (memcpy'ing from state->basic), and then mutates state->basic to point %rip to the trampoline, %rsp to sigsp, etc., and then uses this same state->basic structure in a thread_set_state () call to apply the new state, to set the thread off to run the handler. But these modifications never reach the struct sigcontext, which still represents the state of the thread when it was interrupted. Moreover, in practice both sc_rsp and sc_ursp will have the same value, because of the 'state->basic.rsp = state->basic.ursp;' line (which is the only change to state->basic done before memcpying it onto the sigcontext). Here's what this looks like in practice, on i686-gnu: $ uname -a GNU hurdle 0.9 GNU-Mach 1.8+git20230410-486/Hurd-0.9 i686-AT386 GNU $ ./scp-demo Set sigaltstack to 0x200019c0 Current esp is 0x1037d48 Caught a signal, my esp is 0x2000169c sc->sc_uesp = 0x1037b6c, sc->sc_esp = 0x1037b6c scp-demo.c source: #define _GNU_SOURCE 1 #include <signal.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <error.h> #include <errno.h> #include <stdint.h> #define esp \ ({ \ void *__esp; \ asm ("mov %%esp, %0" : "=rm" (__esp)); \ __esp; \ }) void handler (int signo, long int sigcode, struct sigcontext *sc) { /* We're not allowed to call printf from inside the signal handler, but it's fine for the sake of the demo. */ printf ("Caught a signal, my esp is %p\n", esp); printf ("sc->sc_uesp = %p, sc->sc_esp = %p\n", sc->sc_uesp, sc->sc_esp); } int main () { stack_t stack; struct sigaction sa; stack.ss_size = 4096; stack.ss_sp = malloc (stack.ss_size); stack.ss_flags = 0; if (sigaltstack (&stack, NULL) < 0) error (1, errno, "sigaltstack"); memset (&sa, 0, sizeof (sa)); sa.sa_handler = handler; sa.sa_flags = SA_ONSTACK; /* not SA_SIGINFO */ if (sigaction (SIGUSR1, &sa, NULL) < 0) error (1, errno, "sigaction"); /* The stack grows down. */ printf ("Set sigaltstack to %p\n", stack.ss_sp + stack.ss_size); printf ("Current esp is %p\n", esp); raise (SIGUSR1); } I hope this makes sense, and I'd be happy to answer more questions :) Sergey