patch for x86 treatment of fs and gs in signal handlers

Richard Henderson (rth@cygnus.com)
Tue, 25 Aug 1998 17:38:55 -0700


--NzB8fVQJ5HfG6fxh
Content-Type: text/plain; charset=us-ascii

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~

--NzB8fVQJ5HfG6fxh
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=d-x86-gs

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

--NzB8fVQJ5HfG6fxh--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html