diff options
Diffstat (limited to 'gold')
-rw-r--r-- | gold/ChangeLog | 79 | ||||
-rw-r--r-- | gold/Makefile.in | 15 | ||||
-rwxr-xr-x | gold/configure | 216 | ||||
-rw-r--r-- | gold/configure.ac | 21 | ||||
-rw-r--r-- | gold/i386.cc | 246 | ||||
-rw-r--r-- | gold/output.cc | 9 | ||||
-rw-r--r-- | gold/output.h | 45 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 40 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 114 | ||||
-rw-r--r-- | gold/x86_64.cc | 380 |
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, |