hurd: Avoid asm statements which return

They are not supposed to change flow control.

This fixes miscompilation with gcc 14.2.0 which then drops code, see
https://lists.gnu.org/archive/html/bug-hurd/2024-11/msg00145.html
This commit is contained in:
Samuel Thibault 2024-12-26 23:11:28 +01:00
parent 757ac24f8f
commit 7fa9e786b6
5 changed files with 98 additions and 69 deletions

View File

@ -231,6 +231,8 @@ _dl_sysdep_start (void **start_argptr,
abort (); abort ();
} }
RETURN_TO_TRAMPOLINE();
void void
_dl_sysdep_start_cleanup (void) _dl_sysdep_start_cleanup (void)
{ {

View File

@ -15,8 +15,6 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
register int *sp asm ("%esp");
#include <hurd.h> #include <hurd.h>
#include <hurd/signal.h> #include <hurd/signal.h>
#include <hurd/msg.h> #include <hurd/msg.h>
@ -54,29 +52,36 @@ __sigreturn2 (int *usp, struct sigcontext *scp)
MACH_PORT_RIGHT_RECEIVE, -1); MACH_PORT_RIGHT_RECEIVE, -1);
THREAD_SETMEM (THREAD_SELF, reply_port, scp->sc_reply_port); THREAD_SETMEM (THREAD_SELF, reply_port, scp->sc_reply_port);
sp = usp; void sigreturn2_trampoline (int *usp) __attribute__ ((__noreturn__));
#define A(line) asm volatile (#line) sigreturn2_trampoline (usp);
/* The members in the sigcontext are arranged in this order
so we can pop them easily. */
/* Pop the segment registers (except %cs and %ss, done last). */
A (popl %gs);
A (popl %fs);
A (popl %es);
A (popl %ds);
/* Pop the general registers. */
A (popa);
/* Pop the processor flags. */
A (popf);
/* Return to the saved PC. */
A (ret);
/* Firewall. */
A (hlt);
#undef A
__builtin_unreachable ();
} }
asm("sigreturn2_trampoline:\n"
/* Restore thread stack */
"movl 4(%esp),%esp\n"
/* The members in the sigcontext are arranged in this order
so we can pop them easily. */
/* Pop the segment registers (except %cs and %ss, done last). */
"popl %gs\n"
"popl %fs\n"
"popl %es\n"
"popl %ds\n"
/* Pop the general registers. */
"popa\n"
/* Pop the processor flags. */
"popf\n"
/* Return to the saved PC. */
"ret\n"
/* Firewall. */
"hlt\n");
int int
__sigreturn (struct sigcontext *scp) __sigreturn (struct sigcontext *scp)
{ {
@ -142,16 +147,21 @@ __sigreturn (struct sigcontext *scp)
*--usp = 0; *--usp = 0;
*--usp = (int) __sigreturn2; *--usp = (int) __sigreturn2;
/* Restore thread stack */
sp = usp;
/* Return into __sigreturn2. */
asm volatile ("ret");
/* Firewall. */
asm volatile ("hlt");
}
/* NOTREACHED */ void sigreturn_trampoline (int *usp) __attribute__ ((__noreturn__));
return -1; sigreturn_trampoline (usp);
}
} }
asm("sigreturn_trampoline:\n"
/* Restore thread stack */
"movl 4(%esp),%esp\n"
/* Return into __sigreturn2. */
"ret\n"
/* Firewall. */
"hlt\n");
weak_alias (__sigreturn, sigreturn) weak_alias (__sigreturn, sigreturn)

View File

@ -249,6 +249,8 @@ _hurd_stack_setup (void **argptr)
_hurd_startup (argptr, &doinit); _hurd_startup (argptr, &doinit);
__builtin_unreachable (); __builtin_unreachable ();
} }
RETURN_TO_TRAMPOLINE();
#endif #endif

View File

