2

When executing a dynamically linked executable on Linux, the dynamic linker is invoked as its interpreter (described in this answer). If I understand correctly, running:

$ ./dynamic_elf

Will result in Linux executing:

/lib64/ld-linux.so.2 ./dynamic_elf

I'm having a hard time understanding how that will work for /proc/self/exe. Per the logic above, running:

$ /proc/self/exe

Will result in Linux executing:

/lib64/ld-linux.so.2 /proc/self/exe

Now, when the dynamic linker tries to load the elf at /proc/self/exe, wouldn't it point to the dynamic linker itself, as ld-linux.so.2 is now the running executable?

I know that the command above JustWorks, so what am I missing?

  • Does the dynamic linker gets more than the path of the elf that invoked it?

  • Are the semantics here different from shebang (#!) interpreters?

uvuv
  • 368
  • 1
  • 7

1 Answers1

3

As you pointed out, the kernel is not passing the executed binary as a path to the interpreter:

$ /lib64/ld-linux-x86-64.so.2 /proc/self/exe
loader cannot load itself

Although the glibc dynamic linker supports this invocation method (providing the program to run as an argument), it's not what's used during the normal execution of an interpreted ELF binary. In fact, the kernel provides the arguments from the execve unmodified to the dynamic linker.

The dynamic linker doesn't "load" or "execute" the interpreted ELF binary at all. The kernel loads both the interpreter and the interpreted binary into memory and begins execution at the entry point of the interpreter. The entry point of the interpreted binary is passed to the interpreter via the AT_ENTRY field in the auxiliary vector.

The dynamic linker then preforms the necessary runtime linking and jumps to the "real" entry point.

You can observe this all in gdb if you set a break point on _start when executing a normal interpreted ELF executable. With "show args" you'll see the "real" argv without any extra values, and the memory map of the process will already have the interpreted binary loaded (before the interpreter has run a single instruction).

#! scripts work the way you expect (actually manipulating the argv values).

Mikel Rychliski
  • 3,455
  • 5
  • 22
  • 29