diff --git a/config.make.in b/config.make.in
index 75bb9cc..09c71fb 100644
--- a/config.make.in
+++ b/config.make.in
@@ -53,6 +53,8 @@ have-protected-data = @libc_cv_protected_data@
 with-fp = @with_fp@
 enable-timezone-tools = @enable_timezone_tools@
 unwind-find-fde = @libc_cv_gcc_unwind_find_fde@
+have-tlsdesc = @libc_cv_tlsdesc@
+config-cflags-tlsdesc = @libc_cv_cc_tlsdesc@
 have-fpie = @libc_cv_fpie@
 stack-protector = @stack_protector@
 have-selinux = @have_selinux@
diff --git a/configure b/configure
index 01f5075..4865e48 100755
--- a/configure
+++ b/configure
@@ -617,6 +617,8 @@ have_libcap
 have_libaudit
 LIBGD
 libc_cv_cc_loop_to_function
+libc_cv_tlsdesc
+libc_cv_cc_tlsdesc
 libc_cv_cc_submachine
 libc_cv_cc_nofma
 stack_protector
@@ -5929,6 +5931,57 @@ $as_echo "$libc_cv_cc_submachine" >&6; }
 fi
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler option to enable TLS descriptors" >&5
+$as_echo_n "checking for compiler option to enable TLS descriptors... " >&6; }
+if ${libc_cv_cc_tlsdesc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  libc_cv_cc_tlsdesc=-no-tlsdesc-support
+for opt in -mtls-dialect=desc -mtls-dialect=gnu2; do
+  if { ac_try='${CC-cc} $opt -xc /dev/null -S -o /dev/null'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  libc_cv_cc_tlsdesc=$opt; break
+fi
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_tlsdesc" >&5
+$as_echo "$libc_cv_cc_tlsdesc" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TLS descriptor support" >&5
+$as_echo_n "checking for TLS descriptor support... " >&6; }
+if ${libc_cv_tlsdesc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  libc_cv_tlsdesc=no
+if test "$libc_cv_cc_tlsdesc" != -no-tlsdesc-support; then
+cat > conftest.c <<EOF
+__thread int bar;
+int foo (void) { return bar; }
+EOF
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+		    -fPIC -shared -o conftest.so conftest.c
+		    "$libc_cv_cc_tlsdesc" -nostdlib -nostartfiles'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    if $READELF -rW conftest.so | grep _TLSDESC > /dev/null; then
+      libc_cv_tlsdesc=yes
+    fi
+  fi
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_tlsdesc" >&5
+$as_echo "$libc_cv_tlsdesc" >&6; }
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC accepts -fno-tree-loop-distribute-patterns with \
 __attribute__ ((__optimize__))" >&5
 $as_echo_n "checking if $CC accepts -fno-tree-loop-distribute-patterns with \
diff --git a/configure.ac b/configure.ac
index 3fdf992..13f6630 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1474,6 +1474,32 @@ if test -n "$submachine"; then
 fi
 AC_SUBST(libc_cv_cc_submachine)
 
+AC_CACHE_CHECK(for compiler option to enable TLS descriptors,
+	       libc_cv_cc_tlsdesc, [dnl
+libc_cv_cc_tlsdesc=-no-tlsdesc-support
+for opt in -mtls-dialect=desc -mtls-dialect=gnu2; do
+  LIBC_TRY_CC_OPTION([$opt], [libc_cv_cc_tlsdesc=$opt; break])
+done])
+AC_SUBST(libc_cv_cc_tlsdesc)
+
+AC_CACHE_CHECK(for TLS descriptor support, libc_cv_tlsdesc, [dnl
+libc_cv_tlsdesc=no
+if test "$libc_cv_cc_tlsdesc" != -no-tlsdesc-support; then
+cat > conftest.c <<EOF
+__thread int bar;
+int foo (void) { return bar; }
+EOF
+  if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS
+		    -fPIC -shared -o conftest.so conftest.c
+		    "$libc_cv_cc_tlsdesc" -nostdlib -nostartfiles]); then
+    if $READELF -rW conftest.so | grep _TLSDESC > /dev/null; then
+      libc_cv_tlsdesc=yes
+    fi
+  fi
+fi
+rm -f conftest*])
+AC_SUBST(libc_cv_tlsdesc)
+
 AC_CACHE_CHECK(if $CC accepts -fno-tree-loop-distribute-patterns with \
 __attribute__ ((__optimize__)), libc_cv_cc_loop_to_function, [dnl
 cat > conftest.c <<EOF
diff --git a/elf/Makefile b/elf/Makefile
index 76985cc..b919531 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -160,6 +160,9 @@ selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
 ifneq ($(selinux-enabled),1)
 tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
 endif
+ifeq ($(have-tlsdesc),yes)
+tests += tst-lazytls1 tst-lazytls2 tst-lazytls3 tst-lazytls4
+endif
 endif
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-leaks1-mem.out \
@@ -279,6 +282,10 @@ modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
 endif
 endif
 
+ifeq ($(have-tlsdesc),yes)
+modules-names += tst-lazytls1mod tst-lazytls2mod tst-lazytls3mod tst-lazytls4mod
+endif
+
 ifeq (yes,$(build-shared))
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out
@@ -1234,3 +1241,15 @@ $(objpfx)tst-audit12: $(libdl)
 tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so
 $(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so
 LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map
+
+$(objpfx)tst-lazytls1: $(shared-thread-library) $(objpfx)tst-lazytls1mod.so
+$(objpfx)tst-lazytls2: $(shared-thread-library) $(objpfx)tst-lazytls2mod.so
+$(objpfx)tst-lazytls3: $(shared-thread-library) $(objpfx)tst-lazytls3mod.so
+$(objpfx)tst-lazytls4: $(shared-thread-library) $(objpfx)tst-lazytls4mod.so
+
+ifeq ($(have-tlsdesc),yes)
+CFLAGS-tst-lazytls1mod.c += $(config-cflags-tlsdesc)
+CFLAGS-tst-lazytls2mod.c += $(config-cflags-tlsdesc)
+CFLAGS-tst-lazytls3mod.c += $(config-cflags-tlsdesc)
+CFLAGS-tst-lazytls4mod.c += $(config-cflags-tlsdesc)
+endif
diff --git a/elf/tst-lazytls.h b/elf/tst-lazytls.h
new file mode 100644
index 0000000..4067240
--- /dev/null
+++ b/elf/tst-lazytls.h
@@ -0,0 +1,11 @@
+#define A(n) \
+B(n##0) B(n##1) B(n##2) B(n##3) B(n##4) B(n##5) B(n##6) B(n##7) B(n##8) B(n##9)
+#define B(n) \
+T(n##0) T(n##1) T(n##2) T(n##3) T(n##4) T(n##5) T(n##6) T(n##7) T(n##8) T(n##9)
+
+/* Invoke T 500 times with different arguments.  */
+A(0)
+A(1)
+A(2)
+A(3)
+A(4)
diff --git a/elf/tst-lazytls1.c b/elf/tst-lazytls1.c
new file mode 100644
index 0000000..5130277
--- /dev/null
+++ b/elf/tst-lazytls1.c
@@ -0,0 +1,38 @@
+#include <pthread.h>
+#include <assert.h>
+
+static pthread_barrier_t b;
+
+void *
+start (void *a)
+{
+	pthread_barrier_wait (&b);
+
+#define T(n) \
+	extern void f##n (void); \
+	f##n ();
+
+#include "tst-lazytls.h"
+
+	return 0;
+}
+
+#define NTHREAD 66
+
+static int
+do_test (void)
+{
+	pthread_t td[NTHREAD];
+	int i;
+
+	assert (pthread_barrier_init (&b, 0, NTHREAD) == 0);
+	for (i = 0; i < NTHREAD; i++)
+		assert (pthread_create (td+i, 0, start, 0) == 0);
+	for (i = 0; i < NTHREAD; i++)
+		assert (pthread_join (td[i], 0) == 0);
+
+	return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-lazytls1mod.c b/elf/tst-lazytls1mod.c
new file mode 100644
index 0000000..b33dcb5
--- /dev/null
+++ b/elf/tst-lazytls1mod.c
@@ -0,0 +1,17 @@
+int want = 8;
+
+#ifndef LINKAGE
+#define LINKAGE static
+#endif
+
+#define T(n) \
+__attribute__ ((section (".a."#n))) \
+LINKAGE __thread int a##n = 7; \
+\
+void \
+f##n (void) \
+{ \
+	if (++a##n != want) __builtin_trap (); \
+}
+
+#include "tst-lazytls.h"
diff --git a/elf/tst-lazytls2.c b/elf/tst-lazytls2.c
new file mode 100644
index 0000000..42afb27
--- /dev/null
+++ b/elf/tst-lazytls2.c
@@ -0,0 +1 @@
+#include "tst-lazytls1.c"
diff --git a/elf/tst-lazytls2mod.c b/elf/tst-lazytls2mod.c
new file mode 100644
index 0000000..8df3289
--- /dev/null
+++ b/elf/tst-lazytls2mod.c
@@ -0,0 +1,10 @@
+/* Add an extern call hoping that it adds a relocation entry to .rel.plt
+   that changes the alignment of the tlsdesc entries.  */
+void
+unused (void)
+{
+	extern int puts (const char*);
+	puts ("");
+}
+
+#include "tst-lazytls1mod.c"
diff --git a/elf/tst-lazytls3.c b/elf/tst-lazytls3.c
new file mode 100644
index 0000000..42afb27
--- /dev/null
+++ b/elf/tst-lazytls3.c
@@ -0,0 +1 @@
+#include "tst-lazytls1.c"
diff --git a/elf/tst-lazytls3mod.c b/elf/tst-lazytls3mod.c
new file mode 100644
index 0000000..7551e42
--- /dev/null
+++ b/elf/tst-lazytls3mod.c
@@ -0,0 +1,2 @@
+#define LINKAGE
+#include "tst-lazytls1mod.c"
diff --git a/elf/tst-lazytls4.c b/elf/tst-lazytls4.c
new file mode 100644
index 0000000..42afb27
--- /dev/null
+++ b/elf/tst-lazytls4.c
@@ -0,0 +1 @@
+#include "tst-lazytls1.c"
diff --git a/elf/tst-lazytls4mod.c b/elf/tst-lazytls4mod.c
new file mode 100644
index 0000000..4d10b29
--- /dev/null
+++ b/elf/tst-lazytls4mod.c
@@ -0,0 +1,2 @@
+#define LINKAGE
+#include "tst-lazytls2mod.c"
