How can the dynamic linker/loader itself be dynamically linked as reported by `file`?

  1. Yes, it links itself when it initialises. Technically the dynamic linker doesn’t need object resolution and relocation for itself, since it’s fully resolved as-is, but it does define symbols and it has to take care of those when resolving the binary it’s “interpreting”, and those symbols are updated to point to their implementations in the loaded libraries. In particular, this affects malloc — the linker has a minimal version built-in, with the corresponding symbol, but that’s replaced by the C library’s version once it’s loaded and relocated (or even by an interposed version if there is one), with some care taken to ensure this doesn’t happen at a point where it might break the linker.

    The gory details are in rtld.c, in the dl_main function.

    Note however that ld.so has no external dependencies. You can see the symbols involved with nm -D; none of them are undefined.

  2. The manpage only refers to entries directly under /lib, i.e. /lib/ld.so (the libc 5 dynamic linker, which supports a.out) and /lib*/ld-linux*.so* (the libc 6 dynamic linker, which supports ELF). The manpage is very specific, and ld.so is not ld-2.28.so.

    The dynamic linker found on the vast majority of current systems doesn’t include a.out support.

file and ldd report different things for the dynamic linker because they have different definitions of what constitutes a statically-linked binary. For ldd, a binary is statically linked if it has no DT_NEEDED symbols, i.e. no undefined symbols. For file, an ELF binary is statically linked if it doesn’t have a PT_DYNAMIC section (this will change in the release of file following 5.37; it now uses the presence of a PT_INTERP section as the indicator of a dynamically-linked binary, which matches the comment in the code).

The GNU C library dynamic linker doesn’t have any DT_NEEDED symbols, but it does have a PT_DYNAMIC section (since it is technically a shared library). As a result, ldd (which is the dynamic linker) indicates that it’s statically linked, but file indicates that it’s dynamically linked. It doesn’t have a PT_INTERP section, so the next release of file will also indicate that it’s statically linked.

$ ldd /lib64/ld-linux-x86-64.so.2
        statically linked

$ file $(readlink /lib64/ld-linux-x86-64.so.2)
/lib/x86_64-linux-gnu/ld-2.28.so: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=f25dfd7b95be4ba386fd71080accae8c0732b711, stripped

(with file 5.35)

$ file $(readlink /lib64/ld-linux-x86-64.so.2)
/lib/x86_64-linux-gnu/ld-2.28.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=f25dfd7b95be4ba386fd71080accae8c0732b711, stripped

(with the currently in-development version of file).