Статическая линковка libc, возможно или нет, рекомендуется или нет?

Вопрос или проблема

Я вижу эту строку в моем бинарном файле:

0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

Не должно ли я избавиться от этого? На самом деле, более запутанно, почему это там в первую очередь? Мне кажется, что компиляция всего, что работает только на хост-машине, по умолчанию в gcc немного безумна. Разве не опасно просто полагаться на какую-то случайную libc, которая может быть или не быть на машине, куда я в конечном итоге скопирую этот бинарник? Я этого не понимаю. На Windows, я думаю, я бы получил какую-то ошибку “отсутствует выполнение”, которая привязана к точному времени выполнения, с которым я его компилировал, так что если я скомпилировал на XP с определенным компилятором, то любая хост-машина также должна иметь установленное это время выполнения. Но на Linux я никогда не слышал о таком случае; или есть ли каталог из 50 различных libc.so где-то, и правильная версия связывается, когда моё приложение пытается запуститься? У меня есть ощущение, что .dll ад наоборот существует на Linux, но подозреваю, что это не так.

По крайней мере, с библиотекой GNU C, связывание несет информацию о версии для каждого символа (функции и т. д.), который используется. Вы можете увидеть это с помощью objdump -T; например, на /bin/ls, я получаю

DYNAMIC SYMBOL TABLE:
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3   __ctype_toupper_loc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __uflow
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 getenv
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 sigprocmask
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __snprintf_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 raise
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 free
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 abort

и так далее.

Разработчики библиотеки C прилагают большие усилия, чтобы обеспечить обратную совместимость библиотеки C. Вышеуказанный вывод означает, что ls нуждается в __ctype_toupper_loc из версии 2.3 или более поздней версии библиотеки C и т. д. Любая библиотека C, которая предоставляет все необходимые символы, сможет запустить данный бинарный файл; и любая заданная версия библиотеки GNU C предоставляет реализации всех символов, которые когда-либо предоставлялись более старыми версиями библиотеки C (начиная с 1997 года).

Другой способ решения вопроса, используемый большинством библиотек на системах на базе Linux (на самом деле, на системах на базе ELF и других), это soname. Каждая библиотека определяет не только своё имя, но и номер версии, который изменяется каждый раз, когда вводятся разрушающие изменения (в некоторых случаях чаще). Несколько версий библиотек с разными soname могут быть установлены параллельно; например

-rw-r--r--  1 root root  2500416 Dec 16 21:07 libcrypto.so.1.0.2
-rw-r--r--  1 root root  2711616 Nov 28 23:43 libcrypto.so.1.1

(Это также используется библиотекой C, о чем свидетельствует название зависимости, libc.so.6 — но последнее изменение soname библиотеки GNU C произошло много лет назад.)

Отвечая на вопрос в вашем заголовке, теоретически возможно статически связать библиотеку C, но это редко необходимо или полезно (и может быть запутанным, поскольку некоторые части библиотеки C динамически связаны даже при статическом связывании библиотеки C). Может быть полезным статически связывать другие библиотеки. Другие языки используют разные подходы, и, например, программы на Go статически связаны.

Ответ или решение

Статическая компоновка libc: возможно ли это и стоит ли это делать?

Вопрос статической компоновки библиотеки C (libc) на Linux вызывает множество дискуссий среди IT-специалистов. Давайте разберем, почему с точки зрения компоновки ваше приложение может зависеть от динамической библиотеки libc, и в каких случаях статическая компоновка может оказаться актуальной.

1. Почему динамическая связка – это норма

Вы упомянули, что в выводе вашего бинарного файла появилось сообщение о зависимостях от libc.so.6, что означает, что ваше приложение использует динамически связанную библиотеку. В Linux это распространенный подход, и на это есть несколько причин:

  • Эффективность: Большинство приложений для Linux используют динамическую компоновку, поскольку она позволяет разделять код библиотек между разными приложениями. Это значительно сокращает общий объем занимаемой памяти.

  • Обновляемость: Когда библиотека обновляется (например, для исправления ошибок или уязвимостей), все приложения, которые её используют, получают доступ к обновленной версии без необходимости перекомпиляции.

  • Совместимость: Как вы заметили, разработчики C-библиотеки делают всё возможное для обеспечения обратной совместимости. Это значит, что многие бинарные файлы, созданные с помощью старых версий glibc, могут запускаться на новых версиях библиотеки, что облегчает поддержку приложений.

2. Версии библиотек и их наличие

В отличие от Windows, где библиотеки могут иметь строгие требования к версиям, в Linux устанавливаются разные версии библиотек (soname). Таким образом, у вас действительно может быть несколько версий одной и той же библиотеки, и система будет автоматически подбирать нужную. Например, у вас может быть:

  • libc.so.6 — последняя версия GLIBC.
  • libc.so.5 — более старая версия, которая также может существовать в системе.

Этот механизм предотвращает «ад с динамическими библиотеками», о котором вы упомянули.

3. Возможность и обоснованность статической компоновки

С точки зрения возможностей, статическая компоновка libc возможна, но она не всегда рекомендована по следующим причинам:

  • Размер бинарного файла: Статически скомпонованное приложение включает в себя весь код библиотеки, что значительно увеличивает размер итогового файла.

  • Совместимость и обновление: Если в статически скомпонованной библиотеке обнаружена уязвимость, ваше приложение не может быть автоматически обновлено. Вам придется перекомпилировать и выпустить новую версию приложения.

  • Проблемы с зависимостями: Некоторые части libc, такие как стандартные настройки locales, могут использовать внешние ресурсы, что делает статическую компоновку еще более сложной и потенциально проблематичной.

4. Когда может быть полезна статическая компоновка

Несмотря на ограничения, статическая компоновка может быть полезна в определённых сценариях:

  • Изолированные системы: Встраиваемые системы или контейнеры, где системная библиотека может отсутствовать или не быть совместимой. В этом случае использование статической компоновки может уменьшить риск несоответствия библиотек.

  • Минимизация зависимостей: Для специфических утилит или в ситуациях, когда важно избежать всех возможных зависимостей от библиотек системы, статическая компоновка может быть целесообразной.

Заключение

Исходя из изложенного, статическая компоновка libc — это возможный, но не всегда рекомендованный подход. В большинстве случаев динамическая компоновка предоставляет больше преимуществ, особенно в контексте совместимости, обновляемости и эффективного использования ресурсов. Если ваша среда позволяет полагаться на динамические библиотеки, это, вероятно, лучший выбор. В случае специфических требований и ограничений на системный уровень стоит рассмотреть статическую компоновку, но с пониманием присущих ей рисков и недостатков.

Оцените материал
Добавить комментарий

Капча загружается...