[BZ,#14995] glibc fails to build if gold is the default linker, even if ld.bfd is available

Message ID 20150310132049.GA29526@gmail.com
State New, archived
Headers

Commit Message

H.J. Lu March 10, 2015, 1:20 p.m. UTC
  On Tue, Mar 10, 2015 at 05:57:32AM -0700, H.J. Lu wrote:
> Use gold to build glibc exposed some serious gold bugs.  I opened:
> 
> https://sourceware.org/bugzilla/show_bug.cgi?id=18102
> https://sourceware.org/bugzilla/show_bug.cgi?id=18103
> 
> and noted:
> 
> https://sourceware.org/bugzilla/show_bug.cgi?id=14995#c10
> 
> This patch adds --enable-gold to use gold to build glibc.  It can be
> used to work on gold issues.  If --enable-gold isn't used, it will check
> if gold is the default linker and -fuse-ld=bfd is available.  If gold
> is the default linker, uses -fuse-ld=bfd to create shared libraries if
> it is available.  Tested on x32, x86-64 and x86-32.  OK for master?  
> 
> 
> H.J.
> ----
> The gold linker has no builtin default linker script and it can't be
> to create shared libraries.  Unless --enable-gold is used, it should
> only be used to create executables.  Use -fuse-ld=bfd to create shared
> libraries.
> 
> 	[BZ #14995]
> 	* Makerules (shlib-LDFLAGS): New.
> 	($(common-objpfx)shlib.lds): Use it.
> 	(build-shlib): Likewise.
> 	(build-module-helper): Likewise.
> 	($(common-objpfx)libc_pic.os): Likewise.
> 	* config.make.in (use-bfd): New.
> 	* configure: Regenerated.
> 	* configure.ac: Add --enable-gold.
> 	Accept gold 1.11 or higher.
> 	(libc_cv_cc_use_bfd): Set to yes if -fuse-ld=bfd works.  AC_SUBST.
> 	(LDBFDFLAGS): New.
> 	Use $LDBFDFLAGS to check if default -shared layout is sufficient.

Small update to properly handle ld is gold.

H.J.
---
From 389ed28d1175b67ee5dcd40e69df912d4a1109b0 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Mon, 9 Mar 2015 09:16:26 -0700
Subject: [PATCH] Support build glibc with gold as default linker

The gold linker has no builtin default linker script and it can't be
to create shared libraries.  Unless --enable-gold is used, it should
only be used to create executables.  Use -fuse-ld=bfd to create shared
libraries.

	[BZ #14995]
	* Makerules (shlib-LDFLAGS): New.
	($(common-objpfx)shlib.lds): Use it.
	(build-shlib): Likewise.
	(build-module-helper): Likewise.
	($(common-objpfx)libc_pic.os): Likewise.
	* config.make.in (use-bfd): New.
	* configure: Regenerated.
	* configure.ac: Add --enable-gold.
	Accept gold 1.11 or higher.
	(libc_cv_cc_use_bfd): Set to yes if -fuse-ld=bfd works.  AC_SUBST.
	(LDBFDFLAGS): New.
	Use $LDBFDFLAGS to check if default -shared layout is sufficient.
---
 Makerules      |  13 ++++--
 config.make.in |   1 +
 configure      | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 configure.ac   |  66 ++++++++++++++++++++++++---
 4 files changed, 207 insertions(+), 13 deletions(-)
  

Patch

diff --git a/Makerules b/Makerules
index c79915f..1b0ded0 100644
--- a/Makerules
+++ b/Makerules
@@ -517,6 +517,11 @@  $(LINK.o) -shared $(static-libgcc) -Wl,-O1 $(sysdep-LDFLAGS) \
 	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
 endef
 
+ifeq (yes,$(use-bfd))
+# Use BFD linker to create shared libraries.
+shlib-LDFLAGS = -fuse-ld=bfd
+endif
+
 ifeq (yes,$(use-default-link))
 # If the linker is good enough, we can let it use its default linker script.
 shlib-lds =
@@ -528,7 +533,7 @@  $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
 	$(LINK.o) -shared -Wl,-O1 \
 		  -nostdlib -nostartfiles \
 		  $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \
-		  -Wl,--verbose 2>&1 | \
+		  $(shlib-LDFLAGS) -Wl,--verbose 2>&1 | \
 	  sed > $@T \
 	      -e '/^=========/,/^=========/!d;/^=========/d' \
 	      $(if $(filter yes,$(have-hash-style)), \
@@ -562,7 +567,7 @@  shlib-lds-flags = -T $(shlib-lds)
 endif
 
 define build-shlib
-$(build-shlib-helper) -o $@ $(shlib-lds-flags) \
+$(build-shlib-helper) -o $@ $(shlib-lds-flags) $(shlib-LDFLAGS) \
 	  $(csu-objpfx)abi-note.o $(build-shlib-objlist)
 endef
 
@@ -570,7 +575,7 @@  define build-module-helper
 $(LINK.o) -shared $(static-libgcc) $(sysdep-LDFLAGS) $(rtld-LDFLAGS) \
 	  $(if $($(@F)-no-z-defs)$(no-z-defs),,-Wl,-z,defs) \
 	  -B$(csu-objpfx) $(load-map-file) \
-	  $(LDFLAGS.so) $(LDFLAGS-$(@F:%.so=%).so) \
+	  $(LDFLAGS.so) $(LDFLAGS-$(@F:%.so=%).so) $(shlib-LDFLAGS) \
 	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
 endef
 
@@ -618,7 +623,7 @@  endif
 # from being allocated in libc.so, which introduces evil dependencies
 # between libc.so and ld.so, which can make it impossible to upgrade.
 $(common-objpfx)libc_pic.os: $(common-objpfx)libc_pic.a
-	$(LINK.o) -nostdlib -nostartfiles -r -o $@ \
+	$(LINK.o) -nostdlib -nostartfiles -r -o $@  $(shlib-LDFLAGS) \
 	$(LDFLAGS-c_pic.os) -Wl,-d $(whole-archive) $^ -o $@
 
 ifeq (,$(strip $(shlib-lds-flags)))
diff --git a/config.make.in b/config.make.in
index ad4dd30..c2c05e3 100644
--- a/config.make.in
+++ b/config.make.in
@@ -94,6 +94,7 @@  use-nscd = @use_nscd@
 build-hardcoded-path-in-tests= @hardcoded_path_in_tests@
 build-pt-chown = @build_pt_chown@
 enable-lock-elision = @enable_lock_elision@
+use-bfd = @libc_cv_cc_use_bfd@
 
 # Build tools.
 CC = @CC@
diff --git a/configure b/configure
index 71cc6bb..1a3962e 100755
--- a/configure
+++ b/configure
@@ -648,6 +648,8 @@  SED
 MAKEINFO
 MSGFMT
 MAKE
+libc_cv_cc_use_bfd
+LD_BFD
 LD
 AS
 OBJCOPY
@@ -773,6 +775,7 @@  enable_multi_arch
 enable_nss_crypt
 enable_obsolete_rpc
 enable_systemtap
+enable_gold
 enable_build_nscd
 enable_nscd
 enable_pt_chown
@@ -1437,6 +1440,7 @@  Optional Features:
   --enable-obsolete-rpc   build and install the obsolete RPC code for
                           link-time usage
   --enable-systemtap      enable systemtap static probe points [default=no]
+  --enable-gold           use gold to build glibc [default=no]
   --disable-build-nscd    disable building and installing the nscd daemon
   --disable-nscd          library functions will not contact the nscd daemon
   --enable-pt_chown       Enable building and installing pt_chown
@@ -3801,6 +3805,14 @@  See \`config.log' for more details" "$LINENO" 5; }
   fi
 fi
 
+# Check whether --enable-gold was given.
+if test "${enable_gold+set}" = set; then :
+  enableval=$enable_gold; enable_gold=$enableval
+else
+  enable_gold=no
+fi
+
+
 # Check whether --enable-build-nscd was given.
 if test "${enable_build_nscd+set}" = set; then :
   enableval=$enable_build_nscd; build_nscd=$enableval
@@ -4647,7 +4659,16 @@  if test $ac_verc_fail = yes; then
   AS=: critic_missing="$critic_missing as"
 fi
 
-for ac_prog in $LD
+
+# Accept gold 1.11 or higher
+if test -n "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
+  case $LD in
+  *ld.gold) LD_BFD="`echo $LD | sed -e 's/.gold$/.bfd/'`";;
+  *ld) LD_BFD=${LD}.bfd;;
+  *) as_fn_error $? "unsupported gold linker: $LD" "$LINENO" 5;;
+  esac
+  ld_is_gold=yes
+  for ac_prog in $LD
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
@@ -4695,7 +4716,111 @@  else
   # Found it, now check the version.
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD" >&5
 $as_echo_n "checking version of $LD... " >&6; }
-  ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+  ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*GNU gold.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    1.1[1-9]*|1.[2-9][0-9]*|1.1[0-9][0-9]*|[2-9].*|[1-9][0-9]*)
+       ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+    *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_prog_version" >&5
+$as_echo "$ac_prog_version" >&6; }
+fi
+if test $ac_verc_fail = yes; then
+  LD=:
+fi
+
+else
+  ld_is_gold=no
+  LD_BFD=$LD
+fi
+LDBFDFLAGS=
+# The gold linker has no builtin default linker script and it can't be
+# to create shared libraries.  Unless --enable-gold is used, it should
+# only be used to create executables.  Use -fuse-ld=bfd to create shared
+# libraries if it works.
+if test $ld_is_gold = no || test $enable_gold = no; then
+  if test $ld_is_gold = yes; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC accepts -fuse-ld=bfd" >&5
+$as_echo_n "checking if $CC accepts -fuse-ld=bfd... " >&6; }
+if ${libc_cv_cc_use_bfd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  		   cat > conftest.c <<EOF
+int main (void) { return 0; }
+EOF
+    if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fuse-ld=bfd -nostdlib -nostartfiles -o conftest conftest.c'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+      libc_cv_cc_use_bfd=yes
+      LDBFDFLAGS="-fuse-ld=bfd"
+    else
+      libc_cv_cc_use_bfd=no
+    fi
+    rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_use_bfd" >&5
+$as_echo "$libc_cv_cc_use_bfd" >&6; }
+    if test "x$libc_cv_cc_use_bfd" != xyes; then
+      as_fn_error $? "${CC-cc} does not support -fuse-ld=bfd" "$LINENO" 5
+    fi
+  else
+    libc_cv_cc_use_bfd=no
+  fi
+  for ac_prog in $LD_BFD
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LD_BFD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LD_BFD"; then
+  ac_cv_prog_LD_BFD="$LD_BFD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LD_BFD="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LD_BFD=$ac_cv_prog_LD_BFD
+if test -n "$LD_BFD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD_BFD" >&5
+$as_echo "$LD_BFD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$LD_BFD" && break
+done
+
+if test -z "$LD_BFD"; then
+  ac_verc_fail=yes
+else
+  # Found it, now check the version.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD_BFD" >&5
+$as_echo_n "checking version of $LD_BFD... " >&6; }
+  ac_prog_version=`$LD_BFD --version 2>&1 | sed -n 's/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
   case $ac_prog_version in
     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
     2.1[0-9][0-9]*|2.2[2-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*)
@@ -4707,7 +4832,14 @@  $as_echo_n "checking version of $LD... " >&6; }
 $as_echo "$ac_prog_version" >&6; }
 fi
 if test $ac_verc_fail = yes; then
-  LD=: critic_missing="$critic_missing ld"
+  LD=:
+fi
+
+else
+  libc_cv_cc_use_bfd=no
+fi
+if test "$LD" = ":"; then
+  critic_missing="$critic_missing ld"
 fi
 
 
@@ -6241,7 +6373,7 @@  else
 	  .string "GNU"
 	  .string "bar"
 EOF
-  if { ac_try='  ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&5'
+  if { ac_try='  ${CC-cc} $ASFLAGS $LDBFDFLAGS -shared -o conftest.so conftest.s 1>&5'
   { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
   (eval $ac_try) 2>&5
   ac_status=$?
diff --git a/configure.ac b/configure.ac
index 678c739..b473993 100644
--- a/configure.ac
+++ b/configure.ac
@@ -345,6 +345,12 @@  void foo (int i, void *p)
   fi
 fi
 
+AC_ARG_ENABLE(gold,
+              [AS_HELP_STRING([--enable-gold],
+	       [use gold to build glibc @<:@default=no@:>@])],
+              [enable_gold=$enableval],
+	      [enable_gold=no])
+
 AC_ARG_ENABLE([build-nscd],
 	      [AS_HELP_STRING([--disable-build-nscd],
 	       [disable building and installing the nscd daemon])],
@@ -933,10 +939,60 @@  AC_CHECK_PROG_VER(AS, $AS, --version,
 		  [GNU assembler.* \([0-9]*\.[0-9.]*\)],
 		  [2.1[0-9][0-9]*|2.2[2-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*],
 		  AS=: critic_missing="$critic_missing as")
-AC_CHECK_PROG_VER(LD, $LD, --version,
-		  [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
-		  [2.1[0-9][0-9]*|2.2[2-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*],
-		  LD=: critic_missing="$critic_missing ld")
+
+# Accept gold 1.11 or higher
+if test -n "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
+  case $LD in
+  *ld.gold) LD_BFD="`echo $LD | sed -e 's/.gold$/.bfd/'`";;
+  *ld) LD_BFD=${LD}.bfd;;
+  *) AC_MSG_ERROR([unsupported gold linker: $LD]);;
+  esac
+  ld_is_gold=yes
+  AC_CHECK_PROG_VER(LD, $LD, --version,
+		    [GNU gold.* \([0-9][0-9]*\.[0-9.]*\)],
+		    [1.1[1-9]*|1.[2-9][0-9]*|1.1[0-9][0-9]*|[2-9].*|[1-9][0-9]*],
+		    LD=:)
+else
+  ld_is_gold=no
+  LD_BFD=$LD
+fi
+LDBFDFLAGS=
+# The gold linker has no builtin default linker script and it can't be
+# to create shared libraries.  Unless --enable-gold is used, it should
+# only be used to create executables.  Use -fuse-ld=bfd to create shared
+# libraries if it works.
+if test $ld_is_gold = no || test $enable_gold = no; then
+  if test $ld_is_gold = yes; then
+    AC_CACHE_CHECK(if $CC accepts -fuse-ld=bfd,
+		   libc_cv_cc_use_bfd, [dnl
+		   cat > conftest.c <<EOF
+int main (void) { return 0; }
+EOF
+    if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -fuse-ld=bfd -nostdlib -nostartfiles -o conftest conftest.c])
+    then
+      libc_cv_cc_use_bfd=yes
+      LDBFDFLAGS="-fuse-ld=bfd"
+    else
+      libc_cv_cc_use_bfd=no
+    fi
+    rm -f conftest*])
+    if test "x$libc_cv_cc_use_bfd" != xyes; then
+      AC_MSG_ERROR([${CC-cc} does not support -fuse-ld=bfd])
+    fi
+  else
+    libc_cv_cc_use_bfd=no
+  fi
+  AC_CHECK_PROG_VER(LD_BFD, $LD_BFD, --version,
+		    [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
+		    [2.1[0-9][0-9]*|2.2[2-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*],
+		    LD=:)
+else
+  libc_cv_cc_use_bfd=no
+fi
+if test "$LD" = ":"; then
+  critic_missing="$critic_missing ld"
+fi
+AC_SUBST(libc_cv_cc_use_bfd)
 
 # These programs are version sensitive.
 AC_CHECK_TOOL_PREFIX
@@ -1472,7 +1528,7 @@  if test "$use_default_link" = default; then
 	  .string "bar"
 EOF
   if AC_TRY_COMMAND([dnl
-  ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&AS_MESSAGE_LOG_FD]) &&
+  ${CC-cc} $ASFLAGS $LDBFDFLAGS -shared -o conftest.so conftest.s 1>&AS_MESSAGE_LOG_FD]) &&
        ac_try=`$READELF -S conftest.so | sed -n \
 	 ['${x;p;}
 	  s/^ *\[ *[1-9][0-9]*\]  *\([^ ][^ ]*\)  *\([^ ][^ ]*\) .*$/\2 \1/