Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 Jan 2007 22:26:24 +0100
From:      Divacky Roman <xdivac02@stud.fit.vutbr.cz>
To:        Tijl Coosemans <tijl@ulyssis.org>
Cc:        freebsd-emulation@freebsd.org, jkim@freebsd.org
Subject:   Re: linuxolator: tls_test results amd64
Message-ID:  <20070122212624.GA49466@stud.fit.vutbr.cz>
In-Reply-To: <200701221752.21628.tijl@ulyssis.org>
References:  <790a9fff0701211041j1176d00gd6dd75d0989cf4ec@mail.gmail.com> <200701220001.22404.tijl@ulyssis.org> <20070122081810.GA42976@stud.fit.vutbr.cz> <200701221752.21628.tijl@ulyssis.org>

next in thread | previous in thread | raw e-mail | index | archive | help
> > 1) why the first test succeeds?
> 
> Segment registers have a hidden part that contains base address and
> limit (and some more flags I guess). When you load a value into a
> segment register, this hidden part is updated with the info contained
> in the descriptor (entry in GDT/LDT). On amd64 the base address of FS
> and GS (in this hidden part) can also be changed directly using the
> wrmsr instruction.
> 
> The first test requests base address 0x00000000. set_thread_area
> sets GS.base (in hidden part) to 0x00000000 and returns 4 as descriptor
> entry number. This is the user data segment descriptor, which base
> address is also 0x00000000 (I think). So when you next load 4<<3|3 in
> FS, FS.base also ends up being 0x00000000 and the test succeeds.
> 
> The second test requests a different base address. GS.base is set to
> this address, but when you then load 4<<3|3 into FS, FS.base ends up
> with 0x00000000 and so your second read test fails (NULL pointer
> dereference).
 
understood
 
> > 2) why real apps (ie. using %gs) show the very same behaviour (first
> > program works then it doesnt)
> 
> Hmm, can you point me to the source of such a program? I would expect
> programs that use glibc to always fail. Glibc expects set_thread_area
> to setup a GDT entry and return the entry number. Then glibc loads
> that entry number into GS which sets up GS.base. Because of this, I
> would expect GS.base to always end up being 0x00000000 just as FS.base
> above.
> 
> Wine on Linux does the same. It calls set_thread_area and loads the
> returned entry number in FS. (On Windows, FS is used for tls.)
> 
> The reason setting GS.base directly with a wrmsr works on FreeBSD is
> because i386 user land code doesn't write to GS. i386_set_gsbase

what do you mean by "writing to GS" ?

> already sets up GS on i386, so the compatibility code on amd64 can
> use the wrmsr trick and leave GS itself and the descriptor it points
> to untouched. As far as I understand things, this won't work for
> linux32 compatibility on amd64.

lookin at the code it looks like:

i386_set_gsbase = sysarch(I386_SET_GSBASE, &addr);

and sysarch for that looks like:
wrmsr(MSR_KGSBASE, i386base);
pcb->pcb_gsbase = i386base;

where is the setting up of the GS? I dont get it... 

overall you are saying that to support linux32 tls we have to

1) load an unused segment with proper values
2) return the number of the segment from the set_thread_syscall
3) make the automatic loading/unloading of that segment to happen on
every context switch (just like its done for segment 3 on i386)

do I get it right?

anyway thnx for the explanation you finally shed some light to it.

roman



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