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

Message ID 20140311222933.CC24274474@topped-with-meat.com
State Committed
Headers

Commit Message

Roland McGrath March 11, 2014, 10:29 p.m. UTC
  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.
  

Comments

Patchwork Bot March 17, 2014, 4:50 p.m. UTC | #1
On 12 March 2014 03:59, Roland McGrath <roland@hack.frob.com> wrote:
> 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.

This causes a failure in check-abi-ld.  It looks like the additional
symbol entry:

0000000000000000 g    D  .note.gnu.build-id     0000000000000000  Base
       .hidden __ehdr_start

needs to either be accounted for in the abilist files or ignored in
the abilist script.

Siddhesh
  
Roland McGrath March 17, 2014, 8:07 p.m. UTC | #2
> This causes a failure in check-abi-ld.

I have no problems on x86_64-linux-gnu with trunk binutils.

> It looks like the additional symbol entry:
> 
> 0000000000000000 g    D  .note.gnu.build-id     0000000000000000  Base
>        .hidden __ehdr_start
> 
> needs to either be accounted for in the abilist files or ignored in
> the abilist script.

That looks like a binutils bug.  __ehdr_start should never make it to
.dynsym.  Give details about your libc configuration and your binutils
version.


Thanks,
Roland
  
Mike Frysinger March 19, 2014, 4:24 a.m. UTC | #3
On Tue 11 Mar 2014 15:29:33 Roland McGrath wrote:
> 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.

this breaks on ia64 w/binutils-2.23.2.  using gcc-4.7.3 in case it matters.

$ ../configure --prefix=/usr
$ make -j4
$ echo 'main(){puts("HI");}' | gcc -x c - -o a.out
$ ./elf/ld.so --library-path $PWD ./a.out 
./a.out: symbol lookup error: ./elf/ld.so: undefined symbol: __ehdr_start
-mike
  
Roland McGrath March 24, 2014, 10:30 p.m. UTC | #4
> this breaks on ia64 w/binutils-2.23.2.  using gcc-4.7.3 in case it matters.

Sorry about that.  But I think you're going to have to do most of the
legwork on investigating what's going wrong here, as I do not have any ia64
worlds to test on.

It seems fairly certain that this must be binutils (ld) bugs.  Since ld.so
is linked with -z defs, it should not have gotten out alive with an
undefined symbol.  What does its .dynsym from readelf -W -s look like?

Does adding -Wl,-z,defs to LDFLAGS in the configure check make it fail?
(I'm guessing not, since the link of ld.so didn't fail.)

Probably we can find a way to detect the bug with readelf -r.
Send me your binary and or readelf -WSsr output so I can fiddle.


Thanks,
Roland
  
Mike Frysinger Aug. 6, 2014, 4:35 a.m. UTC | #5
On Mon 24 Mar 2014 15:30:33 Roland McGrath wrote:
> > this breaks on ia64 w/binutils-2.23.2.  using gcc-4.7.3 in case it
> > matters.
> 
> Sorry about that.  But I think you're going to have to do most of the
> legwork on investigating what's going wrong here, as I do not have any ia64
> worlds to test on.
> 
> It seems fairly certain that this must be binutils (ld) bugs.  Since ld.so
> is linked with -z defs, it should not have gotten out alive with an
> undefined symbol.  What does its .dynsym from readelf -W -s look like?
> 
> Does adding -Wl,-z,defs to LDFLAGS in the configure check make it fail?
> (I'm guessing not, since the link of ld.so didn't fail.)
> 
> Probably we can find a way to detect the bug with readelf -r.
> Send me your binary and or readelf -WSsr output so I can fiddle.

hmm, so the symbol is actually defined in ld.so:
$ readelf -sW elf/ld.so | grep ehdr
    32: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN     1 __ehdr_start
   493: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN     1 __ehdr_start

but i guess the fact it's marked HIDDEN is the problem ?

