2008-04-11 Cary Coutant <ccoutant@google.com>
authorCary Coutant <ccoutant@google.com>
Fri, 11 Apr 2008 21:24:30 +0000 (21:24 +0000)
committerCary Coutant <ccoutant@google.com>
Fri, 11 Apr 2008 21:24:30 +0000 (21:24 +0000)
Add support for TLS descriptors for i386 and x86_64.
* i386.cc (Target_i386::Relocate::tls_desc_gd_to_ie): New function.
(Target_i386::Relocate::tls_desc_gd_to_le): New function.
(Target_i386::Got_type): Add GOT_TYPE_TLS_NOFFSET and
GOT_TYPE_TLS_DESC.
(Target_i386::got_mod_index_entry): Remove unnecessary code.
(Target_i386::Scan::local): Implement R_386_TLS_GOTDESC and
R_386_TLS_DESC_CALL relocations.  Fix problem with initial-exec
relocations.
(Target_i386::Scan::global): Fix problem with GD-to-IE relaxation.
Implement R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL relocations;
Fix problem with initial-exec relocations.
(Target_i386::Relocate::relocate_tls): Likewise.
(Target_i386::Relocate::tls_gd_to_ie): Fix problem with GD-to-IE
relaxation.
* output.cc (Output_data_dynamic::Dynamic_entry::write): Add
support for section-plus-offset dynamic table entries.
* output.h (Output_data_dynamic::add_section_plus_offset): New function.
(Output_data_dynamic::Dynamic_entry): Add support for
section-plus-offset dynamic table entries.
(Output_data_dynamic::Classification): Likewise.
(Output_data_dynamic::classification_): Renamed offset_.
* x86_64.cc (Target_x86_64::Relocate::tls_desc_gd_to_ie): New function.
(Target_x86_64::Relocate::tls_desc_gd_to_le): New function.
(Target_x86_64::make_plt_section): New function.
(Target_x86_64::reserve_tlsdesc_entries): New function.
(Output_data_plt_x86_64::Output_data_plt_x86_64): Add new parameter.
(Output_data_plt_x86_64::reserve_tlsdesc_entry): New function.
(Output_data_plt_x86_64::has_tlsdesc_entry): New function.
(Output_data_plt_x86_64::get_tlsdesc_got_offset): New function.
(Output_data_plt_x86_64::get_tlsdesc_plt_offset): New function.
(Output_data_plt_x86_64::tlsdesc_plt_entry): New field.
(Output_data_plt_x86_64::set_final_data_size): Move out of line;
add extra PLT entry for TLS descriptors.
(Output_data_plt_x86_64::got_): New field.
(Output_data_plt_x86_64::tlsdesc_got_offset_): New field.
(Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize new
fields.
(Output_data_plt_x86_64::do_write): Write extra PLT entry for TLS
descriptors.
(Target_x86_64::make_plt_entry): Factor out make_plt_section.
(Target_x86_64::got_mod_index_entry): Remove unnecessary code.
(Target_x86_64::Scan::local): Implement R_386_TLS_GOTDESC and
R_386_TLS_DESC_CALL relocations.
(Target_x86_64::Scan::global): Likewise.
(Target_x86_64::do_finalize_sections): Add dynamic table entries
for TLS descriptors.
(Relocate::relocate_tls): Fix problem with GD-to-IE relaxation.
Implement R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL relocations.
(Target_x86_64::Relocate::tls_gd_to_ie): Fix problem with
GD-to-IE relaxation.
* configure.ac: Export new conditional variables TLS_GNU2_DIALECT
and TLS_DESCRIPTORS.
* Makefile.in: Rebuild.
* configure: Rebuild.
* testsuite/Makefile.am (tls_shared_gd_to_ie_test): New target.
(tls_test_shared2.so): New target.
(tls_shared_gd_to_ie_test_SOURCES): New variable.
(tls_shared_gd_to_ie_test_DEPENDENCIES): New variable.
(tls_shared_gd_to_ie_test_LDFLAGS): New variable.
(tls_shared_gd_to_ie_test_LDADD): New variable.
(tls_shared_gnu2_gd_to_ie_test): New target.
(tls_test_gnu2.o, tls_test_file2_gnu2.o, tls_test_gnu2_shared2.so):
New targets.
(tls_shared_gnu2_gd_to_ie_test_SOURCES): New variable.
(ls_shared_gnu2_gd_to_ie_test_DEPENDENCIES): New variable.
(tls_shared_gnu2_gd_to_ie_test_LDFLAGS): New variable.
(tls_shared_gnu2_gd_to_ie_test_LDADD): New variable.
(tls_shared_gnu2_test): New target.
(tls_test_gnu2_shared.so): New target.
(tls_shared_gnu2_test_SOURCES): New variable.
(tls_shared_gnu2_test_DEPENDENCIES): New variable.
(tls_shared_gnu2_test_LDFLAGS): New variable.
(tls_shared_gnu2_test_LDADD): New variable.
* testsuite/Makefile.in: Rebuild.
* testsuite/Makefile.

gold/ChangeLog
gold/Makefile.in
gold/configure
gold/configure.ac
gold/i386.cc
gold/output.cc
gold/output.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/x86_64.cc

index 9bb3c20304c377d79d6c48ff264fdea9e28497c2..cc05b97fdc484b3d5cd3be1eea8653e6fbc3e3ce 100644 (file)
@@ -1,3 +1,82 @@
+2008-04-11  Cary Coutant  <ccoutant@google.com>
+
+       Add support for TLS descriptors for i386 and x86_64.
+       * i386.cc (Target_i386::Relocate::tls_desc_gd_to_ie): New function.
+       (Target_i386::Relocate::tls_desc_gd_to_le): New function.
+       (Target_i386::Got_type): Add GOT_TYPE_TLS_NOFFSET and
+       GOT_TYPE_TLS_DESC.
+       (Target_i386::got_mod_index_entry): Remove unnecessary code.
+       (Target_i386::Scan::local): Implement R_386_TLS_GOTDESC and
+       R_386_TLS_DESC_CALL relocations.  Fix problem with initial-exec
+       relocations.
+       (Target_i386::Scan::global): Fix problem with GD-to-IE relaxation.
+       Implement R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL relocations;
+       Fix problem with initial-exec relocations.
+       (Target_i386::Relocate::relocate_tls): Likewise.
+       (Target_i386::Relocate::tls_gd_to_ie): Fix problem with GD-to-IE
+       relaxation.
+       * output.cc (Output_data_dynamic::Dynamic_entry::write): Add
+       support for section-plus-offset dynamic table entries.
+       * output.h (Output_data_dynamic::add_section_plus_offset): New function.
+       (Output_data_dynamic::Dynamic_entry): Add support for
+       section-plus-offset dynamic table entries.
+       (Output_data_dynamic::Classification): Likewise.
+       (Output_data_dynamic::classification_): Renamed offset_.
+       * x86_64.cc (Target_x86_64::Relocate::tls_desc_gd_to_ie): New function.
+       (Target_x86_64::Relocate::tls_desc_gd_to_le): New function.
+       (Target_x86_64::make_plt_section): New function.
+       (Target_x86_64::reserve_tlsdesc_entries): New function.
+       (Output_data_plt_x86_64::Output_data_plt_x86_64): Add new parameter.
+       (Output_data_plt_x86_64::reserve_tlsdesc_entry): New function.
+       (Output_data_plt_x86_64::has_tlsdesc_entry): New function.
+       (Output_data_plt_x86_64::get_tlsdesc_got_offset): New function.
+       (Output_data_plt_x86_64::get_tlsdesc_plt_offset): New function.
+       (Output_data_plt_x86_64::tlsdesc_plt_entry): New field.
+       (Output_data_plt_x86_64::set_final_data_size): Move out of line;
+       add extra PLT entry for TLS descriptors.
+       (Output_data_plt_x86_64::got_): New field.
+       (Output_data_plt_x86_64::tlsdesc_got_offset_): New field.
+       (Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize new
+       fields.
+       (Output_data_plt_x86_64::do_write): Write extra PLT entry for TLS
+       descriptors.
+       (Target_x86_64::make_plt_entry): Factor out make_plt_section.
+       (Target_x86_64::got_mod_index_entry): Remove unnecessary code.
+       (Target_x86_64::Scan::local): Implement R_386_TLS_GOTDESC and
+       R_386_TLS_DESC_CALL relocations.
+       (Target_x86_64::Scan::global): Likewise.
+       (Target_x86_64::do_finalize_sections): Add dynamic table entries
+       for TLS descriptors.
+       (Relocate::relocate_tls): Fix problem with GD-to-IE relaxation.
+       Implement R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL relocations.
+       (Target_x86_64::Relocate::tls_gd_to_ie): Fix problem with
+       GD-to-IE relaxation.
+       * configure.ac: Export new conditional variables TLS_GNU2_DIALECT
+       and TLS_DESCRIPTORS.
+       * Makefile.in: Rebuild.
+       * configure: Rebuild.
+       * testsuite/Makefile.am (tls_shared_gd_to_ie_test): New target.
+       (tls_test_shared2.so): New target.
+       (tls_shared_gd_to_ie_test_SOURCES): New variable.
+       (tls_shared_gd_to_ie_test_DEPENDENCIES): New variable.
+       (tls_shared_gd_to_ie_test_LDFLAGS): New variable.
+       (tls_shared_gd_to_ie_test_LDADD): New variable.
+       (tls_shared_gnu2_gd_to_ie_test): New target.
+       (tls_test_gnu2.o, tls_test_file2_gnu2.o, tls_test_gnu2_shared2.so):
+       New targets.
+       (tls_shared_gnu2_gd_to_ie_test_SOURCES): New variable.
+       (ls_shared_gnu2_gd_to_ie_test_DEPENDENCIES): New variable.
+       (tls_shared_gnu2_gd_to_ie_test_LDFLAGS): New variable.
+       (tls_shared_gnu2_gd_to_ie_test_LDADD): New variable.
+       (tls_shared_gnu2_test): New target.
+       (tls_test_gnu2_shared.so): New target.
+       (tls_shared_gnu2_test_SOURCES): New variable.
+       (tls_shared_gnu2_test_DEPENDENCIES): New variable.
+       (tls_shared_gnu2_test_LDFLAGS): New variable.
+       (tls_shared_gnu2_test_LDADD): New variable.
+       * testsuite/Makefile.in: Rebuild.
+       * testsuite/Makefile.
+
 2008-04-11  Ian Lance Taylor  <iant@google.com>
 
        * testsuite/Makefile.am (justsyms_2r.o): Add dependency on
index 03f4c0d6dcec7ccfbebe939728c2c8be5b9ee121..6acd7de8463bf44ca4441c8778bd834d19c19fd4 100644 (file)
@@ -186,7 +186,6 @@ GCC_FALSE = @GCC_FALSE@
 GCC_TRUE = @GCC_TRUE@
 GENCAT = @GENCAT@
 GMSGFMT = @GMSGFMT@
-GREP = @GREP@
 HAVE_ZLIB_FALSE = @HAVE_ZLIB_FALSE@
 HAVE_ZLIB_TRUE = @HAVE_ZLIB_TRUE@
 INCINTL = @INCINTL@
@@ -231,7 +230,11 @@ STRIP = @STRIP@
 TARGETOBJS = @TARGETOBJS@
 THREADS_FALSE = @THREADS_FALSE@
 THREADS_TRUE = @THREADS_TRUE@
+TLS_DESCRIPTORS_FALSE = @TLS_DESCRIPTORS_FALSE@
+TLS_DESCRIPTORS_TRUE = @TLS_DESCRIPTORS_TRUE@
 TLS_FALSE = @TLS_FALSE@
+TLS_GNU2_DIALECT_FALSE = @TLS_GNU2_DIALECT_FALSE@
+TLS_GNU2_DIALECT_TRUE = @TLS_GNU2_DIALECT_TRUE@
 TLS_TRUE = @TLS_TRUE@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
@@ -239,9 +242,10 @@ WARN_CFLAGS = @WARN_CFLAGS@
 WARN_CXXFLAGS = @WARN_CXXFLAGS@
 XGETTEXT = @XGETTEXT@
 YACC = @YACC@
-YFLAGS = @YFLAGS@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
 am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
 am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
 am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
@@ -258,30 +262,23 @@ build_cpu = @build_cpu@
 build_os = @build_os@
 build_vendor = @build_vendor@
 datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
-htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
-localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
-psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 sysconfdir = @sysconfdir@
index e90d04de56ab64c18bdf580bbcba6da3abbcccc5..4201127ad3c94b015fbc02d6cb1b565ce6af458f 100755 (executable)
@@ -309,7 +309,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar THREADS_TRUE THREADS_FALSE TARGETOBJS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE FN_PTRS_IN_SO_WITHOUT_PIC_TRUE FN_PTRS_IN_SO_WITHOUT_PIC_FALSE TLS_TRUE TLS_FALSE STATIC_TLS_TRUE STATIC_TLS_FALSE TLS_GNU2_DIALECT_TRUE TLS_GNU2_DIALECT_FALSE TLS_DESCRIPTORS_TRUE TLS_DESCRIPTORS_FALSE CONSTRUCTOR_PRIORITY_TRUE CONSTRUCTOR_PRIORITY_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CFLAGS LIBOBJS CPP EGREP HAVE_ZLIB_TRUE HAVE_ZLIB_FALSE CXXCPP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -982,7 +982,7 @@ esac
     else
       echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
     fi
-    cd $ac_popdir
+    cd "$ac_popdir"
   done
 fi
 
@@ -2648,8 +2648,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2707,8 +2706,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2824,8 +2822,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2879,8 +2876,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2925,8 +2921,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2970,8 +2965,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3329,8 +3323,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3388,8 +3381,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3460,8 +3452,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3505,8 +3496,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4283,8 +4273,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4326,8 +4315,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4384,8 +4372,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4535,8 +4522,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4595,8 +4581,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4631,6 +4616,111 @@ else
 fi
 
 
+save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -mtls-dialect=gnu2"
+cat >conftest.$ac_ext <<_ACEOF
+int i;
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  have_tls_gnu2=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+have_tls_gnu2=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS="$save_CFLAGS"
+
+
+if test "$have_tls_gnu2" = "yes"; then
+  TLS_GNU2_DIALECT_TRUE=
+  TLS_GNU2_DIALECT_FALSE='#'
+else
+  TLS_GNU2_DIALECT_TRUE='#'
+  TLS_GNU2_DIALECT_FALSE=
+fi
+
+
+echo "$as_me:$LINENO: checking for glibc >= 2.5" >&5
+echo $ECHO_N "checking for glibc >= 2.5... $ECHO_C" >&6
+if test "${gold_cv_lib_glibc25+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+
+#include <features.h>
+#if !defined __GLIBC__
+error
+#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 5)
+error
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  gold_cv_lib_glibc25=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gold_cv_lib_glibc25=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $gold_cv_lib_glibc25" >&5
+echo "${ECHO_T}$gold_cv_lib_glibc25" >&6
+
+
+
+if test "$gold_cv_lib_glibc25" = "yes"; then
+  TLS_DESCRIPTORS_TRUE=
+  TLS_DESCRIPTORS_FALSE='#'
+else
+  TLS_DESCRIPTORS_TRUE='#'
+  TLS_DESCRIPTORS_FALSE=
+fi
+
+
 echo "$as_me:$LINENO: checking for constructor priorities" >&5
 echo $ECHO_N "checking for constructor priorities... $ECHO_C" >&6
 if test "${gold_cv_c_conprio+set}" = set; then
@@ -4648,8 +4738,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4823,8 +4912,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5151,8 +5239,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5322,8 +5409,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5394,8 +5480,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5449,8 +5534,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5513,8 +5597,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5916,8 +5999,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -6067,8 +6149,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -6252,8 +6333,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -6311,8 +6391,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_cxx_werror_flag"
-                        || test ! -s conftest.err'
+        { ac_try='test -z "$ac_cxx_werror_flag"                         || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -6530,6 +6609,20 @@ echo "$as_me: error: conditional \"STATIC_TLS\" was never defined.
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${TLS_GNU2_DIALECT_TRUE}" && test -z "${TLS_GNU2_DIALECT_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"TLS_GNU2_DIALECT\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"TLS_GNU2_DIALECT\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${TLS_DESCRIPTORS_TRUE}" && test -z "${TLS_DESCRIPTORS_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"TLS_DESCRIPTORS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"TLS_DESCRIPTORS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${CONSTRUCTOR_PRIORITY_TRUE}" && test -z "${CONSTRUCTOR_PRIORITY_FALSE}"; then
   { { echo "$as_me:$LINENO: error: conditional \"CONSTRUCTOR_PRIORITY\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -7181,6 +7274,10 @@ s,@TLS_TRUE@,$TLS_TRUE,;t t
 s,@TLS_FALSE@,$TLS_FALSE,;t t
 s,@STATIC_TLS_TRUE@,$STATIC_TLS_TRUE,;t t
 s,@STATIC_TLS_FALSE@,$STATIC_TLS_FALSE,;t t
+s,@TLS_GNU2_DIALECT_TRUE@,$TLS_GNU2_DIALECT_TRUE,;t t
+s,@TLS_GNU2_DIALECT_FALSE@,$TLS_GNU2_DIALECT_FALSE,;t t
+s,@TLS_DESCRIPTORS_TRUE@,$TLS_DESCRIPTORS_TRUE,;t t
+s,@TLS_DESCRIPTORS_FALSE@,$TLS_DESCRIPTORS_FALSE,;t t
 s,@CONSTRUCTOR_PRIORITY_TRUE@,$CONSTRUCTOR_PRIORITY_TRUE,;t t
 s,@CONSTRUCTOR_PRIORITY_FALSE@,$CONSTRUCTOR_PRIORITY_FALSE,;t t
 s,@WARN_CFLAGS@,$WARN_CFLAGS,;t t
@@ -7363,11 +7460,6 @@ esac
   *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
   esac
 
-  if test x"$ac_file" != x-; then
-    { echo "$as_me:$LINENO: creating $ac_file" >&5
-echo "$as_me: creating $ac_file" >&6;}
-    rm -f "$ac_file"
-  fi
   # Let's still pretend it is `configure' which instantiates (i.e., don't
   # use $as_me), people would be surprised to read:
   #    /* config.h.  Generated by config.status.  */
@@ -7406,6 +7498,12 @@ echo "$as_me: error: cannot find input file: $f" >&2;}
         fi;;
       esac
     done` || { (exit 1); exit 1; }
+
+  if test x"$ac_file" != x-; then
+    { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    rm -f "$ac_file"
+  fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
   sed "$ac_vpsub
index aa7fea07c0c65683ea6ab47c060e23f0f07cf713..dd9ad8aa129baf26168789c13bc25b2c0965d282 100644 (file)
@@ -219,6 +219,27 @@ error
 
 AM_CONDITIONAL(STATIC_TLS, test "$gold_cv_lib_glibc24" = "yes")
 
+dnl Test for the -ftls-dialect=gnu2 option.
+save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -mtls-dialect=gnu2"
+AC_COMPILE_IFELSE([int i;], [have_tls_gnu2=yes], [have_tls_gnu2=no])
+CFLAGS="$save_CFLAGS"
+AM_CONDITIONAL(TLS_GNU2_DIALECT, test "$have_tls_gnu2" = "yes")
+
+dnl On GNU/Linux TLS descriptors are supported by the dynamic loader
+dnl only with glibc 2.5 or later.
+AC_CACHE_CHECK([for glibc >= 2.5], [gold_cv_lib_glibc25],
+[AC_COMPILE_IFELSE([
+#include <features.h>
+#if !defined __GLIBC__
+error
+#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 5)
+error
+#endif
+], [gold_cv_lib_glibc25=yes], [gold_cv_lib_glibc25=no])])
+
+AM_CONDITIONAL(TLS_DESCRIPTORS, test "$gold_cv_lib_glibc25" = "yes")
+
 dnl Check whether the compiler supports constructor priorities in
 dnl attributes, which were added in gcc 4.3.
 AC_CACHE_CHECK([for constructor priorities], [gold_cv_c_conprio],
index 7cfe117854b126e2de3db40346e1de0192ea1ed1..c0b2e85335127eb108f834e5768fa40bd666bf88 100644 (file)
@@ -236,6 +236,26 @@ class Target_i386 : public Sized_target<32, false>
                 unsigned char* view,
                 section_size_type view_size);
 
+    // Do a TLS_GOTDESC or TLS_DESC_CALL General-Dynamic to Initial-Exec
+    // transition.
+    inline void
+    tls_desc_gd_to_ie(const Relocate_info<32, false>*, size_t relnum,
+                     Output_segment* tls_segment,
+                     const elfcpp::Rel<32, false>&, unsigned int r_type,
+                     elfcpp::Elf_types<32>::Elf_Addr value,
+                     unsigned char* view,
+                     section_size_type view_size);
+
+    // Do a TLS_GOTDESC or TLS_DESC_CALL General-Dynamic to Local-Exec
+    // transition.
+    inline void
+    tls_desc_gd_to_le(const Relocate_info<32, false>*, size_t relnum,
+                     Output_segment* tls_segment,
+                     const elfcpp::Rel<32, false>&, unsigned int r_type,
+                     elfcpp::Elf_types<32>::Elf_Addr value,
+                     unsigned char* view,
+                     section_size_type view_size);
+
     // Do a TLS Local-Dynamic to Local-Exec transition.
     inline void
     tls_ld_to_le(const Relocate_info<32, false>*, size_t relnum,
@@ -343,9 +363,10 @@ class Target_i386 : public Sized_target<32, false>
   enum Got_type
   {
     GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
-    GOT_TYPE_TLS_OFFSET = 1,    // GOT entry for TLS offset
-    GOT_TYPE_TLS_PAIR = 2,      // GOT entry for TLS module/offset pair
-    GOT_TYPE_TLS_DESC = 3       // GOT entry for TLS_DESC pair
+    GOT_TYPE_TLS_NOFFSET = 1,   // GOT entry for negative TLS offset
+    GOT_TYPE_TLS_OFFSET = 2,    // GOT entry for positive TLS offset
+    GOT_TYPE_TLS_PAIR = 3,      // GOT entry for TLS module/offset pair
+    GOT_TYPE_TLS_DESC = 4       // GOT entry for TLS_DESC pair
   };
 
   // The GOT section.
@@ -360,7 +381,7 @@ class Target_i386 : public Sized_target<32, false>
   Copy_relocs<32, false>* copy_relocs_;
   // Space for variables copied with a COPY reloc.
   Output_data_space* dynbss_;
-  // Offset of the GOT entry for the TLS module index;
+  // Offset of the GOT entry for the TLS module index.
   unsigned int got_mod_index_offset_;
 };
 
@@ -704,7 +725,6 @@ Target_i386::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
       unsigned int got_offset = got->add_constant(0);
       rel_dyn->add_local(object, 0, elfcpp::R_386_TLS_DTPMOD32, got,
                          got_offset);
-      got->add_constant(0);
       this->got_mod_index_offset_ = got_offset;
     }
   return this->got_mod_index_offset_;
@@ -1011,13 +1031,25 @@ Target_i386::Scan::local(const General_options&,
            break;
 
          case elfcpp::R_386_TLS_GOTDESC:     // Global-dynamic (from ~oliva)
-         case elfcpp::R_386_TLS_DESC_CALL:
-            // FIXME: If not relaxing to LE, we need to generate
-            // a GOT entry with an R_386_TLS_DESC reloc.
-            if (optimized_type != tls::TLSOPT_TO_LE)
+            if (optimized_type == tls::TLSOPT_NONE)
+              {
+                // Create a double GOT entry with an R_386_TLS_DESC reloc.
+                Output_data_got<32, false>* got
+                    = target->got_section(symtab, layout);
+                unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+                got->add_local_pair_with_rel(object, r_sym, 
+                                             lsym.get_st_shndx(),
+                                             GOT_TYPE_TLS_DESC,
+                                             target->rel_dyn_section(layout),
+                                             elfcpp::R_386_TLS_DESC, 0);
+              }
+            else if (optimized_type != tls::TLSOPT_TO_LE)
               unsupported_reloc_local(object, r_type);
            break;
 
+         case elfcpp::R_386_TLS_DESC_CALL:
+           break;
+
          case elfcpp::R_386_TLS_LDM:         // Local-dynamic
            if (optimized_type == tls::TLSOPT_NONE)
              {
@@ -1057,7 +1089,10 @@ Target_i386::Scan::local(const General_options&,
                unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
                                           ? elfcpp::R_386_TLS_TPOFF32
                                           : elfcpp::R_386_TLS_TPOFF);
-                got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+               unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+                                        ? GOT_TYPE_TLS_OFFSET
+                                        : GOT_TYPE_TLS_NOFFSET);
+                got->add_local_with_rel(object, r_sym, got_type,
                                         target->rel_dyn_section(layout),
                                         dyn_r_type);
              }
@@ -1313,21 +1348,38 @@ Target_i386::Scan::global(const General_options& options,
                // Create a GOT entry for the tp-relative offset.
                 Output_data_got<32, false>* got
                     = target->got_section(symtab, layout);
-                got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
                                          target->rel_dyn_section(layout),
-                                         elfcpp::R_386_TLS_TPOFF32);
+                                         elfcpp::R_386_TLS_TPOFF);
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
            break;
 
          case elfcpp::R_386_TLS_GOTDESC:     // Global-dynamic (~oliva url)
-         case elfcpp::R_386_TLS_DESC_CALL:
-            // FIXME: If not relaxing to LE, we need to generate
-            // a GOT entry with an R_386_TLS_DESC reloc.
-            if (optimized_type != tls::TLSOPT_TO_LE)
+            if (optimized_type == tls::TLSOPT_NONE)
+              {
+                // Create a double GOT entry with an R_386_TLS_DESC reloc.
+                Output_data_got<32, false>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC,
+                                             target->rel_dyn_section(layout),
+                                             elfcpp::R_386_TLS_DESC, 0);
+              }
+            else if (optimized_type == tls::TLSOPT_TO_IE)
+              {
+               // Create a GOT entry for the tp-relative offset.
+                Output_data_got<32, false>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
+                                         target->rel_dyn_section(layout),
+                                         elfcpp::R_386_TLS_TPOFF);
+              }
+            else if (optimized_type != tls::TLSOPT_TO_LE)
               unsupported_reloc_global(object, r_type, gsym);
-            unsupported_reloc_global(object, r_type, gsym);
+           break;
+
+         case elfcpp::R_386_TLS_DESC_CALL:
            break;
 
          case elfcpp::R_386_TLS_LDM:         // Local-dynamic
@@ -1366,7 +1418,10 @@ Target_i386::Scan::global(const General_options& options,
                unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
                                           ? elfcpp::R_386_TLS_TPOFF32
                                           : elfcpp::R_386_TLS_TPOFF);
-                got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+               unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+                                        ? GOT_TYPE_TLS_OFFSET
+                                        : GOT_TYPE_TLS_NOFFSET);
+                got->add_global_with_rel(gsym, got_type,
                                          target->rel_dyn_section(layout),
                                          dyn_r_type);
              }
@@ -1782,19 +1837,20 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
        }
       else
         {
+          unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+                                   ? GOT_TYPE_TLS_NOFFSET
+                                   : GOT_TYPE_TLS_PAIR);
           unsigned int got_offset;
           if (gsym != NULL)
             {
-              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_PAIR));
-              got_offset = (gsym->got_offset(GOT_TYPE_TLS_PAIR)
-                            - target->got_size());
+              gold_assert(gsym->has_got_offset(got_type));
+              got_offset = gsym->got_offset(got_type) - target->got_size();
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
-              gold_assert(object->local_has_got_offset(r_sym,
-                                                       GOT_TYPE_TLS_PAIR));
-              got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_PAIR)
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              got_offset = (object->local_got_offset(r_sym, got_type)
                            - target->got_size());
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
@@ -1819,6 +1875,50 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
 
     case elfcpp::R_386_TLS_GOTDESC:      // Global-dynamic (from ~oliva url)
     case elfcpp::R_386_TLS_DESC_CALL:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+        {
+         gold_assert(tls_segment != NULL);
+         this->tls_desc_gd_to_le(relinfo, relnum, tls_segment,
+                                 rel, r_type, value, view,
+                                 view_size);
+         break;
+        }
+      else
+        {
+          unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+                                   ? GOT_TYPE_TLS_NOFFSET
+                                   : GOT_TYPE_TLS_DESC);
+          unsigned int got_offset;
+          if (gsym != NULL)
+            {
+              gold_assert(gsym->has_got_offset(got_type));
+              got_offset = gsym->got_offset(got_type) - target->got_size();
+            }
+          else
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              got_offset = (object->local_got_offset(r_sym, got_type)
+                           - target->got_size());
+            }
+          if (optimized_type == tls::TLSOPT_TO_IE)
+           {
+              gold_assert(tls_segment != NULL);
+             this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type,
+                                      got_offset, view, view_size);
+              break;
+           }
+          else if (optimized_type == tls::TLSOPT_NONE)
+            {
+              if (r_type == elfcpp::R_386_TLS_GOTDESC)
+                {
+                  // Relocate the field with the offset of the pair of GOT
+                  // entries.
+                  Relocate_functions<32, false>::rel32(view, got_offset);
+                }
+              break;
+            }
+        }
       gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
                             _("unsupported reloc %u"),
                             r_type);
@@ -1882,19 +1982,20 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
         {
           // Relocate the field with the offset of the GOT entry for
           // the tp-relative offset of the symbol.
+         unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+                                  ? GOT_TYPE_TLS_OFFSET
+                                  : GOT_TYPE_TLS_NOFFSET);
           unsigned int got_offset;
           if (gsym != NULL)
             {
-              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
-              got_offset = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+              gold_assert(gsym->has_got_offset(got_type));
+              got_offset = gsym->got_offset(got_type);
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
-              gold_assert(object->local_has_got_offset(r_sym,
-                                                       GOT_TYPE_TLS_OFFSET));
-              got_offset = object->local_got_offset(r_sym,
-                                                    GOT_TYPE_TLS_OFFSET);
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              got_offset = object->local_got_offset(r_sym, got_type);
             }
           // For the R_386_TLS_IE relocation, we need to apply the
           // absolute address of the GOT entry.
@@ -2004,7 +2105,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo,
 inline void
 Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
                                    size_t relnum,
-                                   Output_segment* tls_segment,
+                                   Output_segment*,
                                    const elfcpp::Rel<32, false>& rel,
                                    unsigned int,
                                    elfcpp::Elf_types<32>::Elf_Addr value,
@@ -2026,9 +2127,8 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
 
   int roff = 5;
 
-  // FIXME: For now, support only one form.
-  tls::check_tls(relinfo, relnum, rel.get_r_offset(),
-                 op1 == 0x8d && op2 == 0x04);
+  // FIXME: For now, support only the first (SIB) form.
+  tls::check_tls(relinfo, relnum, rel.get_r_offset(), op2 == 0x04);
 
   if (op2 == 0x04)
     {
@@ -2058,7 +2158,6 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
        }
     }
 
-  value = tls_segment->memsz() - value;
   Relocate_functions<32, false>::rel32(view + roff, value);
 
   // The next reloc should be a PLT32 reloc against __tls_get_addr.
@@ -2066,6 +2165,83 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
   this->skip_call_tls_get_addr_ = true;
 }
 
+// Do a relocation in which we convert a TLS_GOTDESC or TLS_DESC_CALL
+// General-Dynamic to a Local-Exec.
+
+inline void
+Target_i386::Relocate::tls_desc_gd_to_le(
+    const Relocate_info<32, false>* relinfo,
+    size_t relnum,
+    Output_segment* tls_segment,
+    const elfcpp::Rel<32, false>& rel,
+    unsigned int r_type,
+    elfcpp::Elf_types<32>::Elf_Addr value,
+    unsigned char* view,
+    section_size_type view_size)
+{
+  if (r_type == elfcpp::R_386_TLS_GOTDESC)
+    {
+      // leal foo@TLSDESC(%ebx), %eax
+      // ==> leal foo@NTPOFF, %eax
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
+      tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+                     view[-2] == 0x8d && view[-1] == 0x83);
+      view[-1] = 0x05;
+      value -= tls_segment->memsz();
+      Relocate_functions<32, false>::rel32(view, value);
+    }
+  else
+    {
+      // call *foo@TLSCALL(%eax)
+      // ==> nop; nop
+      gold_assert(r_type == elfcpp::R_386_TLS_DESC_CALL);
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 2);
+      tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+                     view[0] == 0xff && view[1] == 0x10);
+      view[0] = 0x66;
+      view[1] = 0x90;
+    }
+}
+
+// Do a relocation in which we convert a TLS_GOTDESC or TLS_DESC_CALL
+// General-Dynamic to an Initial-Exec.
+
+inline void
+Target_i386::Relocate::tls_desc_gd_to_ie(
+    const Relocate_info<32, false>* relinfo,
+    size_t relnum,
+    Output_segment*,
+    const elfcpp::Rel<32, false>& rel,
+    unsigned int r_type,
+    elfcpp::Elf_types<32>::Elf_Addr value,
+    unsigned char* view,
+    section_size_type view_size)
+{
+  if (r_type == elfcpp::R_386_TLS_GOTDESC)
+    {
+      // leal foo@TLSDESC(%ebx), %eax
+      // ==> movl foo@GOTNTPOFF(%ebx), %eax
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
+      tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+                     view[-2] == 0x8d && view[-1] == 0x83);
+      view[-2] = 0x8b;
+      Relocate_functions<32, false>::rel32(view, value);
+    }
+  else
+    {
+      // call *foo@TLSCALL(%eax)
+      // ==> nop; nop
+      gold_assert(r_type == elfcpp::R_386_TLS_DESC_CALL);
+      tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 2);
+      tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+                     view[0] == 0xff && view[1] == 0x10);
+      view[0] = 0x66;
+      view[1] = 0x90;
+    }
+}
+
 // Do a relocation in which we convert a TLS Local-Dynamic to a
 // Local-Exec.
 
index 7a76f79377c129743980d547b6fb8d6cf68f1a93..9ec14625abf8750cea72b757800abe3ec90a993e 100644 (file)
@@ -1342,16 +1342,12 @@ Output_data_dynamic::Dynamic_entry::write(
     const Stringpool* pool) const
 {
   typename elfcpp::Elf_types<size>::Elf_WXword val;
-  switch (this->classification_)
+  switch (this->offset_)
     {
     case DYNAMIC_NUMBER:
       val = this->u_.val;
       break;
 
-    case DYNAMIC_SECTION_ADDRESS:
-      val = this->u_.od->address();
-      break;
-
     case DYNAMIC_SECTION_SIZE:
       val = this->u_.od->data_size();
       break;
@@ -1369,7 +1365,8 @@ Output_data_dynamic::Dynamic_entry::write(
       break;
 
     default:
-      gold_unreachable();
+      val = this->u_.od->address() + this->offset_;
+      break;
     }
 
   elfcpp::Dyn_write<size, big_endian> dw(pov);
index e69777554930691f8e227b569bf03a5a1f75cf8e..126ec71e9984abed74106fb1713ccb1c701a7c5a 100644 (file)
@@ -1534,6 +1534,13 @@ class Output_data_dynamic : public Output_section_data
   add_section_address(elfcpp::DT tag, const Output_data* od)
   { this->add_entry(Dynamic_entry(tag, od, false)); }
 
+  // Add a new dynamic entry with the address of output data
+  // plus a constant offset.
+  void
+  add_section_plus_offset(elfcpp::DT tag, const Output_data* od,
+                          unsigned int offset)
+  { this->add_entry(Dynamic_entry(tag, od, offset)); }
+
   // Add a new dynamic entry with the size of output data.
   void
   add_section_size(elfcpp::DT tag, const Output_data* od)
@@ -1573,25 +1580,31 @@ class Output_data_dynamic : public Output_section_data
    public:
     // Create an entry with a fixed numeric value.
     Dynamic_entry(elfcpp::DT tag, unsigned int val)
-      : tag_(tag), classification_(DYNAMIC_NUMBER)
+      : tag_(tag), offset_(DYNAMIC_NUMBER)
     { this->u_.val = val; }
 
     // Create an entry with the size or address of a section.
     Dynamic_entry(elfcpp::DT tag, const Output_data* od, bool section_size)
       : tag_(tag),
-       classification_(section_size
-                       ? DYNAMIC_SECTION_SIZE
-                       : DYNAMIC_SECTION_ADDRESS)
+       offset_(section_size
+               ? DYNAMIC_SECTION_SIZE
+               : DYNAMIC_SECTION_ADDRESS)
+    { this->u_.od = od; }
+
+    // Create an entry with the address of a section plus a constant offset.
+    Dynamic_entry(elfcpp::DT tag, const Output_data* od, unsigned int offset)
+      : tag_(tag),
+       offset_(offset)
     { this->u_.od = od; }
 
     // Create an entry with the address of a symbol.
     Dynamic_entry(elfcpp::DT tag, const Symbol* sym)
-      : tag_(tag), classification_(DYNAMIC_SYMBOL)
+      : tag_(tag), offset_(DYNAMIC_SYMBOL)
     { this->u_.sym = sym; }
 
     // Create an entry with a string.
     Dynamic_entry(elfcpp::DT tag, const char* str)
-      : tag_(tag), classification_(DYNAMIC_STRING)
+      : tag_(tag), offset_(DYNAMIC_STRING)
     { this->u_.str = str; }
 
     // Write the dynamic entry to an output view.
@@ -1600,25 +1613,27 @@ class Output_data_dynamic : public Output_section_data
     write(unsigned char* pov, const Stringpool*) const;
 
    private:
+    // Classification is encoded in the OFFSET field.
     enum Classification
     {
-      // Number.
-      DYNAMIC_NUMBER,
       // Section address.
-      DYNAMIC_SECTION_ADDRESS,
+      DYNAMIC_SECTION_ADDRESS = 0,
+      // Number.
+      DYNAMIC_NUMBER = -1U,
       // Section size.
-      DYNAMIC_SECTION_SIZE,
+      DYNAMIC_SECTION_SIZE = -2U,
       // Symbol adress.
-      DYNAMIC_SYMBOL,
+      DYNAMIC_SYMBOL = -3U,
       // String.
-      DYNAMIC_STRING
+      DYNAMIC_STRING = -4U
+      // Any other value indicates a section address plus OFFSET.
     };
 
     union
     {
       // For DYNAMIC_NUMBER.
       unsigned int val;
-      // For DYNAMIC_SECTION_ADDRESS and DYNAMIC_SECTION_SIZE.
+      // For DYNAMIC_SECTION_SIZE and section address plus OFFSET.
       const Output_data* od;
       // For DYNAMIC_SYMBOL.
       const Symbol* sym;
@@ -1627,8 +1642,8 @@ class Output_data_dynamic : public Output_section_data
     } u_;
     // The dynamic tag.
     elfcpp::DT tag_;
-    // The type of entry.
-    Classification classification_;
+    // The type of entry (Classification) or offset within a section.
+    unsigned int offset_;
   };
 
   // Add an entry to the list.
index cec5412e8e4efc47de7633ae01041662038897d2..8859520c2097287bb3f343c7c054e0960f0fcfe7 100644 (file)
@@ -410,12 +410,15 @@ check_PROGRAMS += tls_test
 check_PROGRAMS += tls_pic_test
 check_PROGRAMS += tls_shared_test
 check_PROGRAMS += tls_shared_ie_test
+check_PROGRAMS += tls_shared_gd_to_ie_test
 tls_test_pic.o: tls_test.cc
        $(CXXCOMPILE) -c -fpic -o $@ $<
 tls_test_file2_pic.o: tls_test_file2.cc
        $(CXXCOMPILE) -c -fpic -o $@ $<
 tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o gcctestdir/ld
        $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o
+tls_test_shared2.so: tls_test_file2_pic.o gcctestdir/ld
+       $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_pic.o
 
 tls_test_pic_ie.o: tls_test.cc
        $(CXXCOMPILE) -c -fpic -ftls-model=initial-exec -o $@ $<
@@ -444,6 +447,43 @@ tls_shared_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_ie_shared.so
 tls_shared_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
 tls_shared_ie_test_LDADD = tls_test_ie_shared.so -lpthread
 
+tls_shared_gd_to_ie_test_SOURCES = tls_test_main.cc
+tls_shared_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_pic.o tls_test_shared2.so
+tls_shared_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_gd_to_ie_test_LDADD = tls_test_pic.o tls_test_shared2.so -lpthread
+
+if TLS_GNU2_DIALECT
+
+check_PROGRAMS += tls_shared_gnu2_gd_to_ie_test
+
+tls_test_gnu2.o: tls_test.cc
+       $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+tls_test_file2_gnu2.o: tls_test_file2.cc
+       $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
+       $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_gnu2.o
+
+tls_shared_gnu2_gd_to_ie_test_SOURCES = tls_test_main.cc
+tls_shared_gnu2_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2.o tls_test_gnu2_shared2.so
+tls_shared_gnu2_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_gnu2_gd_to_ie_test_LDADD = tls_test_gnu2.o tls_test_gnu2_shared2.so -lpthread
+
+if TLS_DESCRIPTORS
+
+check_PROGRAMS += tls_shared_gnu2_test
+
+tls_test_gnu2_shared.so: tls_test_gnu2.o tls_test_file2_gnu2.o gcctestdir/ld
+       $(CXXLINK) -Bgcctestdir/ -shared tls_test_gnu2.o tls_test_file2_gnu2.o
+
+tls_shared_gnu2_test_SOURCES = tls_test_main.cc
+tls_shared_gnu2_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2_shared.so
+tls_shared_gnu2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+tls_shared_gnu2_test_LDADD = tls_test_gnu2_shared.so -lpthread
+
+endif TLS_DESCRIPTORS
+
+endif TLS_GNU2_DIALECT
+
 if STATIC_TLS
 check_PROGRAMS += tls_static_test
 check_PROGRAMS += tls_static_pic_test
index 0666360bd71efb13e3a91159002f6da8ceb7ea06..b46861f2de95498fbf6888ac4abce83ff1a6c41c 100644 (file)
@@ -46,7 +46,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
        $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
        $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
        $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
-       $(am__EXEEXT_10)
+       $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = basic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \
@@ -146,14 +146,17 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_4 = tls_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_pic_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_test \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_ie_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_ie_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_gd_to_ie_test
 @GCC_FALSE@tls_test_DEPENDENCIES =
 @NATIVE_LINKER_FALSE@tls_test_DEPENDENCIES =
 @TLS_FALSE@tls_test_DEPENDENCIES =
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_5 = tls_static_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_5 = tls_shared_gnu2_gd_to_ie_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__append_6 = tls_shared_gnu2_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__append_7 = tls_static_test \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@      tls_static_pic_test
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_6 = tls_shared_nonpic_test
-@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_7 = initpri1
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__append_8 = tls_shared_nonpic_test
+@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_9 = initpri1
 @CONSTRUCTOR_PRIORITY_FALSE@initpri1_DEPENDENCIES = libgoldtest.a \
 @CONSTRUCTOR_PRIORITY_FALSE@   ../libgold.a \
 @CONSTRUCTOR_PRIORITY_FALSE@   ../../libiberty/libiberty.a \
@@ -170,7 +173,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 # Test --detect-odr-violations
 
 # Similar to --detect-odr-violations: check for undefined symbols in .so's
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_8 = debug_msg.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_10 = debug_msg.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.sh ver_test_2.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_4.sh ver_test_5.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.sh \
@@ -183,7 +186,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 
 # We also want to make sure we do something reasonable when there's no
 # debug info available.  For the best test, we use .so's.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_9 = debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_11 = debug_msg.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err ver_test_2.syms \
@@ -191,7 +194,7 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_7.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_matching_test.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_10 = debug_msg.err \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_12 = debug_msg.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_ndebug.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ undef_symbol.err \
@@ -199,17 +202,17 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_3.stdout
 
 # Test -o when emitting to a special file (such as something in /dev).
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_11 = flagstest_o_specialfile
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_13 = flagstest_o_specialfile
 
 # Test --compress-debug-sections.  FIXME: check we actually compress.
 
 # The specialfile output has a tricky case when we also compress debug
 # sections, because it requires output-file resizing.
-@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_12 = flagstest_compress_debug_sections \
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__append_14 = flagstest_compress_debug_sections \
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections
 
 # Test symbol versioning.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_13 = ver_test ver_test_2 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_15 = ver_test ver_test_2 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6 script_test_1 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_2 justsyms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ binary_test script_test_3
@@ -304,15 +307,18 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_pic_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_test$(EXEEXT) \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_ie_test$(EXEEXT)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__EXEEXT_5 = tls_static_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_ie_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       tls_shared_gd_to_ie_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__EXEEXT_5 = tls_shared_gnu2_gd_to_ie_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am__EXEEXT_6 = tls_shared_gnu2_test$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@am__EXEEXT_7 = tls_static_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@      tls_static_pic_test$(EXEEXT)
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__EXEEXT_6 = tls_shared_nonpic_test$(EXEEXT)
-@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_7 = initpri1$(EXEEXT)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_8 = flagstest_o_specialfile$(EXEEXT)
-@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_9 = flagstest_compress_debug_sections$(EXEEXT) \
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am__EXEEXT_8 = tls_shared_nonpic_test$(EXEEXT)
+@CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_9 = initpri1$(EXEEXT)
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_10 = flagstest_o_specialfile$(EXEEXT)
+@GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_11 = flagstest_compress_debug_sections$(EXEEXT) \
 @GCC_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_LINKER_TRUE@ flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT)
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_10 = ver_test$(EXEEXT) \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_12 = ver_test$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_2$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_6$(EXEEXT) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_1$(EXEEXT) \
@@ -482,6 +488,17 @@ script_test_3_DEPENDENCIES = libgoldtest.a ../libgold.a \
 am__tls_pic_test_SOURCES_DIST = tls_test_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_pic_test_OBJECTS = tls_test_main.$(OBJEXT)
 tls_pic_test_OBJECTS = $(am_tls_pic_test_OBJECTS)
+am__tls_shared_gd_to_ie_test_SOURCES_DIST = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_shared_gd_to_ie_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_gd_to_ie_test_OBJECTS =  \
+       $(am_tls_shared_gd_to_ie_test_OBJECTS)
+am__tls_shared_gnu2_gd_to_ie_test_SOURCES_DIST = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am_tls_shared_gnu2_gd_to_ie_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_gnu2_gd_to_ie_test_OBJECTS =  \
+       $(am_tls_shared_gnu2_gd_to_ie_test_OBJECTS)
+am__tls_shared_gnu2_test_SOURCES_DIST = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@am_tls_shared_gnu2_test_OBJECTS = tls_test_main.$(OBJEXT)
+tls_shared_gnu2_test_OBJECTS = $(am_tls_shared_gnu2_test_OBJECTS)
 am__tls_shared_ie_test_SOURCES_DIST = tls_test_main.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@am_tls_shared_ie_test_OBJECTS = tls_test_main.$(OBJEXT)
 tls_shared_ie_test_OBJECTS = $(am_tls_shared_ie_test_OBJECTS)
@@ -685,7 +702,9 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(initpri1_SOURCES) $(justsyms_SOURCES) \
        $(object_unittest_SOURCES) $(script_test_1_SOURCES) \
        $(script_test_2_SOURCES) script_test_3.c \
-       $(tls_pic_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
+       $(tls_pic_test_SOURCES) $(tls_shared_gd_to_ie_test_SOURCES) \
+       $(tls_shared_gnu2_gd_to_ie_test_SOURCES) \
+       $(tls_shared_gnu2_test_SOURCES) $(tls_shared_ie_test_SOURCES) \
        $(tls_shared_nonpic_test_SOURCES) $(tls_shared_test_SOURCES) \
        $(tls_static_pic_test_SOURCES) $(tls_static_test_SOURCES) \
        $(tls_test_SOURCES) $(two_file_mixed_2_shared_test_SOURCES) \
@@ -729,6 +748,9 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
        $(object_unittest_SOURCES) $(am__script_test_1_SOURCES_DIST) \
        $(am__script_test_2_SOURCES_DIST) script_test_3.c \
        $(am__tls_pic_test_SOURCES_DIST) \
+       $(am__tls_shared_gd_to_ie_test_SOURCES_DIST) \
+       $(am__tls_shared_gnu2_gd_to_ie_test_SOURCES_DIST) \
+       $(am__tls_shared_gnu2_test_SOURCES_DIST) \
        $(am__tls_shared_ie_test_SOURCES_DIST) \
        $(am__tls_shared_nonpic_test_SOURCES_DIST) \
        $(am__tls_shared_test_SOURCES_DIST) \
@@ -797,7 +819,6 @@ GCC_FALSE = @GCC_FALSE@
 GCC_TRUE = @GCC_TRUE@
 GENCAT = @GENCAT@
 GMSGFMT = @GMSGFMT@
-GREP = @GREP@
 HAVE_ZLIB_FALSE = @HAVE_ZLIB_FALSE@
 HAVE_ZLIB_TRUE = @HAVE_ZLIB_TRUE@
 INCINTL = @INCINTL@
@@ -842,7 +863,11 @@ STRIP = @STRIP@
 TARGETOBJS = @TARGETOBJS@
 THREADS_FALSE = @THREADS_FALSE@
 THREADS_TRUE = @THREADS_TRUE@
+TLS_DESCRIPTORS_FALSE = @TLS_DESCRIPTORS_FALSE@
+TLS_DESCRIPTORS_TRUE = @TLS_DESCRIPTORS_TRUE@
 TLS_FALSE = @TLS_FALSE@
+TLS_GNU2_DIALECT_FALSE = @TLS_GNU2_DIALECT_FALSE@
+TLS_GNU2_DIALECT_TRUE = @TLS_GNU2_DIALECT_TRUE@
 TLS_TRUE = @TLS_TRUE@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
@@ -850,9 +875,10 @@ WARN_CFLAGS = @WARN_CFLAGS@
 WARN_CXXFLAGS = @WARN_CXXFLAGS@
 XGETTEXT = @XGETTEXT@
 YACC = @YACC@
-YFLAGS = @YFLAGS@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
 am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
 am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
 am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
@@ -869,30 +895,23 @@ build_cpu = @build_cpu@
 build_os = @build_os@
 build_vendor = @build_vendor@
 datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
 host_os = @host_os@
 host_vendor = @host_vendor@
-htmldir = @htmldir@
 includedir = @includedir@
 infodir = @infodir@
 install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
-localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
-psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 sysconfdir = @sysconfdir@
@@ -923,13 +942,13 @@ TEST_STRIP = $(top_builddir)/../binutils/strip-new
 # .o's), but not all of them (such as .so's and .err files).  We
 # improve on that here.  automake-1.9 info docs say "mostlyclean" is
 # the right choice for files 'make' builds that people rebuild.
-MOSTLYCLEANFILES = *.so $(am__append_10)
+MOSTLYCLEANFILES = *.so $(am__append_12)
 
 # We will add to these later, for each individual test.  Note
 # that we add each test under check_SCRIPTS or check_PROGRAMS;
 # the TESTS variable is automatically populated from these.
-check_SCRIPTS = $(am__append_8)
-check_DATA = $(am__append_9)
+check_SCRIPTS = $(am__append_10)
+check_DATA = $(am__append_11)
 TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
 
 # ---------------------------------------------------------------------
@@ -1143,6 +1162,18 @@ binary_unittest_SOURCES = binary_unittest.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_ie_shared.so
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_ie_test_LDADD = tls_test_ie_shared.so -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_pic.o tls_test_shared2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_shared_gd_to_ie_test_LDADD = tls_test_pic.o tls_test_shared2.so -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2.o tls_test_gnu2_shared2.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_gd_to_ie_test_LDADD = tls_test_gnu2.o tls_test_gnu2_shared2.so -lpthread
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_SOURCES = tls_test_main.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_DEPENDENCIES = gcctestdir/ld tls_test_gnu2_shared.so
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_shared_gnu2_test_LDADD = tls_test_gnu2_shared.so -lpthread
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_test_SOURCES = $(tls_test_SOURCES)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_test_DEPENDENCIES = $(tls_test_DEPENDENCIES)
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@STATIC_TLS_TRUE@@TLS_TRUE@tls_static_test_LDFLAGS = $(tls_test_LDFLAGS) -static
@@ -1333,6 +1364,15 @@ script_test_2$(EXEEXT): $(script_test_2_OBJECTS) $(script_test_2_DEPENDENCIES)
 tls_pic_test$(EXEEXT): $(tls_pic_test_OBJECTS) $(tls_pic_test_DEPENDENCIES) 
        @rm -f tls_pic_test$(EXEEXT)
        $(CXXLINK) $(tls_pic_test_LDFLAGS) $(tls_pic_test_OBJECTS) $(tls_pic_test_LDADD) $(LIBS)
+tls_shared_gd_to_ie_test$(EXEEXT): $(tls_shared_gd_to_ie_test_OBJECTS) $(tls_shared_gd_to_ie_test_DEPENDENCIES) 
+       @rm -f tls_shared_gd_to_ie_test$(EXEEXT)
+       $(CXXLINK) $(tls_shared_gd_to_ie_test_LDFLAGS) $(tls_shared_gd_to_ie_test_OBJECTS) $(tls_shared_gd_to_ie_test_LDADD) $(LIBS)
+tls_shared_gnu2_gd_to_ie_test$(EXEEXT): $(tls_shared_gnu2_gd_to_ie_test_OBJECTS) $(tls_shared_gnu2_gd_to_ie_test_DEPENDENCIES) 
+       @rm -f tls_shared_gnu2_gd_to_ie_test$(EXEEXT)
+       $(CXXLINK) $(tls_shared_gnu2_gd_to_ie_test_LDFLAGS) $(tls_shared_gnu2_gd_to_ie_test_OBJECTS) $(tls_shared_gnu2_gd_to_ie_test_LDADD) $(LIBS)
+tls_shared_gnu2_test$(EXEEXT): $(tls_shared_gnu2_test_OBJECTS) $(tls_shared_gnu2_test_DEPENDENCIES) 
+       @rm -f tls_shared_gnu2_test$(EXEEXT)
+       $(CXXLINK) $(tls_shared_gnu2_test_LDFLAGS) $(tls_shared_gnu2_test_OBJECTS) $(tls_shared_gnu2_test_LDADD) $(LIBS)
 tls_shared_ie_test$(EXEEXT): $(tls_shared_ie_test_OBJECTS) $(tls_shared_ie_test_DEPENDENCIES) 
        @rm -f tls_shared_ie_test$(EXEEXT)
        $(CXXLINK) $(tls_shared_ie_test_LDFLAGS) $(tls_shared_ie_test_OBJECTS) $(tls_shared_ie_test_LDADD) $(LIBS)
@@ -1854,6 +1894,8 @@ uninstall-am: uninstall-info-am
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXCOMPILE) -c -fpic -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared2.so: tls_test_file2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_pic.o
 
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_pic_ie.o: tls_test.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXCOMPILE) -c -fpic -ftls-model=initial-exec -o $@ $<
@@ -1861,6 +1903,16 @@ uninstall-am: uninstall-info-am
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXCOMPILE) -c -fpic -ftls-model=initial-exec -o $@ $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_ie_shared.so: tls_test_pic_ie.o tls_test_file2_pic_ie.o gcctestdir/ld
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic_ie.o tls_test_file2_pic_ie.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2.o: tls_test.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@        $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_file2_gnu2.o: tls_test_file2.cc
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@        $(CXXCOMPILE) -c -fpic -mtls-dialect=gnu2 -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2_shared2.so: tls_test_file2_gnu2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@        $(CXXLINK) -Bgcctestdir/ -shared tls_test_file2_gnu2.o
+
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@tls_test_gnu2_shared.so: tls_test_gnu2.o tls_test_file2_gnu2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_DESCRIPTORS_TRUE@@TLS_GNU2_DIALECT_TRUE@@TLS_TRUE@  $(CXXLINK) -Bgcctestdir/ -shared tls_test_gnu2.o tls_test_file2_gnu2.o
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o gcctestdir/ld
 @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@       $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.o: debug_msg.cc
index 34f54c8e761533d2c81aff8c09ebf5f7e50e9f73..e60b3f6fa40c9e372108688a673d7e9021063d91 100644 (file)
@@ -227,13 +227,14 @@ class Target_x86_64 : public Sized_target<64, false>
                 unsigned char*, elfcpp::Elf_types<64>::Elf_Addr,
                 section_size_type);
 
-    // Do a TLS General-Dynamic to Local-Exec transition.
+    // Do a TLS General-Dynamic to Initial-Exec transition.
     inline void
     tls_gd_to_ie(const Relocate_info<64, false>*, size_t relnum,
                 Output_segment* tls_segment,
                 const elfcpp::Rela<64, false>&, unsigned int r_type,
                 elfcpp::Elf_types<64>::Elf_Addr value,
                 unsigned char* view,
+                elfcpp::Elf_types<64>::Elf_Addr,
                 section_size_type view_size);
 
     // Do a TLS General-Dynamic to Local-Exec transition.
@@ -245,6 +246,25 @@ class Target_x86_64 : public Sized_target<64, false>
                 unsigned char* view,
                 section_size_type view_size);
 
+    // Do a TLSDESC-style General-Dynamic to Initial-Exec transition.
+    inline void
+    tls_desc_gd_to_ie(const Relocate_info<64, false>*, size_t relnum,
+                     Output_segment* tls_segment,
+                     const elfcpp::Rela<64, false>&, unsigned int r_type,
+                     elfcpp::Elf_types<64>::Elf_Addr value,
+                     unsigned char* view,
+                     elfcpp::Elf_types<64>::Elf_Addr,
+                     section_size_type view_size);
+
+    // Do a TLSDESC-style General-Dynamic to Local-Exec transition.
+    inline void
+    tls_desc_gd_to_le(const Relocate_info<64, false>*, size_t relnum,
+                     Output_segment* tls_segment,
+                     const elfcpp::Rela<64, false>&, unsigned int r_type,
+                     elfcpp::Elf_types<64>::Elf_Addr value,
+                     unsigned char* view,
+                     section_size_type view_size);
+
     // Do a TLS Local-Dynamic to Local-Exec transition.
     inline void
     tls_ld_to_le(const Relocate_info<64, false>*, size_t relnum,
@@ -294,10 +314,18 @@ class Target_x86_64 : public Sized_target<64, false>
     return this->got_plt_;
   }
 
+  // Create the PLT section.
+  void
+  make_plt_section(Symbol_table* symtab, Layout* layout);
+
   // Create a PLT entry for a global symbol.
   void
   make_plt_entry(Symbol_table*, Layout*, Symbol*);
 
+  // Create the reserved PLT and GOT entries for the TLS descriptor resolver.
+  void
+  reserve_tlsdesc_entries(Symbol_table* symtab, Layout* layout);
+
   // Create a GOT entry for the TLS module index.
   unsigned int
   got_mod_index_entry(Symbol_table* symtab, Layout* layout,
@@ -356,7 +384,7 @@ class Target_x86_64 : public Sized_target<64, false>
   Copy_relocs<64, false>* copy_relocs_;
   // Space for variables copied with a COPY reloc.
   Output_data_space* dynbss_;
-  // Offset of the GOT entry for the TLS module index;
+  // Offset of the GOT entry for the TLS module index.
   unsigned int got_mod_index_offset_;
 };
 
@@ -437,12 +465,33 @@ class Output_data_plt_x86_64 : public Output_section_data
  public:
   typedef Output_data_reloc<elfcpp::SHT_RELA, true, 64, false> Reloc_section;
 
-  Output_data_plt_x86_64(Layout*, Output_data_space*);
+  Output_data_plt_x86_64(Layout*, Output_data_got<64, false>*,
+                         Output_data_space*);
 
   // Add an entry to the PLT.
   void
   add_entry(Symbol* gsym);
 
+  // Add the reserved TLSDESC_PLT entry to the PLT.
+  void
+  reserve_tlsdesc_entry(unsigned int got_offset)
+  { this->tlsdesc_got_offset_ = got_offset; }
+
+  // Return true if a TLSDESC_PLT entry has been reserved.
+  bool
+  has_tlsdesc_entry() const
+  { return this->tlsdesc_got_offset_ != -1U; }
+
+  // Return the GOT offset for the reserved TLSDESC_PLT entry.
+  unsigned int
+  get_tlsdesc_got_offset() const
+  { return this->tlsdesc_got_offset_; }
+
+  // Return the offset of the reserved TLSDESC_PLT entry.
+  unsigned int
+  get_tlsdesc_plt_offset() const
+  { return (this->count_ + 1) * plt_entry_size; }
+
   // Return the .rel.plt section data.
   const Reloc_section*
   rel_plt() const
@@ -464,10 +513,12 @@ class Output_data_plt_x86_64 : public Output_section_data
   // Other entries in the PLT for an executable.
   static unsigned char plt_entry[plt_entry_size];
 
+  // The reserved TLSDESC entry in the PLT for an executable.
+  static unsigned char tlsdesc_plt_entry[plt_entry_size];
+
   // Set the final size.
   void
-  set_final_data_size()
-  { this->set_data_size((this->count_ + 1) * plt_entry_size); }
+  set_final_data_size();
 
   // Write out the PLT data.
   void
@@ -475,10 +526,14 @@ class Output_data_plt_x86_64 : public Output_section_data
 
   // The reloc section.
   Reloc_section* rel_;
+  // The .got section.
+  Output_data_got<64, false>* got_;
   // The .got.plt section.
   Output_data_space* got_plt_;
   // The number of PLT entries.
   unsigned int count_;
+  // Offset of the reserved TLSDESC_GOT entry when needed.
+  unsigned int tlsdesc_got_offset_;
 };
 
 // Create the PLT section.  The ordinary .got section is an argument,
@@ -486,8 +541,10 @@ class Output_data_plt_x86_64 : public Output_section_data
 // section just for PLT entries.
 
 Output_data_plt_x86_64::Output_data_plt_x86_64(Layout* layout,
+                                               Output_data_got<64, false>* got,
                                                Output_data_space* got_plt)
-  : Output_section_data(8), got_plt_(got_plt), count_(0)
+  : Output_section_data(8), got_(got), got_plt_(got_plt), count_(0),
+    tlsdesc_got_offset_(-1U)
 {
   this->rel_ = new Reloc_section();
   layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
@@ -532,6 +589,16 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym)
   // appear in the relocations.
 }
 
+// Set the final size.
+void
+Output_data_plt_x86_64::set_final_data_size()
+{
+  unsigned int count = this->count_;
+  if (this->has_tlsdesc_entry())
+    ++count;
+  this->set_data_size((count + 1) * plt_entry_size);
+}
+
 // The first entry in the PLT for an executable.
 
 unsigned char Output_data_plt_x86_64::first_plt_entry[plt_entry_size] =
@@ -557,6 +624,20 @@ unsigned char Output_data_plt_x86_64::plt_entry[plt_entry_size] =
   0, 0, 0, 0   // replaced with offset to start of .plt
 };
 
+// The reserved TLSDESC entry in the PLT for an executable.
+
+unsigned char Output_data_plt_x86_64::tlsdesc_plt_entry[plt_entry_size] =
+{
+  // From Alexandre Oliva, "Thread-Local Storage Descriptors for IA32
+  // and AMD64/EM64T", Version 0.9.4 (2005-10-10).
+  0xff, 0x35,  // pushq x(%rip)
+  0, 0, 0, 0,  // replaced with address of linkmap GOT entry (at PLTGOT + 8)
+  0xff,        0x25,   // jmpq *y(%rip)
+  0, 0, 0, 0,  // replaced with offset of reserved TLSDESC_GOT entry
+  0x0f,        0x1f,   // nop
+  0x40, 0
+};
+
 // Write out the PLT.  This uses the hand-coded instructions above,
 // and adjusts them as needed.  This is specified by the AMD64 ABI.
 
@@ -576,7 +657,13 @@ Output_data_plt_x86_64::do_write(Output_file* of)
 
   unsigned char* pov = oview;
 
+  // The base address of the .plt section.
   elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
+  // The base address of the .got section.
+  elfcpp::Elf_types<32>::Elf_Addr got_base = this->got_->address();
+  // The base address of the PLT portion of the .got section,
+  // which is where the GOT pointer will point, and where the
+  // three reserved GOT entries are located.
   elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
 
   memcpy(pov, first_plt_entry, plt_entry_size);
@@ -618,6 +705,23 @@ Output_data_plt_x86_64::do_write(Output_file* of)
       elfcpp::Swap<64, false>::writeval(got_pov, plt_address + plt_offset + 6);
     }
 
+  if (this->has_tlsdesc_entry())
+    {
+      // Set and adjust the reserved TLSDESC PLT entry.
+      unsigned int tlsdesc_got_offset = this->get_tlsdesc_got_offset();
+      memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
+      elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+                                                 (got_address + 8
+                                                  - (plt_address + plt_offset
+                                                     + 6)));
+      elfcpp::Swap_unaligned<32, false>::writeval(pov + 8,
+                                                 (got_base
+                                                  + tlsdesc_got_offset
+                                                  - (plt_address + plt_offset
+                                                     + 12)));
+      pov += plt_entry_size;
+    }
+
   gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
   gold_assert(static_cast<section_size_type>(got_pov - got_view) == got_size);
 
@@ -625,30 +729,60 @@ Output_data_plt_x86_64::do_write(Output_file* of)
   of->write_output_view(got_file_offset, got_size, got_view);
 }
 
-// Create a PLT entry for a global symbol.
+// Create the PLT section.
 
 void
-Target_x86_64::make_plt_entry(Symbol_table* symtab, Layout* layout,
-                              Symbol* gsym)
+Target_x86_64::make_plt_section(Symbol_table* symtab, Layout* layout)
 {
-  if (gsym->has_plt_offset())
-    return;
-
   if (this->plt_ == NULL)
     {
       // Create the GOT sections first.
       this->got_section(symtab, layout);
 
-      this->plt_ = new Output_data_plt_x86_64(layout, this->got_plt_);
+      this->plt_ = new Output_data_plt_x86_64(layout, this->got_,
+                                              this->got_plt_);
       layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_EXECINSTR),
                                      this->plt_);
     }
+}
+
+// Create a PLT entry for a global symbol.
+
+void
+Target_x86_64::make_plt_entry(Symbol_table* symtab, Layout* layout,
+                              Symbol* gsym)
+{
+  if (gsym->has_plt_offset())
+    return;
+
+  if (this->plt_ == NULL)
+    this->make_plt_section(symtab, layout);
 
   this->plt_->add_entry(gsym);
 }
 
+// Create the reserved PLT and GOT entries for the TLS descriptor resolver.
+
+void
+Target_x86_64::reserve_tlsdesc_entries(Symbol_table* symtab,
+                                             Layout* layout)
+{
+  if (this->plt_ == NULL)
+    this->make_plt_section(symtab, layout);
+
+  if (!this->plt_->has_tlsdesc_entry())
+    {
+      // Allocate the TLSDESC_GOT entry.
+      Output_data_got<64, false>* got = this->got_section(symtab, layout);
+      unsigned int got_offset = got->add_constant(0);
+
+      // Allocate the TLSDESC_PLT entry.
+      this->plt_->reserve_tlsdesc_entry(got_offset);
+    }
+}
+
 // Create a GOT entry for the TLS module index.
 
 unsigned int
@@ -663,7 +797,6 @@ Target_x86_64::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
       unsigned int got_offset = got->add_constant(0);
       rela_dyn->add_local(object, 0, elfcpp::R_X86_64_DTPMOD64, got,
                           got_offset, 0);
-      got->add_constant(0);
       this->got_mod_index_offset_ = got_offset;
     }
   return this->got_mod_index_offset_;
@@ -1032,13 +1165,28 @@ Target_x86_64::Scan::local(const General_options&,
             break;
 
           case elfcpp::R_X86_64_GOTPC32_TLSDESC:
-          case elfcpp::R_X86_64_TLSDESC_CALL:
-           // FIXME: If not relaxing to LE, we need to generate
-           // a GOT entry with a R_x86_64_TLSDESC reloc.
-           if (optimized_type != tls::TLSOPT_TO_LE)
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create reserved PLT and GOT entries for the resolver.
+               target->reserve_tlsdesc_entries(symtab, layout);
+
+               // Generate a double GOT entry with an R_X86_64_TLSDESC reloc.
+                Output_data_got<64, false>* got
+                    = target->got_section(symtab, layout);
+                unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
+                got->add_local_pair_with_rela(object, r_sym,
+                                              lsym.get_st_shndx(),
+                                              GOT_TYPE_TLS_DESC,
+                                              target->rela_dyn_section(layout),
+                                              elfcpp::R_X86_64_TLSDESC, 0);
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
            break;
 
+          case elfcpp::R_X86_64_TLSDESC_CALL:
+           break;
+
           case elfcpp::R_X86_64_TLSLD:       // Local-dynamic
            if (optimized_type == tls::TLSOPT_NONE)
              {
@@ -1317,13 +1465,34 @@ Target_x86_64::Scan::global(const General_options& options,
            break;
 
           case elfcpp::R_X86_64_GOTPC32_TLSDESC:
-          case elfcpp::R_X86_64_TLSDESC_CALL:
-           // FIXME: If not relaxing to LE, we need to generate
-           // DTPMOD64 and DTPOFF64, or TLSDESC, relocs.
-           if (optimized_type != tls::TLSOPT_TO_LE)
+           if (optimized_type == tls::TLSOPT_NONE)
+             {
+               // Create reserved PLT and GOT entries for the resolver.
+               target->reserve_tlsdesc_entries(symtab, layout);
+
+               // Create a double GOT entry with an R_X86_64_TLSDESC reloc.
+                Output_data_got<64, false>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC,
+                                               target->rela_dyn_section(layout),
+                                               elfcpp::R_X86_64_TLSDESC, 0);
+             }
+           else if (optimized_type == tls::TLSOPT_TO_IE)
+             {
+               // Create a GOT entry for the tp-relative offset.
+                Output_data_got<64, false>* got
+                    = target->got_section(symtab, layout);
+                got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
+                                          target->rela_dyn_section(layout),
+                                          elfcpp::R_X86_64_TPOFF64);
+             }
+           else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
            break;
 
+          case elfcpp::R_X86_64_TLSDESC_CALL:
+           break;
+
           case elfcpp::R_X86_64_TLSLD:       // Local-dynamic
            if (optimized_type == tls::TLSOPT_NONE)
              {
@@ -1432,6 +1601,16 @@ Target_x86_64::do_finalize_sections(Layout* layout)
          odyn->add_section_size(elfcpp::DT_PLTRELSZ, od);
          odyn->add_section_address(elfcpp::DT_JMPREL, od);
          odyn->add_constant(elfcpp::DT_PLTREL, elfcpp::DT_RELA);
+         if (this->plt_->has_tlsdesc_entry())
+           {
+              unsigned int plt_offset = this->plt_->get_tlsdesc_plt_offset();
+              unsigned int got_offset = this->plt_->get_tlsdesc_got_offset();
+              this->got_->finalize_data_size();
+              odyn->add_section_plus_offset(elfcpp::DT_TLSDESC_PLT,
+                                            this->plt_, plt_offset);
+              odyn->add_section_plus_offset(elfcpp::DT_TLSDESC_GOT,
+                                            this->got_, got_offset);
+           }
        }
 
       if (this->rela_dyn_ != NULL)
@@ -1746,8 +1925,6 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
   switch (r_type)
     {
     case elfcpp::R_X86_64_TLSGD:            // Global-dynamic
-    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
-    case elfcpp::R_X86_64_TLSDESC_CALL:
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
          gold_assert(tls_segment != NULL);
@@ -1758,26 +1935,28 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
        }
       else
         {
+          unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+                                   ? GOT_TYPE_TLS_OFFSET
+                                   : GOT_TYPE_TLS_PAIR);
           unsigned int got_offset;
           if (gsym != NULL)
             {
-              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_PAIR));
-              got_offset = (gsym->got_offset(GOT_TYPE_TLS_PAIR)
-                            - target->got_size());
+              gold_assert(gsym->has_got_offset(got_type));
+              got_offset = gsym->got_offset(got_type) - target->got_size();
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
-              gold_assert(object->local_has_got_offset(r_sym,
-                          GOT_TYPE_TLS_PAIR));
-              got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_PAIR)
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              got_offset = (object->local_got_offset(r_sym, got_type)
                             - target->got_size());
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
             {
               gold_assert(tls_segment != NULL);
+              value = target->got_plt_section()->address() + got_offset;
               this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type,
-                                 got_offset, view, view_size);
+                                 value, view, address, view_size);
               break;
             }
           else if (optimized_type == tls::TLSOPT_NONE)
@@ -1794,6 +1973,60 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
                             _("unsupported reloc %u"), r_type);
       break;
 
+    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
+    case elfcpp::R_X86_64_TLSDESC_CALL:
+      if (optimized_type == tls::TLSOPT_TO_LE)
+       {
+         gold_assert(tls_segment != NULL);
+         this->tls_desc_gd_to_le(relinfo, relnum, tls_segment,
+                                 rela, r_type, value, view,
+                                 view_size);
+         break;
+       }
+      else
+        {
+          unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+                                   ? GOT_TYPE_TLS_OFFSET
+                                   : GOT_TYPE_TLS_DESC);
+          unsigned int got_offset;
+          if (gsym != NULL)
+            {
+              gold_assert(gsym->has_got_offset(got_type));
+              got_offset = gsym->got_offset(got_type) - target->got_size();
+            }
+          else
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
+              gold_assert(object->local_has_got_offset(r_sym, got_type));
+              got_offset = (object->local_got_offset(r_sym, got_type)
+                            - target->got_size());
+            }
+          if (optimized_type == tls::TLSOPT_TO_IE)
+            {
+              gold_assert(tls_segment != NULL);
+              value = target->got_plt_section()->address() + got_offset;
+              this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment,
+                                      rela, r_type, value, view, address,
+                                      view_size);
+              break;
+            }
+          else if (optimized_type == tls::TLSOPT_NONE)
+            {
+              if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
+                {
+                  // Relocate the field with the offset of the pair of GOT
+                  // entries.
+                 value = target->got_plt_section()->address() + got_offset;
+                  Relocate_functions<64, false>::pcrela32(view, value, addend,
+                                                          address);
+                }
+              break;
+            }
+        }
+      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                            _("unsupported reloc %u"), r_type);
+      break;
+
     case elfcpp::R_X86_64_TLSLD:            // Local-dynamic
       if (optimized_type == tls::TLSOPT_TO_LE)
         {
@@ -1882,11 +2115,12 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
 inline void
 Target_x86_64::Relocate::tls_gd_to_ie(const Relocate_info<64, false>* relinfo,
                                       size_t relnum,
-                                      Output_segment* tls_segment,
+                                      Output_segment*,
                                       const elfcpp::Rela<64, false>& rela,
                                       unsigned int,
                                       elfcpp::Elf_types<64>::Elf_Addr value,
                                       unsigned char* view,
+                                      elfcpp::Elf_types<64>::Elf_Addr address,
                                       section_size_type view_size)
 {
   // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
@@ -1903,8 +2137,8 @@ Target_x86_64::Relocate::tls_gd_to_ie(const Relocate_info<64, false>* relinfo,
 
   memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", 16);
 
-  value -= tls_segment->memsz();
-  Relocate_functions<64, false>::rela32(view + 8, value, 0);
+  const elfcpp::Elf_Xword addend = rela.get_r_addend();
+  Relocate_functions<64, false>::pcrela32(view + 8, value, addend - 8, address);
 
   // The next reloc should be a PLT32 reloc against __tls_get_addr.
   // We can skip it.
@@ -1946,6 +2180,84 @@ Target_x86_64::Relocate::tls_gd_to_le(const Relocate_info<64, false>* relinfo,
   this->skip_call_tls_get_addr_ = true;
 }
 
+// Do a TLSDESC-style General-Dynamic to Initial-Exec transition.
+
+inline void
+Target_x86_64::Relocate::tls_desc_gd_to_ie(
+    const Relocate_info<64, false>* relinfo,
+    size_t relnum,
+    Output_segment*,
+    const elfcpp::Rela<64, false>& rela,
+    unsigned int r_type,
+    elfcpp::Elf_types<64>::Elf_Addr value,
+    unsigned char* view,
+    elfcpp::Elf_types<64>::Elf_Addr address,
+    section_size_type view_size)
+{
+  if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
+    {
+      // leaq foo@tlsdesc(%rip), %rax
+      // ==> movq foo@gottpoff(%rip), %rax
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                     view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
+      view[-2] = 0x8b;
+      const elfcpp::Elf_Xword addend = rela.get_r_addend();
+      Relocate_functions<64, false>::pcrela32(view, value, addend, address);
+    }
+  else
+    {
+      // call *foo@tlscall(%rax)
+      // ==> nop; nop
+      gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                     view[0] == 0xff && view[1] == 0x10);
+      view[0] = 0x66;
+      view[1] = 0x90;
+    }
+}
+
+// Do a TLSDESC-style General-Dynamic to Local-Exec transition.
+
+inline void
+Target_x86_64::Relocate::tls_desc_gd_to_le(
+    const Relocate_info<64, false>* relinfo,
+    size_t relnum,
+    Output_segment* tls_segment,
+    const elfcpp::Rela<64, false>& rela,
+    unsigned int r_type,
+    elfcpp::Elf_types<64>::Elf_Addr value,
+    unsigned char* view,
+    section_size_type view_size)
+{
+  if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
+    {
+      // leaq foo@tlsdesc(%rip), %rax
+      // ==> movq foo@tpoff, %rax
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                     view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
+      view[-2] = 0xc7;
+      view[-1] = 0xc0;
+      value -= tls_segment->memsz();
+      Relocate_functions<64, false>::rela32(view, value, 0);
+    }
+  else
+    {
+      // call *foo@tlscall(%rax)
+      // ==> nop; nop
+      gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
+      tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
+      tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+                     view[0] == 0xff && view[1] == 0x10);
+      view[0] = 0x66;
+      view[1] = 0x90;
+    }
+}
+
 inline void
 Target_x86_64::Relocate::tls_ld_to_le(const Relocate_info<64, false>* relinfo,
                                       size_t relnum,