Как сам динамический компоновщик / загрузчик может быть динамически связан как сообщено `file`?

12

Рассмотрим зависимости общего объекта /bin/bash, который включает в себя /lib64/ld-linux-x86-64.so.2(динамический компоновщик / загрузчик):

ldd /bin/bash
    linux-vdso.so.1 (0x00007fffd0887000)
    libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f57a04e3000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f57a04de000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f57a031d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f57a0652000)

Проверка /lib64/ld-linux-x86-64.so.2показывает, что это символическая ссылка на /lib/x86_64-linux-gnu/ld-2.28.so:

ls -la /lib64/ld-linux-x86-64.so.2 
lrwxrwxrwx 1 root root 32 May  1 19:24 /lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.28.so

Кроме того, fileотчеты /lib/x86_64-linux-gnu/ld-2.28.soк себе должны быть динамически связаны:

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

Я хотел бы знать:

  1. Как динамически линкер / загрузчик ( /lib64/ld-linux-x86-64.so.2) может быть динамически связан? Это связывает себя во время выполнения?
  2. /lib/x86_64-linux-gnu/ld-2.28.soзадокументировано для обработки двоичных файлов a.out ( man ld.so), но /bin/bashявляется ли исполняемый файл ELF?

Программа ld.so обрабатывает двоичные файлы a.out, формат, используемый давно; ld-linux.so * (/lib/ld-linux.so.1 для libc5, /lib/ld-linux.so.2 для glibc2) управляет ELF, которым все пользуются уже многие годы.

Shuzheng
источник
Ядро не заботится о таких тонких таксономических тонкостях (и вы не должны ;-)). Ядро делает разницу только между ELF, которые нуждаются в интерпретаторе, и теми, которые этого не делают. И AFAIK, вы не можете использовать переводчика, который сам по себе нужен.
Мосви
Моя шахта /lib/x86_64-linux-gnu/ld-2.28.so
@StephenKitt
@mosvy да, извините, я перепутал fileошибочный комментарий о том, как он определяет статические двоичные файлы, и реальность ld-2.28.so... Различия есть PT_DYNAMIC.
Стивен Китт

Ответы:

17
  1. Да, он связывает себя при инициализации. Технически динамический компоновщик не нуждается в разрешении и перемещении объекта для себя, так как он полностью разрешен как есть, но он определяет символы и должен заботиться о них при разрешении двоичного файла, который он «интерпретирует», и эти символы обновляются указать на их реализации в загруженных библиотеках. В частности, это влияет malloc- в компоновщик встроена минимальная версия с соответствующим символом, но она заменяется версией библиотеки C после ее загрузки и перемещения (или даже вставленной версией, если она есть), с некоторой осторожностью приняты, чтобы гарантировать, что это не случится в точке, где это может сломать компоновщик.

    Кровавые подробности в rtld.c, в dl_mainфункции.

    Обратите внимание, однако, что ld.soне имеет внешних зависимостей. Вы можете увидеть символы, связанные с nm -D; ни один из них не определен.

  2. Страница man относится только к записям, находящимся непосредственно под /lib, т. /lib/ld.so Е. (Динамический компоновщик libc 5, который поддерживает a.out) и /lib*/ld-linux*.so*(динамический компоновщик libc 6, который поддерживает ELF). Эта страница очень специфична и ld.soне является таковой ld-2.28.so.

    Динамический компоновщик, встречающийся в большинстве современных систем, не включает a.outподдержку.

fileи lddсообщать разные вещи для динамического компоновщика, потому что у них разные определения того, что представляет собой статически связанный двоичный файл. Ибо lddдвоичный файл является статически связанным, если у него нет DT_NEEDEDсимволов, то есть нет неопределенных символов. Например file, двоичный файл ELF является статически связанным, если у него нет PT_DYNAMICраздела (это изменится в fileследующей версии 5.37; теперь он использует наличие PT_INTERPраздела в качестве индикатора динамически связанного двоичного файла, который соответствует комментарию в код).

Динамический компоновщик библиотеки GNU C не имеет каких-либо DT_NEEDEDсимволов, но у него есть PT_DYNAMICраздел (поскольку технически это разделяемая библиотека). В результате ldd(динамический компоновщик) указывает, что он статически связан, но fileуказывает, что он динамически связан. В нем нет PT_INTERPраздела, поэтому в следующем выпуске fileтакже будет указано, что он статически связан.

$ 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

file5.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

(с текущей разрабатываемой версией file).

Стивен Китт
источник
Почему слово «интерпретация» используется в контексте динамического связывания? Это слово обычно используется в контексте языков программирования.
Shuzheng
Что вы подразумеваете под "динамическим компоновщиком библиотеки GNU C"? Вы имеете в виду /lib*/ld-linux*.so*или третий динамический компоновщик?
Shuzheng
Где можно увидеть lddотчеты динамического компоновщика как статически связанные? Потому что список зависимостей общих объектов пуст?
Shuzheng
Динамически связанные программы нуждаются в некоторой работе, прежде чем они могут быть выполнены; эта работа выполняется динамическим компоновщиком, который в конечном итоге играет роль, аналогичную интерпретатору - он интерпретирует таблицы перемещения и т. д. для создания чего-то, что может запустить компьютер.
Стивен Китт
Когда я говорю «динамический компоновщик библиотеки GNU C», я имею в виду реализацию, включенную в библиотеку GNU C, которая обычно поставляется как /lib*/ld-linux*.so*. Я указал источник динамического компоновщика, потому что есть другие реализации, доступные для Linux.
Стивен Китт
0
  1. Я подозреваю, что fileпрограмма ошибается из-за того, что динамически компоновщик / загрузчик сам по себе динамически связан. lddПрограмма не согласен. По крайней мере, не в моей системе (Debian Stretch):

    ldd /lib/x86_64-linux-gnu/ld-2.24.so
        statically linked
    
  2. man ld.soтакже гласит: «ld-linux.so * обрабатывает ELF» . В вашей системе (и, кстати, у меня тоже) оба являются символическими ссылками на один и тот же двоичный файл, который, как я понял, способен обрабатывать как ELF, так и (старый устаревший) формат a.out.

Hkoof
источник
какую информацию вы добавляете к принятому ответу?
miracle173
2
@ miracle173 этот ответ старше принятого ответа ;-).
Стивен Китт
вы правы. Я пропустил это. Я думал, что вопрос и принятый ответ очень старые, и этот ответ был опубликован в последние часы. Я не могу отменить свое понижение, пока кто-то не изменит пост.
miracle173