aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/ChangeLog79
-rw-r--r--gold/Makefile.in15
-rwxr-xr-xgold/configure216
-rw-r--r--gold/configure.ac21
-rw-r--r--gold/i386.cc246
-rw-r--r--gold/output.cc9
-rw-r--r--gold/output.h45
-rw-r--r--gold/testsuite/Makefile.am40
-rw-r--r--gold/testsuite/Makefile.in114
-rw-r--r--gold/x86_64.cc380
10 files changed, 976 insertions, 189 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 9bb3c20..cc05b97 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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
diff --git a/gold/Makefile.in b/gold/Makefile.in
index 03f4c0d..6acd7de 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -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@
diff --git a/gold/configure b/gold/configure
index e90d04d..4201127 100755
--- a/gold/configure
+++ b/gold/configure
@@ -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
diff --git a/gold/configure.ac b/gold/configure.ac
index aa7fea0..dd9ad8a 100644
--- a/gold/configure.ac
+++ b/gold/configure.ac
@@ -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],
diff --git a/gold/i386.cc b/gold/i386.cc
index 7cfe117..c0b2e85 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -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.
diff --git a/gold/output.cc b/gold/output.cc
index 7a76f79..9ec1462 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -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);
diff --git a/gold/output.h b/gold/output.h
index e697775..126ec71 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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.
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index cec5412..8859520 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -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
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index 0666360..b46861f 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -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
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 34f54c8..e60b3f6 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -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,