Динамічне посилання - Linux Vs. Windows


10

Під Windows, коли я компілюю код C / C ++ у проекті DLL в MSVC, я отримую 2 файли:

  1. MyDll.dll
  2. MyDll.lib

де, наскільки я розумію, MyDll.libміститься якась таблиця вказівників, що вказує на розташування функцій у dll. При використанні цього dll, скажімо, у файлі exe, MyDll.libвін вбудовується у файл exe під час зв’язку, тому під час виконання він "знає", де розташовані функції, MyDll.dllі може їх використовувати.

Але якщо я компілюю один і той же код під Linux, я отримую лише один файл MySo.soбез MySo.a(еквівалент libфайлу в Linux), тож як виконуваний файл під Linux знає, де розташовані функції, MySo.soякщо нічого не вбудовано в нього під час посилання?

Відповіді:


1

В Linux лінкер (а не динамічний лінкер) здійснює пошук через спільні бібліотеки, визначені під час посилання, і створює посилання на них всередині виконуваного файлу. Коли динамічний лінкер завантажує ці виконувані файли, він завантажує потрібні їм бібліотеки в пам'ять і розв'язує символи, що дозволяє запускати бінарні файли.

MySo.a, якщо він створений, насправді міститиме символи, які мають бути пов'язані безпосередньо у двійковий файл, а не "таблиці пошуку символів", що використовуються в Windows.

відповідь rustyx пояснює процес у Windows більш ретельно, ніж я можу; минуло давно, як я використовував Windows.


