Messages in this thread Patch in this message | | | Date | Tue, 25 Aug 1998 17:38:55 -0700 | From | Richard Henderson <> | Subject | patch for x86 treatment of fs and gs in signal handlers |
| |
Currently the code that sets up the context in which a signal handler runs resets both %fs and %gs to __USER_DS. I argue that this is less than desirable, if not incorrect.
Consider another system, like Sparc or Alpha. In either of these cases we could choose for a particular application to reserve a global register for some purpose. (Of course on Sparc this is directly supported by the ABI, whereas for AXP one must recompile libc. This is beside the point.) In this case, we can expect a suitably chosen register to contain the same value in the signal handler as it did in the context that was interrupted.
In contrast, for x86 we have these two, currently unused, segment regs being clobbered for no particular reason I can divine.
This comes up because it interferes with a potential use of %gs we have in mind for linuxthreads. That is, %gs is set up at the birth of the thread to point to the thread-local data structures, and is thereafter left alone. Currently the code to derive this base address from the stack pointer is quite complex, since we can use nothing so simple as is used in the kernel. This would simplify that code and free up one register in all of the thread functions at the expense of an additional cycle at access time decoding the segment prefix. Whether this is a win overall is not yet known for certain, but it seems promising.
In the patch below, I assume worst case in which I must verify the validity of the segments involved. I don't know how an invalid value could come to reside in the segment registers; if it is in fact not possible, then this check could go away, but someone else will have to decide this.
r~ --- arch/i386/kernel/signal.c.old Thu Aug 20 12:09:42 1998 +++ arch/i386/kernel/signal.c Tue Aug 25 16:48:39 1998 @@ -460,12 +460,26 @@ static void setup_frame(int sig, struct regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; { - unsigned long seg = __USER_DS; - __asm__("movl %w0,%%fs ; movl %w0,%%gs": "=r"(seg) : "0"(seg)); + unsigned long seg; + + seg = frame->sc.fs; + if ((seg & 0xfffc) + && (seg & 4) != 4 + && (seg & 3) != 3) + seg = __USER_DS; + loadsegment(fs,seg); + + seg = frame->sc.gs; + if ((seg & 0xfffc) + && (seg & 4) != 4 + && (seg & 3) != 3) + seg = __USER_DS; + loadsegment(gs,seg); + set_fs(USER_DS); - regs->xds = seg; - regs->xes = seg; - regs->xss = seg; + regs->xds = __USER_DS; + regs->xes = __USER_DS; + regs->xss = __USER_DS; regs->xcs = __USER_CS; } regs->eflags &= ~TF_MASK; | |