detect broken linker handling of __ehdr_start
diff mbox

Message ID 1407383243-30362-1-git-send-email-vapier@gentoo.org
State Accepted, archived
Headers show

Commit Message

Mike Frysinger Aug. 7, 2014, 3:47 a.m. UTC
Older versions of ld on ia64 support __ehdr_start, but generate relocs
when they shouldn't.  This causes the ld.so to not run because it tries
to resolve the __ehdr_start symbol (but it's not exported).

2014-08-06  Mike Frysinger  <vapier@gentoo.org>

	* configure.ac: Change __ehdr_start code to dereference the struct.
	Run readelf on the output to look for relocations.
	* configure: Regenerated.
---
Tested ia64 binutils 2.23.2 & 2.24, and x86_64 binutils 2.23.2 & 2.24.

 configure    | 26 ++++++++++++++++++++------
 configure.ac | 23 ++++++++++++++++++-----
 2 files changed, 38 insertions(+), 11 deletions(-)

Comments

Roland McGrath Aug. 12, 2014, 4:59 p.m. UTC | #1
That looks fine to me and proper for the freeze.  Allan should OK it.
Allan McRae Aug. 12, 2014, 11:31 p.m. UTC | #2
On 13/08/14 02:59, Roland McGrath wrote:
> That looks fine to me and proper for the freeze.  Allan should OK it.
> 

OK to commit,
Allan
Mike Frysinger Aug. 12, 2014, 11:54 p.m. UTC | #3
On Wed 13 Aug 2014 09:31:23 Allan McRae wrote:
> On 13/08/14 02:59, Roland McGrath wrote:
> > That looks fine to me and proper for the freeze.  Allan should OK it.
> 
> OK to commit,

thanks, pushed now
-mike

Patch
diff mbox

diff --git a/configure b/configure
index 646e0bc..86ba307 100755
--- a/configure
+++ b/configure
@@ -6965,8 +6965,11 @@  if test $libc_cv_predef_stack_protector = yes; then
 fi
 libc_extra_cppflags=
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker provides __ehdr_start" >&5
-$as_echo_n "checking whether the linker provides __ehdr_start... " >&6; }
+# Some linkers on some architectures support __ehdr_start but with
+# bugs.  Make sure usage of it does not create relocations in the
+# output (as the linker should resolve them all for us).
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker provides working __ehdr_start" >&5
+$as_echo_n "checking whether the linker provides working __ehdr_start... " >&6; }
 if ${libc_cv_ehdr_start+:} false; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6980,12 +6983,20 @@  LIBS=
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
-extern const char __ehdr_start __attribute__ ((visibility ("hidden")));
-const char *ehdr (void) { return &__ehdr_start; }
+typedef struct {
+  char foo;
+  long val;
+} Ehdr;
+extern const Ehdr __ehdr_start __attribute__ ((visibility ("hidden")));
+long ehdr (void) { return __ehdr_start.val; }
 
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  libc_cv_ehdr_start=yes
+  if $READELF -r conftest | fgrep __ehdr_start >/dev/null; then
+		  libc_cv_ehdr_start=broken
+		else
+		  libc_cv_ehdr_start=yes
+		fi
 else
   libc_cv_ehdr_start=no
 fi
@@ -6998,9 +7009,12 @@  LIBS="$old_LIBS"
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ehdr_start" >&5
 $as_echo "$libc_cv_ehdr_start" >&6; }
-if test $libc_cv_ehdr_start = yes; then
+if test "$libc_cv_ehdr_start" = yes; then
   $as_echo "#define HAVE_EHDR_START 1" >>confdefs.h
 
+elif test "$libc_cv_ehdr_start" = broken; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: linker is broken -- you should upgrade" >&5
+$as_echo "$as_me: WARNING: linker is broken -- you should upgrade" >&2;}
 fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_trap with no external dependencies" >&5
diff --git a/configure.ac b/configure.ac
index e89faa0..2553399 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1880,7 +1880,10 @@  if test $libc_cv_predef_stack_protector = yes; then
 fi
 libc_extra_cppflags=
 
-AC_CACHE_CHECK([whether the linker provides __ehdr_start],
+# Some linkers on some architectures support __ehdr_start but with
+# bugs.  Make sure usage of it does not create relocations in the
+# output (as the linker should resolve them all for us).
+AC_CACHE_CHECK([whether the linker provides working __ehdr_start],
 	       libc_cv_ehdr_start, [
 old_CFLAGS="$CFLAGS"
 old_LDFLAGS="$LDFLAGS"
@@ -1889,16 +1892,26 @@  CFLAGS="$CFLAGS -fPIC"
 LDFLAGS="$LDFLAGS -nostdlib -nostartfiles -shared"
 LIBS=
 AC_LINK_IFELSE([AC_LANG_SOURCE([
-extern const char __ehdr_start __attribute__ ((visibility ("hidden")));
-const char *ehdr (void) { return &__ehdr_start; }
+typedef struct {
+  char foo;
+  long val;
+} Ehdr;
+extern const Ehdr __ehdr_start __attribute__ ((visibility ("hidden")));
+long ehdr (void) { return __ehdr_start.val; }
 ])],
-	       [libc_cv_ehdr_start=yes], [libc_cv_ehdr_start=no])
+	       [if $READELF -r conftest | fgrep __ehdr_start >/dev/null; then
+		  libc_cv_ehdr_start=broken
+		else
+		  libc_cv_ehdr_start=yes
+		fi], [libc_cv_ehdr_start=no])
 CFLAGS="$old_CFLAGS"
 LDFLAGS="$old_LDFLAGS"
 LIBS="$old_LIBS"
 ])
-if test $libc_cv_ehdr_start = yes; then
+if test "$libc_cv_ehdr_start" = yes; then
   AC_DEFINE([HAVE_EHDR_START])
+elif test "$libc_cv_ehdr_start" = broken; then
+  AC_MSG_WARN([linker is broken -- you should upgrade])
 fi
 
 AC_CACHE_CHECK(for __builtin_trap with no external dependencies,