load_fs() and load_gs()

Jung-uk Kim jkim at FreeBSD.org
Fri Jan 26 23:59:34 UTC 2007


I have been chasing TLS problem for Linuxulator/amd64.  The whole 
thing actually boils down to the following simulation:

----------------
#include <stdio.h>
#include <sys/types.h>
#include <machine/cpufunc.h>
#include <machine/sysarch.h>

static __thread u_int tls = 0xdeadbeef;

int
main(void)
{
#if defined(__amd64__)
	u_int		fs;
	uint64_t	fsbase;

	fs = rfs();
	if (sysarch(AMD64_GET_FSBASE, &fsbase))
		return (-1);
	printf("fsbase = 0x%lx, %%fs: 0x%08x, tls = 0x%x\n",
	    fsbase, fs, tls);

	/*
	 * 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);

	if (sysarch(AMD64_GET_FSBASE, &fsbase))
		return (-1);
	printf("fsbase = 0x%lx, %%fs: 0x%08x, tls = 0x%x\n",
	    fsbase, rfs(), tls);
#elif defined(__i386__)
	u_int		gs;
	uint32_t	gsbase;

	gs = rgs();
	if (sysarch(I386_GET_GSBASE, &gsbase))
		return (-1);
	printf("gsbase = 0x%lx, %%gs: 0x%08x, tls = 0x%x\n",
	    gsbase, gs, tls);

	/*
	 * 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);

	if (sysarch(I386_GET_GSBASE, &gsbase))
		return (-1);
	printf("gsbase = 0x%lx, %%gs: 0x%08x, tls = 0x%x\n",
	    gsbase, rgs(), tls);
#endif

	return (0);
}
----------------

If you run it on amd64 (both amd64 and i386 binaries), it segfaults 
at:

	mov	%fs:0x0,%rax	(amd64)

or

	mov	%gs:0x0,%eax	(i386)

which is basically reading tls.  Why does it segfaults when we just 
read and write them back?  Can anyone enlighten me?

Thanks,

Jung-uk Kim


More information about the freebsd-amd64 mailing list