Date: Mon, 29 Jan 2007 13:59:42 +0200 From: Kostik Belousov <kostikbel@gmail.com> To: Jung-uk Kim <jkim@freebsd.org> Cc: freebsd-emulation@freebsd.org, freebsd-amd64@freebsd.org Subject: Re: load_fs() and load_gs() Message-ID: <20070129115942.GA56152@deviant.kiev.zoral.com.ua> In-Reply-To: <200701261821.12274.jkim@FreeBSD.org> References: <200701261821.12274.jkim@FreeBSD.org>
next in thread | previous in thread | raw e-mail | index | archive | help
--gBBFr7Ir9EOA20Yy
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Fri, Jan 26, 2007 at 06:21:09PM -0500, Jung-uk Kim wrote:
> I have been chasing TLS problem for Linuxulator/amd64. The whole=20
> thing actually boils down to the following simulation:
>=20
> ----------------
> #include <stdio.h>
> #include <sys/types.h>
> #include <machine/cpufunc.h>
> #include <machine/sysarch.h>
>=20
> static __thread u_int tls =3D 0xdeadbeef;
>=20
> int
> main(void)
> {
> #if defined(__amd64__)
> u_int fs;
> uint64_t fsbase;
>=20
> fs =3D rfs();
> if (sysarch(AMD64_GET_FSBASE, &fsbase))
> return (-1);
> printf("fsbase =3D 0x%lx, %%fs: 0x%08x, tls =3D 0x%x\n",
> fsbase, fs, tls);
>=20
> /*
> * glibc does the following two calls.
> * Note: Actually we don't do anything here
> * but writing them back.
> */
> if (sysarch(AMD64_SET_FSBASE, &fsbase))
> return (-1);
> load_fs(fs);
According to Intel docs,
In 64-bit mode, memory accesses using FS-segment and GS-segment
overrides are not checked for a runtime limit nor subjected to
attribute-checking. Normal segment loads (MOV to Sreg and POP Sreg) into
FS and GS load a standard 32-bit base value in the hidden portion of the
segment descriptor register. The base address bits above the standard 32
bits are cleared to 0 to allow consistency for implementations that use
less than 64 bits.
So, by executing load_fs(fs), you effectively load some low (<=3D 2^32) val=
ue
into fs base (I suspect that it is just 0, since GUDATA_SEL has 0 as segment
base, see gdt_segs in amd64/machdep.c). And then,
mov %fs:0x0,%rax
instruction just dereferences 0 instead of TLS.
I suspect that Linux does not use that code sequence too, since behaviour
on the segment register load in 64-bit mode is defined by CPU.
>=20
> if (sysarch(AMD64_GET_FSBASE, &fsbase))
> return (-1);
> printf("fsbase =3D 0x%lx, %%fs: 0x%08x, tls =3D 0x%x\n",
> fsbase, rfs(), tls);
> #elif defined(__i386__)
> u_int gs;
> uint32_t gsbase;
>=20
> gs =3D rgs();
> if (sysarch(I386_GET_GSBASE, &gsbase))
> return (-1);
> printf("gsbase =3D 0x%lx, %%gs: 0x%08x, tls =3D 0x%x\n",
> gsbase, gs, tls);
>=20
> /*
> * glibc does the following two calls.
> * Note: Actually we don't do anything here
> * but writing them back.
> */
> if (sysarch(I386_SET_GSBASE, &gsbase))
> return (-1);
> load_gs(gs);
Again, this load segment base hidden register from the segment descriptor
in memory, that is 0. Access to tls would dereference NULL pointer.
In 32-bit mode, the problem is that FreeBSD does not support segmentation
(yet ?).
>=20
> if (sysarch(I386_GET_GSBASE, &gsbase))
> return (-1);
> printf("gsbase =3D 0x%lx, %%gs: 0x%08x, tls =3D 0x%x\n",
> gsbase, rgs(), tls);
> #endif
>=20
> return (0);
> }
> ----------------
>=20
> If you run it on amd64 (both amd64 and i386 binaries), it segfaults=20
> at:
>=20
> mov %fs:0x0,%rax (amd64)
>=20
> or
>=20
> mov %gs:0x0,%eax (i386)
>=20
> which is basically reading tls. Why does it segfaults when we just=20
> read and write them back? Can anyone enlighten me?
In normal situation, when segment registers are not reloaded,
the IA32_FS_BASE and IA32_GS_BASE MSRs define the actual base
used when fs: or gs: segment override is supplied (that is set by
sysarch(XXX_SET_XSBASE) syscalls).
In fact, it seems that kernel uses only gs: for per-cpu data, and completely
ignores fs base. Due to this, IA32_FS_BASE is changed only on thread context
switch.
--gBBFr7Ir9EOA20Yy
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (FreeBSD)
iD8DBQFFveGtC3+MBN1Mb4gRApCgAKDXNPUkS5liGv8wCFiNCALKKbvvmACdEEDF
Iei4lesQuXChJalTg+4M2RM=
=2hyj
-----END PGP SIGNATURE-----
--gBBFr7Ir9EOA20Yy--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070129115942.GA56152>