$ LD_DEBUG=all ./elf/ld.so --library-path $PWD ./a.out
     30300:	file=./a.out [0];  generating link map
     30300:	  dynamic: 0x6000000000000be8  base: 0x0000000000000000   size: 0x2000000000000e90
     30300:	    entry: 0x4000000000000480  phdr: 0x4000000000000040  phnum:                  9
     30300:	
     30300:	
     30300:	file=libc.so.6.1 [0];  needed by ./a.out [0]
     30300:	find library=libc.so.6.1 [0]; searching
     30300:	 search path=/home/vapier/glibc/build/tls:/home/vapier/glibc/build		(LD_LIBRARY_PATH)
     30300:	  trying file=/home/vapier/glibc/build/tls/libc.so.6.1
     30300:	  trying file=/home/vapier/glibc/build/libc.so.6.1
     30300:	
     30300:	file=libc.so.6.1 [0];  generating link map
     30300:	  dynamic: 0x2000000000294550  base: 0x2000000000000000   size: 0x000000000029a430
     30300:	    entry: 0x2000000000029b40  phdr: 0x2000000000000040  phnum:                 10
     30300:	
     30300:	checking for version `GLIBC_2.2' in file /home/vapier/glibc/build/libc.so.6.1 [0] required by file ./a.out [0]
     30300:	checking for version `GLIBC_2.3' in file ./elf/ld.so [0] required by file /home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	checking for version `GLIBC_PRIVATE' in file ./elf/ld.so [0] required by file /home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	
     30300:	Initial object scopes
     30300:	object=./a.out [0]
     30300:	 scope 0: ./a.out /home/vapier/glibc/build/libc.so.6.1 ./elf/ld.so
     30300:	
     30300:	object=linux-gate.so.1 [0]
     30300:	 scope 0: ./a.out /home/vapier/glibc/build/libc.so.6.1 ./elf/ld.so
     30300:	 scope 1: linux-gate.so.1
     30300:	
     30300:	object=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	 scope 0: ./a.out /home/vapier/glibc/build/libc.so.6.1 ./elf/ld.so
     30300:	
     30300:	object=./elf/ld.so [0]
     30300:	 no scope
     30300:	
     30300:	
     30300:	relocation processing: /home/vapier/glibc/build/libc.so.6.1 (lazy)
     30300:	symbol=_res;  lookup in file=./a.out [0]
     30300:	symbol=_res;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_res' [GLIBC_2.2]
     30300:	symbol=_IO_2_1_stdout_;  lookup in file=./a.out [0]
     30300:	symbol=_IO_2_1_stdout_;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_IO_2_1_stdout_' [GLIBC_2.2]
     30300:	symbol=_IO_2_1_stdin_;  lookup in file=./a.out [0]
     30300:	symbol=_IO_2_1_stdin_;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_IO_2_1_stdin_' [GLIBC_2.2]
     30300:	symbol=stderr;  lookup in file=./a.out [0]
     30300:	symbol=stderr;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `stderr' [GLIBC_2.2]
     30300:	symbol=error_one_per_line;  lookup in file=./a.out [0]
     30300:	symbol=error_one_per_line;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `error_one_per_line' [GLIBC_2.2]
     30300:	symbol=__malloc_initialize_hook;  lookup in file=./a.out [0]
     30300:	symbol=__malloc_initialize_hook;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__malloc_initialize_hook' [GLIBC_2.2]
     30300:	symbol=__morecore;  lookup in file=./a.out [0]
     30300:	symbol=__morecore;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__morecore' [GLIBC_2.2]
     30300:	symbol=__ctype_toupper;  lookup in file=./a.out [0]
     30300:	symbol=__ctype_toupper;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__ctype_toupper' [GLIBC_2.2]
     30300:	symbol=__key_encryptsession_pk_LOCAL;  lookup in file=./a.out [0]
     30300:	symbol=__key_encryptsession_pk_LOCAL;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__key_encryptsession_pk_LOCAL' [GLIBC_2.2]
     30300:	symbol=__progname_full;  lookup in file=./a.out [0]
     30300:	symbol=__progname_full;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__progname_full' [GLIBC_2.2]
     30300:	symbol=_environ;  lookup in file=./a.out [0]
     30300:	symbol=_environ;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_environ' [GLIBC_2.2]
     30300:	symbol=__ctype32_toupper;  lookup in file=./a.out [0]
     30300:	symbol=__ctype32_toupper;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__ctype32_toupper' [GLIBC_2.2]
     30300:	symbol=_rtld_global;  lookup in file=./a.out [0]
     30300:	symbol=_rtld_global;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=_rtld_global;  lookup in file=./elf/ld.so [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to ./elf/ld.so [0]: normal symbol `_rtld_global' [GLIBC_PRIVATE]
     30300:	symbol=__progname;  lookup in file=./a.out [0]
     30300:	symbol=__progname;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__progname' [GLIBC_2.2]
     30300:	symbol=argp_err_exit_status;  lookup in file=./a.out [0]
     30300:	symbol=argp_err_exit_status;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `argp_err_exit_status' [GLIBC_2.2]
     30300:	symbol=mallwatch;  lookup in file=./a.out [0]
     30300:	symbol=mallwatch;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `mallwatch' [GLIBC_2.2]
     30300:	symbol=__rcmd_errstr;  lookup in file=./a.out [0]
     30300:	symbol=__rcmd_errstr;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__rcmd_errstr' [GLIBC_2.2]
     30300:	symbol=svcauthdes_stats;  lookup in file=./a.out [0]
     30300:	symbol=svcauthdes_stats;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `svcauthdes_stats' [GLIBC_2.2]
     30300:	symbol=__libc_enable_secure;  lookup in file=./a.out [0]
     30300:	symbol=__libc_enable_secure;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=__libc_enable_secure;  lookup in file=./elf/ld.so [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to ./elf/ld.so [0]: normal symbol `__libc_enable_secure' [GLIBC_PRIVATE]
     30300:	symbol=_res_hconf;  lookup in file=./a.out [0]
     30300:	symbol=_res_hconf;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_res_hconf' [GLIBC_2.2]
     30300:	symbol=malloc;  lookup in file=./a.out [0]
     30300:	symbol=malloc;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `malloc' [GLIBC_2.2]
     30300:	symbol=getdate_err;  lookup in file=./a.out [0]
     30300:	symbol=getdate_err;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `getdate_err' [GLIBC_2.2]
     30300:	symbol=__tzname;  lookup in file=./a.out [0]
     30300:	symbol=__tzname;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__tzname' [GLIBC_2.2]
     30300:	symbol=__timezone;  lookup in file=./a.out [0]
     30300:	symbol=__timezone;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__timezone' [GLIBC_2.2]
     30300:	symbol=_rtld_global_ro;  lookup in file=./a.out [0]
     30300:	symbol=_rtld_global_ro;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=_rtld_global_ro;  lookup in file=./elf/ld.so [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to ./elf/ld.so [0]: normal symbol `_rtld_global_ro' [GLIBC_PRIVATE]
     30300:	symbol=optarg;  lookup in file=./a.out [0]
     30300:	symbol=optarg;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `optarg' [GLIBC_2.2]
     30300:	symbol=svc_max_pollfd;  lookup in file=./a.out [0]
     30300:	symbol=svc_max_pollfd;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `svc_max_pollfd' [GLIBC_2.2]
     30300:	symbol=argp_program_version_hook;  lookup in file=./a.out [0]
     30300:	symbol=argp_program_version_hook;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `argp_program_version_hook' [GLIBC_2.2]
     30300:	symbol=__ctype_tolower;  lookup in file=./a.out [0]
     30300:	symbol=__ctype_tolower;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__ctype_tolower' [GLIBC_2.2]
     30300:	symbol=__after_morecore_hook;  lookup in file=./a.out [0]
     30300:	symbol=__after_morecore_hook;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__after_morecore_hook' [GLIBC_2.2]
     30300:	symbol=__environ;  lookup in file=./a.out [0]
     30300:	symbol=__environ;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__environ' [GLIBC_2.2]
     30300:	symbol=__curbrk;  lookup in file=./a.out [0]
     30300:	symbol=__curbrk;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__curbrk' [GLIBC_2.2]
     30300:	symbol=argp_program_version;  lookup in file=./a.out [0]
     30300:	symbol=argp_program_version;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `argp_program_version' [GLIBC_2.2]
     30300:	symbol=__daylight;  lookup in file=./a.out [0]
     30300:	symbol=__daylight;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__daylight' [GLIBC_2.2]
     30300:	symbol=__memalign_hook;  lookup in file=./a.out [0]
     30300:	symbol=__memalign_hook;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__memalign_hook' [GLIBC_2.2]
     30300:	symbol=__malloc_hook;  lookup in file=./a.out [0]
     30300:	symbol=__malloc_hook;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__malloc_hook' [GLIBC_2.2]
     30300:	symbol=__free_hook;  lookup in file=./a.out [0]
     30300:	symbol=__free_hook;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__free_hook' [GLIBC_2.2]
     30300:	symbol=svc_pollfd;  lookup in file=./a.out [0]
     30300:	symbol=svc_pollfd;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `svc_pollfd' [GLIBC_2.2]
     30300:	symbol=_nl_domain_bindings;  lookup in file=./a.out [0]
     30300:	symbol=_nl_domain_bindings;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_nl_domain_bindings' [GLIBC_2.2]
     30300:	symbol=_nl_msg_cat_cntr;  lookup in file=./a.out [0]
     30300:	symbol=_nl_msg_cat_cntr;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_nl_msg_cat_cntr' [GLIBC_2.2]
     30300:	symbol=argp_program_bug_address;  lookup in file=./a.out [0]
     30300:	symbol=argp_program_bug_address;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `argp_program_bug_address' [GLIBC_2.2]
     30300:	symbol=__key_decryptsession_pk_LOCAL;  lookup in file=./a.out [0]
     30300:	symbol=__key_decryptsession_pk_LOCAL;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__key_decryptsession_pk_LOCAL' [GLIBC_2.2]
     30300:	symbol=h_errlist;  lookup in file=./a.out [0]
     30300:	symbol=h_errlist;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `h_errlist' [GLIBC_2.2]
     30300:	symbol=program_invocation_short_name;  lookup in file=./a.out [0]
     30300:	symbol=program_invocation_short_name;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `program_invocation_short_name' [GLIBC_2.2]
     30300:	symbol=optind;  lookup in file=./a.out [0]
     30300:	symbol=optind;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `optind' [GLIBC_2.2]
     30300:	symbol=_dl_starting_up;  lookup in file=./a.out [0]
     30300:	symbol=_dl_starting_up;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=_dl_starting_up;  lookup in file=./elf/ld.so [0]
     30300:	symbol=stdout;  lookup in file=./a.out [0]
     30300:	symbol=stdout;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `stdout' [GLIBC_2.2]
     30300:	symbol=obstack_alloc_failed_handler;  lookup in file=./a.out [0]
     30300:	symbol=obstack_alloc_failed_handler;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `obstack_alloc_failed_handler' [GLIBC_2.2]
     30300:	symbol=error_print_progname;  lookup in file=./a.out [0]
     30300:	symbol=error_print_progname;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `error_print_progname' [GLIBC_2.2]
     30300:	symbol=optopt;  lookup in file=./a.out [0]
     30300:	symbol=optopt;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `optopt' [GLIBC_2.2]
     30300:	symbol=_IO_funlockfile;  lookup in file=./a.out [0]
     30300:	symbol=_IO_funlockfile;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_IO_funlockfile' [GLIBC_2.2]
     30300:	symbol=obstack_exit_failure;  lookup in file=./a.out [0]
     30300:	symbol=obstack_exit_failure;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `obstack_exit_failure' [GLIBC_2.2]
     30300:	symbol=error_message_count;  lookup in file=./a.out [0]
     30300:	symbol=error_message_count;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `error_message_count' [GLIBC_2.2]
     30300:	symbol=__ctype32_b;  lookup in file=./a.out [0]
     30300:	symbol=__ctype32_b;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__ctype32_b' [GLIBC_2.2]
     30300:	symbol=__ctype32_tolower;  lookup in file=./a.out [0]
     30300:	symbol=__ctype32_tolower;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__ctype32_tolower' [GLIBC_2.2]
     30300:	symbol=svc_fdset;  lookup in file=./a.out [0]
     30300:	symbol=svc_fdset;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `svc_fdset' [GLIBC_2.2]
     30300:	symbol=program_invocation_name;  lookup in file=./a.out [0]
     30300:	symbol=program_invocation_name;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `program_invocation_name' [GLIBC_2.2]
     30300:	symbol=loc1;  lookup in file=./a.out [0]
     30300:	symbol=loc1;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `loc1' [GLIBC_2.2]
     30300:	symbol=free;  lookup in file=./a.out [0]
     30300:	symbol=free;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `free' [GLIBC_2.2]
     30300:	symbol=__ctype_b;  lookup in file=./a.out [0]
     30300:	symbol=__ctype_b;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__ctype_b' [GLIBC_2.2]
     30300:	symbol=loc2;  lookup in file=./a.out [0]
     30300:	symbol=loc2;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `loc2' [GLIBC_2.2]
     30300:	symbol=__fpu_control;  lookup in file=./a.out [0]
     30300:	symbol=__fpu_control;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__fpu_control' [GLIBC_2.2]
     30300:	symbol=re_syntax_options;  lookup in file=./a.out [0]
     30300:	symbol=re_syntax_options;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `re_syntax_options' [GLIBC_2.2]
     30300:	symbol=stdin;  lookup in file=./a.out [0]
     30300:	symbol=stdin;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `stdin' [GLIBC_2.2]
     30300:	symbol=__check_rhosts_file;  lookup in file=./a.out [0]
     30300:	symbol=__check_rhosts_file;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__check_rhosts_file' [GLIBC_2.2]
     30300:	symbol=opterr;  lookup in file=./a.out [0]
     30300:	symbol=opterr;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `opterr' [GLIBC_2.2]
     30300:	symbol=__realloc_hook;  lookup in file=./a.out [0]
     30300:	symbol=__realloc_hook;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `__realloc_hook' [GLIBC_2.2]
     30300:	symbol=_dl_argv;  lookup in file=./a.out [0]
     30300:	symbol=_dl_argv;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=_dl_argv;  lookup in file=./elf/ld.so [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to ./elf/ld.so [0]: normal symbol `_dl_argv' [GLIBC_PRIVATE]
     30300:	symbol=rpc_createerr;  lookup in file=./a.out [0]
     30300:	symbol=rpc_createerr;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `rpc_createerr' [GLIBC_2.2]
     30300:	symbol=_IO_2_1_stderr_;  lookup in file=./a.out [0]
     30300:	symbol=_IO_2_1_stderr_;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file /home/vapier/glibc/build/libc.so.6.1 [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `_IO_2_1_stderr_' [GLIBC_2.2]
     30300:	
     30300:	relocation processing: ./a.out (lazy)
     30300:	
     30300:	relocation processing: ./elf/ld.so
     30300:	symbol=_dl_argv;  lookup in file=./a.out [0]
     30300:	symbol=_dl_argv;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=_dl_argv;  lookup in file=./elf/ld.so [0]
     30300:	binding file ./elf/ld.so [0] to ./elf/ld.so [0]: normal symbol `_dl_argv' [GLIBC_PRIVATE]
     30300:	symbol=_r_debug;  lookup in file=./a.out [0]
     30300:	symbol=_r_debug;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=_r_debug;  lookup in file=./elf/ld.so [0]
     30300:	binding file ./elf/ld.so [0] to ./elf/ld.so [0]: normal symbol `_r_debug' [GLIBC_2.2]
     30300:	symbol=free;  lookup in file=./a.out [0]
     30300:	symbol=free;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	binding file ./elf/ld.so [0] to /home/vapier/glibc/build/libc.so.6.1 [0]: normal symbol `free' [GLIBC_2.2]
     30300:	symbol=__ehdr_start;  lookup in file=./a.out [0]
     30300:	symbol=__ehdr_start;  lookup in file=/home/vapier/glibc/build/libc.so.6.1 [0]
     30300:	symbol=__ehdr_start;  lookup in file=./elf/ld.so [0]
     30300:	./elf/ld.so: error: symbol lookup error: undefined symbol: __ehdr_start (fatal)
./a.out: symbol lookup error: ./elf/ld.so: undefined symbol: __ehdr_start
-mike
  
Mike Frysinger Aug. 6, 2014, 4:59 a.m. UTC | #6
On Wed 06 Aug 2014 00:35:25 Mike Frysinger wrote:
> On Mon 24 Mar 2014 15:30:33 Roland McGrath wrote:
> > > this breaks on ia64 w/binutils-2.23.2.  using gcc-4.7.3 in case it
> > > matters.
> > 
> > Sorry about that.  But I think you're going to have to do most of the
> > legwork on investigating what's going wrong here, as I do not have any
> > ia64
> > worlds to test on.
> > 
> > It seems fairly certain that this must be binutils (ld) bugs.  Since ld.so
> > is linked with -z defs, it should not have gotten out alive with an
> > undefined symbol.  What does its .dynsym from readelf -W -s look like?
> > 
> > Does adding -Wl,-z,defs to LDFLAGS in the configure check make it fail?
> > (I'm guessing not, since the link of ld.so didn't fail.)
> > 
> > Probably we can find a way to detect the bug with readelf -r.
> > Send me your binary and or readelf -WSsr output so I can fiddle.
> 
> hmm, so the symbol is actually defined in ld.so:
> $ readelf -sW elf/ld.so | grep ehdr
>     32: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN     1 __ehdr_start
>    493: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN     1 __ehdr_start
> 
> but i guess the fact it's marked HIDDEN is the problem ?

the source declares it as hidden though.  i was comparing it to x86_64 where 
it doesn't:
   252: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    1 __ehdr_start
then again, x86_64 doesn't add it to the exported symbol list, but ia64 does.

x86_64 also doesn't have a reloc like ia64:
00000000000505c8  0000002000000027 R_IA64_DIR64LSB        0000000000000000 
__ehdr_start + 0

so i guess linker bug for not fully resolving that reloc.  i wonder if it can 
be easily tested for (the simple code in the configure.ac didn't generate a 
reloc).  or maybe i should force this off in the ia64 configure script until 
the linker bug can be tracked down.
-mike
  
Roland McGrath Aug. 6, 2014, 9:02 p.m. UTC | #7
> hmm, so the symbol is actually defined in ld.so:
> $ readelf -sW elf/ld.so | grep ehdr
>     32: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN     1 __ehdr_start
>    493: 0000000000000000     0 NOTYPE  GLOBAL HIDDEN     1 __ehdr_start
> 
> but i guess the fact it's marked HIDDEN is the problem ?

No, it's supposed to be STV_HIDDEN.  It should not be in .dynsym at all,
though (I think the first grep hit is in .dynsym and the second in
.symtab).  Also there should be no dynamic relocs referring to the symbol;
it's presumably because there is one that it appears in .dynsym.  The
runtime resolution process is reloc-driven, not symbol-driven, so the fact
that you saw any LD_DEBUG spew mentioning the name is an indication there
was a reloc.

> the source declares it as hidden though.  i was comparing it to x86_64 where 
> it doesn't:
>    252: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    1 __ehdr_start
> then again, x86_64 doesn't add it to the exported symbol list, but ia64 does.

The visibility has changed over iterations of the linker code.  I think
current versions deliver STV_HIDDEN for all machines, but I'm not
completely sure.

> x86_64 also doesn't have a reloc like ia64:
> 00000000000505c8  0000002000000027 R_IA64_DIR64LSB        0000000000000000 
> __ehdr_start + 0
> 
> so i guess linker bug for not fully resolving that reloc.  i wonder if it can 
> be easily tested for (the simple code in the configure.ac didn't generate a 
> reloc).  or maybe i should force this off in the ia64 configure script until 
> the linker bug can be tracked down.

It would be best if you can figure out how to change the configure check so
that it fails with the buggy ia64 linker.  It might be good enough just to
make the test do readelf -r on conftest.so and complain if any relocs
mention __ehdr_start--or perhaps if there are any relocs at all (I would
expect the linker to turn it into a symbolless reloc and not export the
symbol, but that would still be a bug to have any reloc at all).  But if,
as you say, the trivial example in the configure check doesn't produce a
reloc with the buggy ia64 linker, then you'll have to modify the code to
more thoroughly mirror the real ld.so case.  Figuring out how to do that
might well be tantamount to finding the linker bug.

So, I think you really should figure out the linker's bug and both get the
linker fixed and get our generic configure check to catch buggy linkers.
But forcing it off in ia64/configure is a quick workaround and is certainly
what you should do to have a working ia64 build in the 2.20 release if you
don't manage to work up the configure change in time.


Thanks,
Roland
  
Andreas Schwab Aug. 6, 2014, 9:58 p.m. UTC | #8
Roland McGrath <roland@hack.frob.com> writes:

> So, I think you really should figure out the linker's bug and both get the
> linker fixed and get our generic configure check to catch buggy linkers.

The linker should already be fixed, I couldn't reproduce it with
2.24.0.20140601.

Andreas.
  
Roland McGrath Aug. 6, 2014, 10:04 p.m. UTC | #9
> Roland McGrath <roland@hack.frob.com> writes:
> 
> > So, I think you really should figure out the linker's bug and both get the
> > linker fixed and get our generic configure check to catch buggy linkers.
> 
> The linker should already be fixed, I couldn't reproduce it with
> 2.24.0.20140601.

I wonder if you can find the fix in binutils ChangeLogs.  That might point
the way to what we need to do in the configure check to catch the buggy ones.
  
Mike Frysinger Aug. 7, 2014, 12:25 a.m. UTC | #10
On Wed 06 Aug 2014 23:58:17 Andreas Schwab wrote:
> Roland McGrath <roland@hack.frob.com> writes:
> > So, I think you really should figure out the linker's bug and both get the
> > linker fixed and get our generic configure check to catch buggy linkers.
> 
> The linker should already be fixed, I couldn't reproduce it with
> 2.24.0.20140601.

thanks, i can confirm that 2.23.2 on ia64 fails, but 2.24 passes
-mike
  
Mike Frysinger Aug. 7, 2014, 1:59 a.m. UTC | #11
On Wed 06 Aug 2014 20:25:05 Mike Frysinger wrote:
> On Wed 06 Aug 2014 23:58:17 Andreas Schwab wrote:
> > Roland McGrath <roland@hack.frob.com> writes:
> > > So, I think you really should figure out the linker's bug and both get
> > > the
> > > linker fixed and get our generic configure check to catch buggy linkers.
> > 
> > The linker should already be fixed, I couldn't reproduce it with
> > 2.24.0.20140601.
> 
> thanks, i can confirm that 2.23.2 on ia64 fails, but 2.24 passes

2.23.2 seems to work fine on x86_64
-mike
  

Patch

--- 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;