Overhead от динамической линковки

Что: c0de9bbf633b421a57a10db70d6d76b5f195546e

Когда: 2020-11-11 20:30:51+03:00

Темы: go plan9 tip

Overhead от динамической линковки

http://harmful.cat-v.org/software/dynamic-linking/
http://harmful.cat-v.org/software/dynamic-linking/versioned-symbols
https://sta.li/faq/
В комментарии http://blog.stargrave.org/russian/71870b1510dfc2727093f2767b994b8596f9b163#comment1
я запускал convert, в котором ldd на полэкрана, в течении 165мс. Когда
руками собрал с нуля, то у меня на полтора экрана вывод ldd и утилита
запускается более чем в два раза дольше. Всё таки 200мс это очень и
очень заметное на глаз время, тем более для long-live утилиты.

Когда я только начал в этом году программировать на C, то задавался
вопросом какие библиотеки мне делать (static vs shared). И все хакеры
говорят в один голос о статической линковке. Есть даже целый "stali"
(static linux) дистрибутив, целью которого является только статическая
линковка, musl и всякое такое. В котором много ссылок на конкретные
примеры всяких размеров программ, времени их запуска и тому подобного.
Plan9 и Go -- имеют только такую линковку.

И вот, судя по ImageMagick, я однозачно теперь тоже за статическую.
Во-первых, если использовать всякие -ffunction-sections+-Wl,--gc-sections,
то в итоговом исполняемом файле не останется лишнего кода в виде
неиспользуемых функций. Во-вторых, даже если размер будет и больше, то
он всё равно при этом будет быстро (быстрее) загружаться, что куда
важнее чем место на диске.

Основной аргумент за динамическую линковку у людей: типа если нужно
обновить OpenSSL, то можно только его обновить, не трогая остального. Но
даже я на своей практике с чистой совестью могу заявить что это брехня
только изредка работающая, ибо регулярно *на практике* несовместимости в
версиях библиотеки, которые препятствуют обновлению и по факту
приходится всё равно пересобирать зависимый от неё софт. Да и в чём
проблема пересборки всего что зависит от неё, пускай это даже и libc?
Отсутствие исходников? Не аргумент, ибо они должны быть в свободном ПО.
Проприетарное -- идёт нафиг. Время сборки/пересборки -- а вот это повод
задумываться над скоростью компилирования. C-компиляторы вполне себе
шустрые например. Go -- аналогично, пересобрать ВЕСЬ Go софт, сколько бы
его не было -- вопросы нескольких минут, как мне представляется на
практике. C++/Rust/etc -- теперь я ещё больше понимаю насколько важно
время сборки. А в идеальной и прекрасной системе со свободным ПО (значит
и исходники будут) на C/Go проблем нет никаких. Скорость,
производительность, простота, безопасность (куча ссылок касающаяся
недостатков динамической линковки про безопасность как-раз),
эффективность! Плюс никаких проблем с тем чтобы иметь софт с самыми
разносторонними по версиям зависимостями, ибо они всё равно вшиваются.

Я однозначный поклонник этого подхода!

оставить комментарий

комментарий 0:

From: kmeaw
Date: 2020-11-13 08:47:58Z

Я когда-то пытался жить со static-only системой, и пришёл к следующим
выводам:

1) если пытаться собирать статически то, что не предусмотрено
разработчиком или мейнтейнером, то куча всего неизбежно будет ломаться,
придётся это чинить; например, libnss из glibc просто не работает в
статике;

2) хотя памяти сейчас много, и она дешёвая, динамическая линковка
позволяет экономить память без KSM;

3) статически слинкованные программы гораздо легче деплоить в
традиционных системах - достаточно всего лишь скопировать один файл;
это особенно хорошо работает, когда вся функциональность целого сервиса
влезает в одну программу, которая специализируется конфигом или argv[0],
а единственной production-задачей сервера (или контейнера) является
работа этой программы;

4) конфликты динамических библиотек и сборка замыканий по зависимостям
хорошо реализованы в Nix; в остальных системах можно пытаться повторять
это с помощью манипуляций с LD_LIBRARY_PATH и lddtree, либо установкой
breakpoint на entry point и анализом /proc/$PID/maps;

5) иногда бывает очень полезно точечно исправить какую-нибудь
уязвимость, точечно подправив бинарник; с разделяемыми библиотеками это
можно сделать очень массово и быстро, например
https://github.com/kmeaw/ghostbuster

комментарий 1:

From: Sergey Matveev
Date: 2020-11-13 09:08:14Z


>придётся это чинить; например, libnss из glibc просто не работает в статике;

Да, именно про эти два примера (nss/glibc) я начитался уже :-). Их
постоянно называют. Но я тут проблемы не вижу: нафиг glibc, нафиг
libnss. glibc я вообще вижу так люто ненавидим многими! Да и вот у меня
даже nss и не стоит -- жить без них точно можно.

>2) хотя памяти сейчас много, и она дешёвая, динамическая линковка
>позволяет экономить память без KSM;

Но... памяти сейчас действительно много и она дешёвая :-)! Просто когда
на одной чаше весов скорость загрузки програм, а на другой память...
которая в теории могла бы помочь с ускорением загрузки (кэш ФС хотя бы),
но на практике не сильно помогает. Прям сейчас у меня несколько гигабайт
не заняты даже ZFS ARC-ом -- но для скорости загрузки это всё равно не
поможет.

>3) статически слинкованные программы гораздо легче деплоить в
>традиционных системах - достаточно всего лишь скопировать один файл

О да! За это мне так нравятся программы на Go! Даже без проблем
собранную Go программу с FreeBSD 12.x на 11.x многолетней давности можно
без проблем запустить.

>4) конфликты динамических библиотек и сборка замыканий по зависимостям
>хорошо реализованы в Nix

Двое коллег даже полностью перешли на него! Интересная система, идея и
подход -- очень уважаю!

>5) иногда бывает очень полезно точечно исправить какую-нибудь
>уязвимость, точечно подправив бинарник

Ну... правильнее всё же было бы пересобрать из исходников. Правка
бинаря... хак остаётся хаком :-)

Если это всё что можно сказать про жизнь на статической системе, то,
лично для меня, это только подтверждает что это правильный путь :-)

Сгенерирован: SGBlog 0.34.0