@ -46,31 +46,32 @@ __sigreturn2 (struct hurd_sigstate *ss, uintptr_t *usp,
MACH_PORT_RIGHT_RECEIVE, -1); MACH_PORT_RIGHT_RECEIVE, -1);
THREAD_SETMEM (THREAD_SELF, reply_port, sc_reply_port); THREAD_SETMEM (THREAD_SELF, reply_port, sc_reply_port);
asm volatile ( void sigreturn2_trampoline (uintptr_t *usp) __attribute__ ((__noreturn__));
sigreturn2_trampoline (usp);
}
asm("sigreturn2_trampoline:\n"
/* Point the stack to the register dump. */ /* Point the stack to the register dump. */
"movq %0, %%rsp\n" "movq %rdi, %rsp\n"
/* Pop off the registers. */ /* Pop off the registers. */
"popq %%r8\n" "popq %r8\n"
"popq %%r9\n" "popq %r9\n"
"popq %%r10\n" "popq %r10\n"
"popq %%r11\n" "popq %r11\n"
"popq %%r12\n" "popq %r12\n"
"popq %%r13\n" "popq %r13\n"
"popq %%r14\n" "popq %r14\n"
"popq %%r15\n" "popq %r15\n"
"popq %%rdi\n" "popq %rdi\n"
"popq %%rsi\n" "popq %rsi\n"
"popq %%rbp\n" "popq %rbp\n"
"popq %%rbx\n" "popq %rbx\n"
"popq %%rdx\n" "popq %rdx\n"
"popq %%rcx\n" "popq %rcx\n"
"popq %%rax\n" "popq %rax\n"
"popfq\n" "popfq\n"
/* Restore %rip and %rsp with a single instruction. */ /* Restore %rip and %rsp with a single instruction. */
"retq $128" : "retq $128" );
: "rm" (usp));
__builtin_unreachable ();
}
int int
__sigreturn (struct sigcontext *scp) __sigreturn (struct sigcontext *scp)
@ -152,16 +153,18 @@ __sigreturn (struct sigcontext *scp)
*--usp = scp->sc_r9; *--usp = scp->sc_r9;
*--usp = scp->sc_r8; *--usp = scp->sc_r8;
/* Switch to the user's stack that we have just prepared, and call void sigreturn_trampoline (struct hurd_sigstate *ss, uintptr_t *usp,
__sigreturn2. Clobber "memory" to make sure GCC flushes the stack mach_port_t sc_reply_port)
setup to actual memory. We align the stack as per the ABI, but pass __attribute__ ((__noreturn__));
the original usp to __sigreturn2 as an argument. */ sigreturn_trampoline (ss, usp, sc_reply_port);
asm volatile ("movq %1, %%rsp\n"
"andq $-16, %%rsp\n"
"call __sigreturn2" :
: "D" (ss), "S" (usp), "d" (sc_reply_port)
: "memory");
__builtin_unreachable ();
} }
asm("sigreturn_trampoline:\n"
/* Switch to the user's stack that we have just prepared, and call
__sigreturn2. We align the stack as per the ABI, but pass
the original usp to __sigreturn2 as an argument. */
"movq %rsi, %rsp\n"
"andq $-16, %rsp\n"
"call __sigreturn2");
weak_alias (__sigreturn, sigreturn) weak_alias (__sigreturn, sigreturn)

View File

@ -33,17 +33,29 @@
#undef ENTRY #undef ENTRY
#undef ALIGN #undef ALIGN
#ifndef __ASSEMBLER__
void return_to_trampoline(intptr_t *sp, void *pc, intptr_t retval)
__attribute__((__noreturn__));
#endif
#define RETURN_TO return_to_trampoline
#ifdef __x86_64__ #ifdef __x86_64__
#define RETURN_TO(sp, pc, retval) \ #define RETURN_TO_TRAMPOLINE() \
asm volatile ("movq %0, %%rsp; jmp %*%1 # %2" \ asm ("return_to_trampoline:\n" \
: : "g" (sp), "r" (pc), "a" (retval)) "movq %rdx, %rax\n" \
"movq %rdi, %rsp\n" \
"jmp *%rsi\n");
/* This should be rearranged, but at the moment this file provides /* This should be rearranged, but at the moment this file provides
the most useful definitions for assembler syntax details. */ the most useful definitions for assembler syntax details. */
#include <sysdeps/unix/x86_64/sysdep.h> #include <sysdeps/unix/x86_64/sysdep.h>
#else #else
#define RETURN_TO(sp, pc, retval) \ #define RETURN_TO_TRAMPOLINE() \
asm volatile ("movl %0, %%esp; jmp %*%1 # %2" \ asm ("return_to_trampoline:\n" \
: : "g" (sp), "r" (pc), "a" (retval)) "movl 12(%esp), %eax\n" \
"movl 8(%esp), %edx\n" \
"movl 4(%esp), %esp\n" \
"jmp *%edx\n");
#include <sysdeps/unix/i386/sysdep.h> #include <sysdeps/unix/i386/sysdep.h>
#endif #endif