Page 1 of 1

Так ли нужен PE DLL?

Posted: Tue Mar 12, 2024 2:57 am
by turbocat
Позволю себе ну просто вот 30 секунд или 1 минуту маленькую историческую справку:
Путь поддержки С KolibriOS был труден и тернист. Костыли торчат во все стороны и до сих пор.
Если углубиться в историю проекта, то станет ясно что раньше никаких PE DLL у нас не было. Вся линковка производилась статически. Пример тому наследие MenuetOS — menuetlibc. Вообще menuetlibc это "порт порта". То есть изначально это был порт glibc для MSDOS и являлся частью проекта DJGPP. Потом эта библиотека была адаптирована для MenuetOS (что позволило например портировать на неё DOSBox). Позже ей продолжили пользоваться и в KolibriOS. На самом деле эта библиотека достаточно "плотная" и содержит кучу заглушек для простоты переноса софта, и это был её большой плюс. А вот большим минусом оказалось, что библиотека не потокобезопасна (такая уж ли это проблема если у нас потоки в портах программ используются только для звука) и содержит кучу багов (хмммм покажите). Как я понимаю это и с подвигло Serge сделать кросс компилятор GCC и портировать библиотеку Newlib. Newlib относительно потокобезопасна, однако из-за этого она и раздута. Помимо Newlib появилось куча портов библиотек таких ffmpeg размер которых идёт уже на мегабайты. Если продолжить линковать это всё статически, то ISO образ вероятно очень сильно раздуется (что спорно, потому что такие библиотеки обычно используют 1-2 программы). В общем во имя уменьшения занимаемого пространства на диске, Serge изобрёл чудо способ линковать "динамически" с помощью юзерспейсного загрузчика PE.

Как работает чудо-загрузчик PE от Serge?
В libgcc (линкуется статически) существует некоторый укороченный загрузчик PE, который проводит начальную загрузку libc.dll (она же Newlib). После загрузки, управление передаётся на libc_crt_startup() в libc.dll. А там уже вызывается главный PE загрузчик который парсит "выдранную" из PE секцию импорта и загружает остальные библиотеки.

А зачем ещё используют DLL?
Кроме уменьшения занимаемо программами места на диске DLL используется, например для уменьшения потребляемой памяти. Дело в том что например в Linux so-бибилиотек обязаны быть PIE (position-independent executable), чтобы можно было производить например шаринг страниц памяти с кодом, либо read-only данных между процессами.

DLL- это здорово, а минусы будут?
Из минусов, что я могу вспомнить:
  • Ад из-за зависимостей, особенно для больших проектов;
  • Долгая загрузка (проблема скорее для старых систем);
  • Конфликты версий библиотек (проблема скорее Linux/BSD, в Windows идиотская концепция "тащить всё с собой")
Возвращаясь к загрузчику Serge
Шаринга страниц конечно же в юзерспейсном загрузчике нет. Представим себе небольшую программу использующую пару функций из libc.dll. По идее такая программа должна потреблять немного памяти, но на самом деле она будет загружать в память libc.dll целиком, а это значит что программа которая при статической линковке потребляла бы 40кб памяти, станет потреблять ~600кб. Но это не такая большая проблема если считать что эту библиотеку используют только порты программ. Есть другая беда - это зависимости. Куда проще запускать программу состоящую из одного файла чем с кучей DLL-ок (которые ещё и должны быть заранее помещены в нужную папку)

А что по статической линковке?
  • Статическая линковка проще.
  • Можно заюзать LTO.
  • Полученный бинарник не требует никаких зависимостей.
  • Иногда можно сэкономить на памяти.
  • Поидее бинарник должен загружатся быстрее, но из-за механизма предзагрузки DLL может быть и наоборот.
А вообще к чему это всё?
Дело в том что пилю нам новый GCC-тулчейн, так как тулчейн от Serge знатно так устарел, к тому же у меня есть желание сделать более адекватную SDK которая позволит собирать порты собственными билдистемами вместо шаманизма с Makefile и Tup. И вообще-то мне уже удалось добится некоторых успехов и даже собрать моим тулчейном игру OpenTyrian. Однако я задался вопросом, а так ли нужна поддержка PE DLL? Единственную проблему которую оно решает, это то что программы становятся худее, на этом кажется плюсы заканчиваются. Я сделал сравнения статической линковки и динамической на примере OpenTyrian. Разница в размере файлов вообщем-то в ~2 раза где-то, а выигрыш по потребляемой памяти всего ~600кб. На самом деле это не значительно по сравнению с тем что DosBOX ест где-то 50мб (но не знаю на сколько это будет выгодно с ffmpeg например). Ещё есть обратный пример: когда то давно я делал из SDL PE DLL, и на моё удивление, вместо того чтобы уменьшится, прога стала ещё жирнее (видимо это связано с большим количеством строк с именами функций в импорте).

Выскажите своё мнение
На самом деле мне было бы интересно послушать людей, которые больше разбираются в этой теме чем я. Возможно я что-то упускаю.

PS:
Расписал всё криво. Форумом пользоватся не умею(