Линукс статическая линковка мертва?
Фактически, флаг -static gcc в Linux сейчас не работает. Позвольте мне процитировать из GNU libc FAQ:
2,22. Даже статически связанные программы нуждаются в общих библиотеках, что для меня неприемлемо. Что я могу сделать?
{AJ} NSS (для подробностей просто введите `info libc "Name Service Switch") не будет работать должным образом без разделяемых библиотек. NSS позволяет использовать различные сервисы (например, NIS, файлы, базы данных, hesiod), просто изменив один файл конфигурации (/etc/nsswitch.conf) без перепривязки каких-либо программ. Единственным недостатком является то, что теперь статические библиотеки должны иметь доступ к общим библиотекам. Это прозрачно обрабатывается библиотекой GNU C.
Решением является настройка glibc с параметром --enable-static-nss. В этом случае вы можете создать статический бинарный файл, который будет использовать только службы dns и файлы (для этого измените /etc/nsswitch.conf). Вы должны явно ссылаться на все эти сервисы. Например:
gcc -static test-netdb.c -o test-netdb \ -Wl,--start-group -lc -lnss_files -lnss_dns -lresolv -Wl,--end-group
Проблема этого подхода заключается в том, что вам необходимо связать каждую статическую программу, использующую процедуры NSS, со всеми этими библиотеками.
{UD} На самом деле, больше нельзя сказать, что libc, скомпилированный с этой опцией, использует NSS. Больше нет переключателя. Поэтому настоятельно рекомендуется не использовать --enable-static-nss, так как это делает поведение программ в системе несовместимым.
Что касается этого факта, есть ли сейчас какой-нибудь разумный способ создать полнофункциональную статическую сборку в Linux, или статическое связывание совершенно не работает в Linux? Я имею в виду статическую сборку, которая:
- Ведет себя точно так же, как динамическая сборка (static-nss с несовместимым поведением - зло!);
- Работает на разумных вариациях среды glibc и версий Linux;
5 ответов
Что касается этого факта, есть ли сейчас какой-нибудь разумный способ создать полнофункциональную статическую сборку в Linux, или статическое связывание совершенно не работает в Linux?
Я не знаю, где можно найти исторические ссылки, но да, статические ссылки не работают в системах GNU. (Я считаю, что он умер при переходе с libc4/libc5 на libc6/glibc 2.x.)
Эта функция была признана бесполезной в свете:
Уязвимости безопасности. Приложение, которое было статически связано, даже не поддерживает обновление libc. Если приложение было связано в системе, содержащей уязвимость lib, оно будет сохранено в статически связанном исполняемом файле.
Код наворочен. Если многие статически связанные приложения выполняются в одной и той же системе, стандартные библиотеки не будут использоваться повторно, поскольку каждое приложение содержит в себе собственную копию всего. (Пытаться
du -sh /usr/lib
чтобы понять масштабы проблемы.)
Попробуйте копать архивы списков рассылки LKML и glibc 10-15 лет назад. Я уверен, что давно я видел что-то связанное с LKML.
Я думаю, что это очень раздражает, и я считаю высокомерным называть функцию "бесполезной", потому что у нее есть проблемы, связанные с определенными вариантами использования. Самая большая проблема с подходом glibc заключается в том, что он жестко кодирует пути к системным библиотекам (gconv, а также nss), и поэтому он ломается, когда люди пытаются запустить статический двоичный файл в дистрибутиве Linux, отличном от того, для которого он был создан.
В любом случае, вы можете обойти проблему gconv, установив GCONV_PATH так, чтобы он указывал на соответствующее местоположение, что позволило мне взять двоичные файлы, созданные на Ubuntu, и запустить их на Red Hat.
Статическое связывание снова на подъеме!
- Многие (большинство?) Исполняемые файлы языка программирования Go статически связаны.
- Повышенная мобильность и обратная совместимость - одна из причин их популярности.
- Другие языки программирования прилагают аналогичные усилия, чтобы сделать статическое связывание действительно простым, например, Haskell (я работаю над этим усилием).
- Настраиваемые дистрибутивы / наборы пакетов Linux, такие как NixOS / nixpkgs, позволяют статически связывать большую часть их пакетов (например, его
pkgsStatic
пакетный набор может предоставить все виды статически связанных исполняемых файлов). - Статическое связывание может привести к лучшему устранению неиспользуемого кода во время соединения, уменьшая размер исполняемых файлов.
- libcs, такие как musl, делают статическое связывание простым и корректным.
- Некоторые крупные лидеры индустрии программного обеспечения согласны с этим. Например, Google пишет новую библиотеку libc, нацеленную на статическое связывание ("поддержка статического связывания без PIE и статического связывания с PIE", "мы не намерены инвестировать в этот момент [в] поддержку динамической загрузки и связывания").
Статическое связывание, похоже, не очень нравится в мире Linux. Вот мой дубль.
Люди, которые не видят привлекательности статического связывания, обычно работают в области ядра и операционной системы более низкого уровня. Многие разработчики * nix библиотек потратили целую жизнь на решение неизбежных проблем, связанных с попыткой связать сотню постоянно меняющихся библиотек - задача, которую они выполняют каждый день. Посмотрите на автоинструменты, если вы когда-нибудь захотите узнать, какие сальто им удобно выполнять.
Но не следует ожидать, что все остальные будут тратить на это большую часть своего времени. Статическое связывание продвинет вас далеко от буферизации библиотеки. Разработчик может обновить зависимости своего программного обеспечения в соответствии с расписанием программного обеспечения, вместо того, чтобы быть вынужденным сделать это в момент появления новых версий библиотеки. Это важно для пользовательских приложений со сложными пользовательскими интерфейсами, которым необходимо управлять потоком многих библиотек более низкого уровня, от которых они неизбежно зависят. И именно поэтому я всегда буду фанатом статических ссылок. Если вы можете статически связывать кросс-скомпилированный переносимый код C и C++, вы в значительной степени сделали мир устрицей, поскольку вы сможете быстрее доставлять сложное программное обеспечение на широкий круг постоянно растущих устройств мира.
Там есть много, с чем можно не согласиться, с другой точки зрения, и приятно, что программное обеспечение с открытым исходным кодом учитывает их все.
Добавление на другие ответы:
По причинам, указанным в других ответах, это не рекомендуется для большинства дистрибутивов Linux, но на самом деле существуют дистрибутивы, созданные специально для запуска статически связанных двоичных файлов:
Из сталинского описания:
static linux основан на отобранной вручную коллекции лучших инструментов для каждой задачи, и каждый инструмент статически связан (включая некоторые X-клиенты, такие как st, surf, dwm, dmenu),
Он также нацелен на уменьшение размера двоичных файлов за счет исключения, где это возможно, glibc и других раздутых библиотек GNU (ранние эксперименты показали, что статически связанные двоичные файлы обычно меньше, чем их динамически связанные аналоги glibc!!!). Обратите внимание, что это в значительной степени противоречит мнению Ульриха Дреппера о статическом линковании.
Из-за того, что статически связанные двоичные файлы запускаются быстрее, распределение также нацелено на повышение производительности.
Статическое связывание также помогает уменьшить зависимость.
Вы можете узнать больше об этом в этом вопросе о статических и динамических связях.
То, что вам нужно динамически связываться со службой NSS, не означает, что вы не можете статически связываться с какой-либо другой библиотекой. Все, что часто задаваемые вопросы говорят о том, что даже "статически" связанные программы имеют некоторые динамически связанные библиотеки. Это не говорит о том, что статическое связывание "невозможно" или "не работает".