about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoland McGrath <roland@hack.frob.com>2013-03-28 16:15:48 -0700
committerRoland McGrath <roland@hack.frob.com>2013-03-28 16:15:48 -0700
commit288f7d79fe2dcc8e62c539f57b25d7662a2cd5ff (patch)
tree01fbd48750047a5246b6bcc6d6551eb18bbdd4e3
parentdc0a02638583d8e7f7e1cc72643d1b26ec6042fd (diff)
downloadglibc-288f7d79fe2dcc8e62c539f57b25d7662a2cd5ff.tar.gz
glibc-288f7d79fe2dcc8e62c539f57b25d7662a2cd5ff.tar.xz
glibc-288f7d79fe2dcc8e62c539f57b25d7662a2cd5ff.zip
Use __ehdr_start, if available, as fallback for AT_PHDR.
-rw-r--r--ChangeLog6
-rw-r--r--csu/libc-start.c18
-rw-r--r--sysdeps/mach/hurd/i386/init-first.c22
3 files changed, 38 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index de20ebb1c9..876b577839 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2013-03-28  Roland McGrath  <roland@hack.frob.com>
 
+	* csu/libc-start.c (__libc_start_main) [!SHARED]: If _dl_aux_init
+	didn't do it already, then set _dl_phdr and _dl_phnum based on the
+	magic __ehdr_start linker symbol if it's defined.
+	* sysdeps/mach/hurd/i386/init-first.c (init1) [!SHARED]: Don't set
+	them up here if it was already done.
+
 	* elf/dl-support.c (_dl_phdr): Make pointer to const.
 	(_dl_aux_init): Use const in cast when setting it.
 	* sysdeps/mach/hurd/i386/init-first.c (init1): Remove superfluous cast.
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 9c4c01d9fd..fa9085cf55 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -15,6 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -151,7 +152,24 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
   }
 #  endif
   _dl_aux_init (auxvec);
+  if (GL(dl_phdr) == NULL)
 # endif
+    {
+      /* 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.
+         So we can set up _dl_phdr and _dl_phnum even without any
+         information from auxv.  */
+
+      extern const ElfW(Ehdr) __ehdr_start __attribute__ ((weak));
+      if (&__ehdr_start != NULL)
+        {
+          assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr));
+          GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff;
+          GL(dl_phnum) = __ehdr_start.e_phnum;
+        }
+    }
+
 # ifdef DL_SYSDEP_OSCHECK
   if (!__libc_multiple_libcs)
     {
diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c
index 59253db539..fc3330c1fc 100644
--- a/sysdeps/mach/hurd/i386/init-first.c
+++ b/sysdeps/mach/hurd/i386/init-first.c
@@ -117,14 +117,20 @@ init1 (int argc, char *arg0, ...)
   if ((void *) d == argv[0])
     {
 #ifndef SHARED
-      /* We may need to see our own phdrs, e.g. for TLS setup.
-	 Try the usual kludge to find the headers without help from
-	 the exec server.  */
-      extern const void _start;
-      const ElfW(Ehdr) *const ehdr = &_start;
-      _dl_phdr = (const void *) ehdr + ehdr->e_phoff;
-      _dl_phnum = ehdr->e_phnum;
-      assert (ehdr->e_phentsize == sizeof (ElfW(Phdr)));
+      /* With a new enough linker (binutils-2.23 or better),
+         the magic __ehdr_start symbol will be available and
+         __libc_start_main will have done this that way already.  */
+      if (_dl_phdr == NULL)
+        {
+          /* We may need to see our own phdrs, e.g. for TLS setup.
+             Try the usual kludge to find the headers without help from
+             the exec server.  */
+          extern const void _start;
+          const ElfW(Ehdr) *const ehdr = &_start;
+          _dl_phdr = (const void *) ehdr + ehdr->e_phoff;
+          _dl_phnum = ehdr->e_phnum;
+          assert (ehdr->e_phentsize == sizeof (ElfW(Phdr)));
+        }
 #endif
       return;
     }