1
"Windows застосовує інший підхід ... вкажіть до операційної системи, де саме є символи в DLL" - це суперечить wiki , який говорить про те, що імена функцій все ще вирішені (при запуску або при першому виклику до функції бібліотеки), навіть коли ви використовувати порядкові порядки (якщо тільки не використовується пряме прив'язування адреси, що ніхто не робив би, оскільки це змушує користувачів бібліотеки перекомпілювати та перерозподілити їх код, коли бібліотека змінюється).
юг

@yugr Вилучив цю частину, я все одно схопився за соломку.
SS Anne

4

Лінкер MSVC може з'єднати файли об'єктів (.obj) та бібліотеки об'єктів (.lib) для отримання .EXE або .DLL.

Для зв’язку з DLL процес у MSVC полягає у використанні так званої бібліотеки імпорту (.LIB), яка діє як клей між іменами функції C та таблицею експорту DLL (у DLL функцію можна експортувати за назвою або по порядковим - останній часто використовується для недокументованих API - інтерфейсів).

Однак у більшості випадків таблиця експорту DLL містить усі назви функцій, і тому бібліотека імпорту (.LIB) містить значною мірою зайву інформацію (" функція імпорту ABC -> експортована функція ABC " тощо).
Можна навіть генерувати .LIB з існуючого .DLL.

Лінкери на інших платформах не мають цієї "функції" і можуть зв’язуватися безпосередньо з динамічними бібліотеками.


"Лінкери на інших платформах не мають цієї функції", хоча це легко реалізувати (наприклад, Implib.so робить це для Linux) для досягнення затримки завантаження та інших вигод.
юг

@yugr: тому "особливість" міститься в лапках - це не те, що ти зазвичай хочеш робити, а це додаткова робота, яку ти повинен виконати в Windows.
Кріс Додд

1

Відмінність, яку ви бачите, полягає більше в деталі реалізації - під кришкою і Linux, і Windows працюють аналогічно - ви кодує виклик функції заглушки, яка статично пов'язана у вашому виконуваному файлі, і ця заглушка потім завантажує DLL / shlib (якщо це потрібно затримано) завантаження , інакше бібліотека завантажується при запуску програми) і (при першому дзвінку) розв'язує символ через GetProcAddress/ dlsym.

Єдина відмінність полягає в тому, що в Linux ці функції заглушки (які називаються PLT-заглушками) генеруються динамічно, коли ви зв’язуєте додаток з динамічною бібліотекою (бібліотека містить достатню кількість інформації для їх генерації), тоді як в Linux вони генеруються, коли сама DLL є створено, в окремому .libфайлі.

Два підходи настільки схожі, що насправді можливо імітувати бібліотеки імпорту Windows на Linux (див. Implib.so Проект ).


0

У Linux ви переходите MySo.soдо лінкера, і він здатний витягти лише те, що потрібно для фази посилання, вводячи посилання, яке MySo.soпотрібно під час виконання.


-3

.dllабо .soмають спільні лібри (пов'язані під час виконання), а .aта.lib в є статичною бібліотекою (пов'язаною під час компіляції). Це не має різниці між Windows та Linux.

Різниця полягає в тому, як вони поводяться. Примітка: різниця лише в звичаях, як вони використовуються. Було б не надто важко зробити Linux будувати за допомогою Windows і навпаки, за винятком того, що практично ніхто цього не робить.

Якщо ми використовуємо dll або називаємо функцію навіть із власного двійкового файлу, існує простий і зрозумілий спосіб. Наприклад, в С ми бачимо, що:

int example(int x) {
  ...do_something...
}

int ret = example(42);

Однак на рівні зорі може бути багато відмінностей. Наприклад, на x86 callвиконується код коду, а 42на стеці - дані. Або в деяких регістрах. Або де завгодно. Ніхто цього не знає, перш ніж писати dll , як , як він буде використовуватися. Або як проекти захочуть використовувати його, можливо, написане компілятором (або мовою!), Який навіть зараз не існує (або це невідомо розробникам DLL).

Наприклад, за замовчуванням і C, і Pascal ставлять аргументи (і отримують значення повернення) зі стека - але вони роблять це в іншому порядку . Ви також можете обмінятися аргументами між своїми функціями в регістрах шляхом деяких - залежних від компілятора - оптимізації.

Як ви бачите правильно, звичайним для Windows є те, що будуючи dll, ми також створюємо мінімум .a/ .libз ним. Ця мінімальна статична бібліотека - лише обгортка, символи (функції) цього dll досягаються через неї. Це робить необхідні конверсії виклику на рівні асм.

Його перевага - сумісність. Його недолік полягає в тому, що якщо у вас є лише .dll, ви можете важко розібратися, як його функції хочуть викликати. Це робить використання dlls хакерським завданням, якщо розробник DLL не дає вам.a . Таким чином, він служить переважно цілям закритості, наприклад, так легше отримати додаткові грошові кошти для SDK.

Ще один його недолік - навіть якщо ви використовуєте динамічну бібліотеку, вам потрібно зібрати цю маленьку обгортку статично.

У Linux бінарний інтерфейс dlls є стандартним і відповідає конвенції C. Таким чином, не .aпотрібно, і існує бінарна сумісність між спільними конвертами, в обмін на це ми не маємо переваг користувальницького режиму Microsoft.


1
Будь ласка, надайте доказ того, що функції заглушки можуть змінювати порядок аргументів. Я ніколи не чув про це раніше, і важко повірити, враховуючи, наскільки великі будуть результативні результати.
юг

@yugr Просте переупорядкування регістрів / стеків - це не накладні витрати. Якщо ви використовуєте msvc-компільовані dll з файлів, складених msvc, то очевидно, що не так вже й багато, але це могло б.
петерх

1
Ми можемо заперечити про це, але у випадку, коли ви маєте рацію, слід легко надати довідкові посилання на те, що функції заглушки здатні нетривіально обробляти аргументи (і бути більше, ніж просто манекени батутів).
юг

@yugr Заглушки мають доступ до підписів функції DLL, що робить нетривіальну обробку тривіальною.
петерх

1
Я лише пропоную вам доповнити свою відповідь кількома підтвердженнями щодо того, чим займається бібліотека імпорту (оскільки деякі вимоги сумнівні).
юг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.