Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Oct 2007 18:41:34 -0400
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        freebsd-emulation@FreeBSD.org
Cc:        freebsd-questions@FreeBSD.org
Subject:   Re: amd64_set_gsbase()
Message-ID:  <200710081841.35968.jkim@FreeBSD.org>
In-Reply-To: <200710090100.58577.mihai.dontu@gmail.com>
References:  <200710082135.58099.mihai.dontu@gmail.com> <200710081537.03836.jkim@FreeBSD.org> <200710090100.58577.mihai.dontu@gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Monday 08 October 2007 06:00 pm, Mihai Donțu wrote:
> On Monday 08 October 2007, Jung-uk Kim wrote:
> > Yes, you are correct.  A short version is "don't do that".  A
> > long version goes like this.  %fs and %gs are not preserved while
> > context switching on amd64.
>
> But this makes emulation software such as Wine a lost hope, doesn't
> it? Because Windows apps access the Thread Information Block (TIB)
> via %gs (%fs on ia32).

It was discussed many times on freebsd-emulation@.

> Anyway, my so called "small" program is actually a Win64 emulator
> and I need the segment selector to "stay put" across syscalls. It
> works like a charm on single threaded apps, but as soon as I spawn
> a thread, all hell breaks loose :)

Yup, that's expected. ;-)

> I've managed to come up with something that *kind of* works. It
> goes like this:
>
> void my_handler( int s )
> {
>     if ( s == SIGSEGV ) {
>         if ( get_gs() == 0 ) {
>             amd64_set_gsbase();
>         } else {
>             signal( SIGSEGV, SIG_DFL );
>         }
>     }
> }
>
> int my_init( void )
> {
>     /* alloc TIB memory and initialize */
>
>     amd64_set_gsbase( lpTIB );
>     signal( SIGSEGV, my_handler );
>
>     return 0;
> }
>
> but after a series of dlopen()-s, my_handler() is called without
> %gs being zero and without a valid fault (the handler does not get
> recalled after signal( SIGSEGV, SIG_DFL ). I'm still working on
> this aspect ...

That does not work, i.e., %gs vs. base address mapping is not 
preserved on FreeBSD/amd64 as I said.  You can probably maintain some 
mapping table, though.

> > In fact, you should not use amd64_set_gsbase()
> > directly.  If you *really* have to mess up with base addresses,
> > you have to use sysarch(2) syscall, i.e.,
> > sysarch(AMD64_SET_GSBASE, args).
>
> I found this: /usr/src/lib/libc/amd64/sys/amd64_set_gsbase.c:32
> "
> int
> amd64_set_gsbase(void *addr)
> {
>         return (sysarch(AMD64_SET_GSBASE, &addr));
> }
> "
>
> and this (man 2 sysarch()): "The sysarch() system call should never
> be called directly by user programs.  Instead, they should access
> its functions using the architecture-dependent library."
>
> Who am I suppose to believe? :)

Sorry, my bad. :-(

> > However, it only changes the base address via MSR, i.e., %gs
> > itself has no meaning.
>
> Maybe, but the selector loaded in %gs *does* have meaning.

In long mode, we don't really care about segment registers.  While 
implementing TLS for Linuxulator, I had to do the following hack, for 
example:

http://docs.freebsd.org/cgi/mid.cgi?200703300006.l2U06LA1075891

Under Linux and Windows, they do preserve segment registers vs. base 
addresses mapping for backward compatibility, AFAIK with some 
performance penalty.

Jung-uk Kim

> Anyway, the thing is I _have_ to make this work. I'll keep you
> posted ;)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200710081841.35968.jkim>