diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | config.h.in | 3 | ||||
-rwxr-xr-x | configure | 38 | ||||
-rw-r--r-- | configure.ac | 21 | ||||
-rw-r--r-- | elf/rtld.c | 23 |
5 files changed, 89 insertions, 4 deletions
@@ -1,3 +1,11 @@ +2014-03-13 Roland McGrath <roland@hack.frob.com> + + * 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. + 2014-03-13 Joseph Myers <joseph@codesourcery.com> * INSTALL: Regenerated. diff --git a/config.h.in b/config.h.in index 40797e7fdc..ed3c5933eb 100644 --- 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 + /* */ @@ -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. diff --git a/configure.ac b/configure.ac index f3dd87d912..59dbb5e1b2 100644 --- 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. diff --git a/elf/rtld.c b/elf/rtld.c index 63e92d3006..9d121dc8f5 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1371,10 +1371,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; |