diff --git a/configure.ac b/configure.ac
index 123f0d2..33bcd62 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1412,6 +1412,26 @@ elif test "$libc_cv_ssp" = "yes"; then
 fi
 AC_SUBST(stack_protector)
 
+AC_CACHE_CHECK([for -mtls-dialect=gnu2], libc_cv_mtls_dialect_gnu2,
+[dnl
+cat > conftest.c <<EOF
+__thread int i;
+void foo (void)
+{
+  i = 10;
+}
+EOF
+if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -S -fPIC -mtls-dialect=gnu2
+		   conftest.c 1>&AS_MESSAGE_LOG_FD])
+then
+  libc_cv_mtls_dialect_gnu2=yes
+else
+  libc_cv_mtls_dialect_gnu2=no
+fi
+rm -f conftest*])
+AC_SUBST(libc_cv_mtls_dialect_gnu2)
+LIBC_CONFIG_VAR([have-mtls-dialect-gnu2], [$libc_cv_mtls_dialect_gnu2])
+
 AC_CACHE_CHECK(whether cc puts quotes around section names,
 	       libc_cv_have_section_quotes,
 	       [cat > conftest.c <<EOF
diff --git a/elf/Makefile b/elf/Makefile
index 210dde9..593403c 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -224,6 +224,13 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \
 		tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
 		tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12
+ifeq (yes,$(have-mtls-dialect-gnu2))
+tests += tst-gnu2-tls1
+modules-names += tst-gnu2-tls1mod
+$(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
+tst-gnu2-tls1mod.so-no-z-defs = yes
+CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
+endif
 ifeq (yes,$(have-protected-data))
 modules-names += tst-protected1moda tst-protected1modb
 tests += tst-protected1a tst-protected1b
diff --git a/elf/tst-gnu2-tls1.c b/elf/tst-gnu2-tls1.c
new file mode 100644
index 0000000..f55de59
--- /dev/null
+++ b/elf/tst-gnu2-tls1.c
@@ -0,0 +1,52 @@
+/* Test local and global dynamic models for GNU2 TLS.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int * get_gd (void);
+extern void set_gd (int);
+extern int test_gd (int);
+extern int * get_ld (void);
+extern void set_ld (int);
+extern int test_ld (int);
+
+__thread int gd = 1;
+
+static int
+do_test (void)
+{
+  int *p;
+
+  p = get_gd ();
+  set_gd (3);
+  if (*p != 3 || !test_gd (3))
+    abort ();
+
+  p = get_ld ();
+  set_ld (4);
+  if (*p != 4 || !test_ld (4))
+    abort ();
+
+  printf ("PASS\n");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-gnu2-tls1mod.c b/elf/tst-gnu2-tls1mod.c
new file mode 100644
index 0000000..45c4816
--- /dev/null
+++ b/elf/tst-gnu2-tls1mod.c
@@ -0,0 +1,56 @@
+/* DSO used by tst-gnu2-tls1.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+static __thread int ld;
+
+int *
+get_ld (void)
+{
+  return &ld;
+}
+
+void
+set_ld (int i)
+{
+  ld = i;
+}
+
+int
+test_ld (int i)
+{
+  return ld == i;
+}
+extern __thread int gd;
+
+int *
+get_gd (void)
+{
+  return &gd;
+}
+
+void
+set_gd (int i)
+{
+  gd = i;
+}
+
+int
+test_gd (int i)
+{
+  return gd == i;
+}
diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S
index 3cb7c3d..777f30b 100644
--- a/sysdeps/x86_64/dl-tlsdesc.S
+++ b/sysdeps/x86_64/dl-tlsdesc.S
@@ -163,14 +163,15 @@ _dl_tlsdesc_dynamic:
 	/* The PLT entry will have pushed the link_map pointer.  */
 _dl_tlsdesc_resolve_rela:
 	cfi_adjust_cfa_offset (8)
-	/* Save all call-clobbered registers.  */
-	subq	$72, %rsp
-	cfi_adjust_cfa_offset (72)
+	/* Save all call-clobbered registers.  Add 8 bytes for push in
+	   the PLT entry to align the stack.  */
+	subq	$80, %rsp
+	cfi_adjust_cfa_offset (80)
 	movq	%rax, (%rsp)
 	movq	%rdi, 8(%rsp)
 	movq	%rax, %rdi	/* Pass tlsdesc* in %rdi.  */
 	movq	%rsi, 16(%rsp)
-	movq	72(%rsp), %rsi	/* Pass link_map* in %rsi.  */
+	movq	80(%rsp), %rsi	/* Pass link_map* in %rsi.  */
 	movq	%r8, 24(%rsp)
 	movq	%r9, 32(%rsp)
 	movq	%r10, 40(%rsp)
@@ -187,8 +188,8 @@ _dl_tlsdesc_resolve_rela:
 	movq	48(%rsp), %r11
 	movq	56(%rsp), %rdx
 	movq	64(%rsp), %rcx
-	addq	$80, %rsp
-	cfi_adjust_cfa_offset (-80)
+	addq	$88, %rsp
+	cfi_adjust_cfa_offset (-88)
 	jmp	*(%rax)
 	cfi_endproc
 	.size	_dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
