This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH roland/ehdr_start] Use __ehdr_start, when available, for rtld to get its own headers.


My motivation for this change is my NaCl port, where the old code's
assumption about ELF file layout does not hold.  But in fact this is
not only cleaner but results in marginally better code.  (To compensate
I've added a couple of asserts. ;-)

Tested on x86_64-linux-gnu:
* with binutils-2.22 that the configure check fails and nothing changes
* with binutils trunk (2.23 or 2.24 would do as well) that the configure
  check passes and the new code works (no 'make check' regressions)

I'll commit this in a few days absent objections.


Thanks,
Roland


	* configure.ac (HAVE_EHDR_START): New check.
	* configure: Regenerated.
	* config.h.in (HAVE_EHDR_START): New #undef.
	* elf/rtld.c (dl_main) [HAVE_EHDR_START]: Use __ehdr_start rather than
	assuming the lowest-addressed segment maps the start of the file.

--- a/config.h.in
+++ b/config.h.in
@@ -195,6 +195,9 @@
 /* Define if linux/fanotify.h is available.  */
 #undef HAVE_LINUX_FANOTIFY_H
 
+/* Define if the linker defines __ehdr_start.  */
+#undef HAVE_EHDR_START
+
 /*
  */
 
--- a/configure
+++ b/configure
@@ -7268,6 +7268,44 @@ if test $libc_cv_predef_stack_protector = yes; then
 fi
 
 
+{ $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; }
+if ${libc_cv_ehdr_start+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+old_CFLAGS="$CFLAGS"
+old_LDFLAGS="$LDFLAGS"
+old_LIBS="$LIBS"
+CFLAGS="$CFLAGS -fPIC"
+LDFLAGS="$LDFLAGS -nostdlib -nostartfiles -shared"
+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; }
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  libc_cv_ehdr_start=yes
+else
+  libc_cv_ehdr_start=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+CFLAGS="$old_CFLAGS"
+LDFLAGS="$old_LDFLAGS"
+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
+  $as_echo "#define HAVE_EHDR_START 1" >>confdefs.h
+
+fi
+
 ### End of automated tests.
 ### Now run sysdeps configure fragments.
 
--- a/configure.ac
+++ b/configure.ac
@@ -2069,6 +2069,27 @@ if test $libc_cv_predef_stack_protector = yes; then
 fi
 AC_SUBST(libc_extra_cflags)
 
+AC_CACHE_CHECK([whether the linker provides __ehdr_start],
+	       libc_cv_ehdr_start, [
+old_CFLAGS="$CFLAGS"
+old_LDFLAGS="$LDFLAGS"
+old_LIBS="$LIBS"
+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; }
+])],
+	       [libc_cv_ehdr_start=yes], [libc_cv_ehdr_start=no])
+CFLAGS="$old_CFLAGS"
+LDFLAGS="$old_LDFLAGS"
+LIBS="$old_LIBS"
+])
+if test $libc_cv_ehdr_start = yes; then
+  AC_DEFINE([HAVE_EHDR_START])
+fi
+
 ### End of automated tests.
 ### Now run sysdeps configure fragments.
 
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1370,10 +1370,25 @@ of this helper program; chances are you did not intend to run this program.\n\
     GLRO(dl_use_load_bias) = main_map->l_addr == 0 ? -1 : 0;
 
   /* Set up the program header information for the dynamic linker
-     itself.  It is needed in the dl_iterate_phdr() callbacks.  */
-  ElfW(Ehdr) *rtld_ehdr = (ElfW(Ehdr) *) GL(dl_rtld_map).l_map_start;
-  ElfW(Phdr) *rtld_phdr = (ElfW(Phdr) *) (GL(dl_rtld_map).l_map_start
-					  + rtld_ehdr->e_phoff);
+     itself.  It is needed in the dl_iterate_phdr callbacks.  */
+  const ElfW(Ehdr) *rtld_ehdr;
+
+  /* Starting from binutils-2.23, the linker will define the magic symbol
+     __ehdr_start to point to our own ELF header if it is visible in a
+     segment that also includes the phdrs.  If that's not available, we use
+     the old method that assumes the beginning of the file is part of the
+     lowest-addressed PT_LOAD segment.  */
+#ifdef HAVE_EHDR_START
+  extern const ElfW(Ehdr) __ehdr_start __attribute__ ((visibility ("hidden")));
+  rtld_ehdr = &__ehdr_start;
+#else
+  rtld_ehdr = (void *) GL(dl_rtld_map).l_map_start;
+#endif
+  assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
+  assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
+
+  const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
+
   GL(dl_rtld_map).l_phdr = rtld_phdr;
   GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]