]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Make i386 signal delivery work with -mregparm
authorH. Peter Anvin <hpa@zytor.com>
Tue, 31 Aug 2004 03:38:44 +0000 (20:38 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Tue, 31 Aug 2004 03:38:44 +0000 (20:38 -0700)
This patch allows i386 signal delivery to work correctly when userspace is
compiled with -mregparm.  This is somewhat hacky: it passes the arguments
*both* on the stack and in registers, but it works because there are only
one or three (depending on SA_SIGINFO) official arguments.  If you're
relying on the unofficial arguments then you're doing something nonportable
anyway and can put in the __attribute__((cdecl,regparm(0))) in the correct
place.

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/kernel/signal.c

index 019c7a620a1faa58d169c98e2e1c7d0350ec97cb..b32a4b0a3e50833e7201aa5bca6ef06b8bac3e12 100644 (file)
@@ -345,18 +345,20 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        void __user *restorer;
        struct sigframe __user *frame;
        int err = 0;
+       int usig;
 
        frame = get_sigframe(ka, regs, sizeof(*frame));
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
                goto give_sigsegv;
 
-       err |= __put_user((current_thread_info()->exec_domain
-                          && current_thread_info()->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current_thread_info()->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
+       usig = current_thread_info()->exec_domain
+               && current_thread_info()->exec_domain->signal_invmap
+               && sig < 32
+               ? current_thread_info()->exec_domain->signal_invmap[sig]
+               : sig;
+
+       err |= __put_user(usig, &frame->sig);
        if (err)
                goto give_sigsegv;
 
@@ -395,6 +397,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        /* Set up registers for signal handler */
        regs->esp = (unsigned long) frame;
        regs->eip = (unsigned long) ka->sa.sa_handler;
+       regs->eax = (unsigned long) sig;
+       regs->edx = (unsigned long) 0;
+       regs->ecx = (unsigned long) 0;
 
        set_fs(USER_DS);
        regs->xds = __USER_DS;
@@ -420,18 +425,20 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        void __user *restorer;
        struct rt_sigframe __user *frame;
        int err = 0;
+       int usig;
 
        frame = get_sigframe(ka, regs, sizeof(*frame));
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
                goto give_sigsegv;
 
-       err |= __put_user((current_thread_info()->exec_domain
-                          && current_thread_info()->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current_thread_info()->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
+       usig = current_thread_info()->exec_domain
+               && current_thread_info()->exec_domain->signal_invmap
+               && sig < 32
+               ? current_thread_info()->exec_domain->signal_invmap[sig]
+               : sig;
+
+       err |= __put_user(usig, &frame->sig);
        err |= __put_user(&frame->info, &frame->pinfo);
        err |= __put_user(&frame->uc, &frame->puc);
        err |= copy_siginfo_to_user(&frame->info, info);
@@ -474,6 +481,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        /* Set up registers for signal handler */
        regs->esp = (unsigned long) frame;
        regs->eip = (unsigned long) ka->sa.sa_handler;
+       regs->eax = (unsigned long) usig;
+       regs->edx = (unsigned long) &frame->info;
+       regs->ecx = (unsigned long) &frame->uc;
 
        set_fs(USER_DS);
        regs->xds = __USER_DS;