Що означають "статично пов'язані" та "динамічно пов'язані"?


229

Я часто чую терміни "статично пов'язаний" і "динамічно пов'язаний", часто посилаючись на код, написаний на C , C ++ або C # . Що вони, про що саме говорять, і що вони пов'язують?

Відповіді:


445

Існує (у більшості випадків дисконтування інтерпретованого коду) два етапи переходу від вихідного коду (те, що ви пишете) до виконуваного коду (що ви запускаєте).

Перша - компіляція, яка перетворює вихідний код в об'єктні модулі.

Друге, що пов'язує, - це те, що поєднує об'єктивні модулі разом, щоб утворювати виконуваний файл.

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

Коли ви статично зв'язуєте файл у виконуваний файл, його вміст включається під час посилання. Іншими словами, вміст файла фізично вставляється у виконуваний файл, який ви будете запускати.

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

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

Статично пов'язані файли 'заблоковані' у виконуваний файл під час посилання, тому вони ніколи не змінюються. Динамічно пов'язаний файл, на який посилається виконуваний файл, може змінитись лише заміною файла на диску.

Це дозволяє оновлювати функціональність без необхідності повторного посилання коду; завантажувач повторно посилається кожного разу, коли ви його запускаєте.

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


Як приклад , давайте розглянемо випадок, коли користувач збирає свій main.cфайл для статичного та динамічного посилання.

Phase     Static                    Dynamic
--------  ----------------------    ------------------------
          +---------+               +---------+
          | main.c  |               | main.c  |
          +---------+               +---------+
Compile........|.........................|...................
          +---------+ +---------+   +---------+ +--------+
          | main.o  | | crtlib  |   | main.o  | | crtimp |
          +---------+ +---------+   +---------+ +--------+
Link...........|..........|..............|...........|.......
               |          |              +-----------+
               |          |              |
          +---------+     |         +---------+ +--------+
          |  main   |-----+         |  main   | | crtdll |
          +---------+               +---------+ +--------+
Load/Run.......|.........................|..........|........
          +---------+               +---------+     |
          | main in |               | main in |-----+
          | memory  |               | memory  |
          +---------+               +---------+

У статичному випадку ви бачите, що основна програма та бібліотека виконання C пов'язані між собою у час зв'язку (розробниками). Оскільки користувач, як правило, не може повторно зв’язати виконуваний файл, він застряг у поведінці бібліотеки.

У динамічному випадку основна програма пов’язана з бібліотекою імпорту програми C (що декларує те, що є в динамічній бібліотеці, але насправді не визначає ). Це дозволяє лінкеру зв’язатись, хоча фактичний код відсутній.

Тоді, під час виконання, завантажувач операційної системи здійснює пізнє з'єднання основної програми з DLL виконання програми C (динамічна бібліотека посилань або спільна бібліотека чи інша номенклатура).

Власник програми C може в будь-який час скинути нову DLL, щоб забезпечити оновлення або виправлення помилок. Як було сказано раніше, це має як переваги, так і недоліки.


11
Виправте мене, якщо я помиляюся, але в Windows програмне забезпечення, як правило, включає власні бібліотеки при встановленні, навіть якщо вони динамічно пов'язані. У багатьох системах Linux з менеджером пакетів багато динамічно пов'язаних бібліотек ("спільних об'єктів") фактично поділяються між програмним забезпеченням.
Пол Фішер

6
@PaulF: такі речі, як звичайні керування Windows, DirectX, .NET і так далі, багато постачаються разом із програмами, тоді як в Linux ви, як правило, використовуєте apt або yum або щось подібне для управління залежностями - значить, ви маєте рацію в цьому сенсі . Виграйте програми, які передають власний код як DLL, як правило, не діляться ними.
paxdiablo

31
У дев’ятому колі пекла є спеціальне місце для тих, хто оновлює свої DLL-файли та порушує сумісність. Так, якщо інтерфейси зникнуть або модифікуються, то динамічне посилання буде падати в купу. Ось чому цього не слід робити. У будь-якому випадку додайте функцію2 () до DLL, але не змінюйте функцію (), якщо люди її використовують. Найкращий спосіб впоратися з цим - перекодувати функцію () таким чином, що вона викликає function2 (), але не змінювати підпис функції ().
paxdiablo

1
@Paul Fisher, я знаю, що це пізно, але ... бібліотека, яка постачається з Windows DLL, не є повною бібліотекою, це лише купа заглушок, які повідомляють лінкеру, що містить DLL. Потім посилання може автоматично вводити інформацію в .exe для завантаження DLL, і символи не відображаються як невизначені.
Марк Викуп від

1
@Santropedro, ви правдиві по всіх підрахунках значення значення lib, імпорту та DLL-імен. Суфікс є лише умовою, тому не читайте занадто багато цього (наприклад, DLL може мати розширення .dllабо .soрозширення) - думайте про відповідь як пояснення понять, а не як точний опис. І, відповідно до тексту, це приклад, що показує статичне та динамічне посилання лише на файли часу виконання C, так що так, це `crt вказує у всіх них.
paxdiablo

221

Я думаю, що хороший відповідь на це питання має пояснити , що зв'язування є .

Коли ви компілюєте якийсь код C (наприклад), він перекладається на машинну мову. Просто послідовність байтів, яка під час запуску змушує процесор додавати, віднімати, порівнювати, "goto", читати пам'ять, записувати пам'ять, подібні речі. Цей матеріал зберігається в об’єктних (.o) файлах.

Зараз, давно, комп'ютерні вчені винайшли цю "підпрограму". Виконайте тут-ось-цю частину коду-і поверніть сюди. Не так давно вони зрозуміли, що найкорисніші підпрограми можуть зберігатися в спеціальному місці та використовуватися будь-якою програмою, яка їм потрібна.

Тепер у перші дні програмістам доведеться пробивати адресу пам'яті, на якій знаходились ці підпрограми. Щось подібне CALL 0x5A62. Це було нудно і проблематично, якщо ці адреси пам’яті колись потрібно змінювати.

Отже, процес був автоматизований. Ви пишете програму, яка дзвонить printf(), і компілятор не знає адреси пам'яті printf. Тож компілятор просто пише CALL 0x0000і додає примітку до об’єктного файлу, що говорить "повинен замінити цей 0x0000 місцем пам'яті printf ".

Статичний зв'язок означає, що програма лінкера (GNU називається ld ) додає printfмашинний код безпосередньо у ваш виконуваний файл і змінює 0x0000 на адресу printf. Це відбувається, коли створений ваш виконуваний файл.

Динамічна зв'язок означає, що вищезазначений крок не відбудеться. У виконаному файлі все ще є примітка, в якій сказано, що "повинен замінити 0x000 місцем пам'яті printf". Завантажувач операційної системи повинен знайти код printf, завантажити його в пам'ять і виправити адресу CALL щоразу, коли програма запускається .

Програми звичайно викликають деякі функції, які будуть статично пов'язані (стандартні функції бібліотеки, як printfправило, статично пов'язані) та інші функції, які динамічно пов'язані. Статичні "стають частиною" виконуваного файлу, а динамічні "приєднуються" під час запуску виконуваного файлу.

У обох методів є переваги та недоліки, а між операційними системами є відмінності. Але оскільки ви не запитували, я закінчу це на цьому.


4
Я теж зробив, однак я маю вибрати лише 1 відповідь.
UnkwnTech

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

1
Вибачте, я не можу запропонувати жодної книги. Спершу слід вивчити мову складання. Тоді Вікіпедія може дати гідний огляд таких тем. Ви можете переглянути ldдокументацію GNU .
Артелій

31

Статистично пов’язані бібліотеки пов'язані в час компіляції. Динамічно пов'язані бібліотеки завантажуються під час виконання. Статичне з'єднання перетворює біт бібліотеки у ваш виконуваний файл. Динамічне посилання пов'язане лише з посиланням на бібліотеку; біти динамічної бібліотеки існують в іншому місці і можуть бути замінені пізніше.


16

Оскільки жоден з перерахованих вище публікацій насправді не показує, як статично щось зв’язати і побачити, що ви це зробили правильно, тому я вирішу це питання:

Проста програма C

#include <stdio.h>

int main(void)
{
    printf("This is a string\n");
    return 0;
}

Динамічно зв’язуйте програму С

gcc simpleprog.c -o simpleprog

І запустіть fileна бінарному:

file simpleprog 

І це покаже, що це динамічно пов'язане щось за рубежем:

"simpleprog: 64-бітний виконуваний файл LSB ELF, x86-64, версія 1 (SYSV), динамічно пов'язаний (використовує спільні libs), для GNU / Linux 2.6.26, BuildID [sha1] = 0xf715572611a8b04f686809d90d1c0d75c6028f0f, не позбавлений"

Натомість давайте на цей раз статично зв’яжемо програму:

gcc simpleprog.c -static -o simpleprog

Запуск файлу на цьому статично пов'язаному бінарному файлі покаже:

file simpleprog 

"simpleprog: 64-розрядний виконуваний файл LSB, x86-64, версія 1 (GNU / Linux), статично пов'язаний, для GNU / Linux 2.6.26, BuildID [sha1] = 0x8c0b12250801c5a7c7434647b7dc65a644d6132b, не позбавлений"

І ви можете бачити, що це щасливо статично пов'язане. На жаль, але не всі бібліотеки просто статично пов'язати таким чином, і це може зажадати великих зусиль, використовуючи libtoolабо вручну зв’язуючи об'єктний код і бібліотеки С.

На щастя, багато вбудованих бібліотек C, як-от, muslпропонують статичні параметри зв'язку майже для всіх, якщо не всіх їхніх бібліотек.

Тепер straceстворений вами бінарний файл ви бачите, що до запуску програми немає доступу до бібліотек:

strace ./simpleprog

Тепер порівняйте з результатами програми, straceщо динамічно пов'язана, і ви побачите, що статично пов'язана напруга версії набагато коротша!


2

(Я не знаю C #, але цікаво мати статичну концепцію зв'язку для мови VM)

Динамічне посилання передбачає знання потрібного функціоналу, на який у вас є лише посилання у вашій програмі. Ви мовно виконуєте час або ОС шукаєте фрагмент коду у файловій системі, мережі чи скомпільованому кеш-коді, узгоджуючи посилання, а потім вживаєте декількох заходів для інтеграції його до свого програмного зображення в пам'яті, наприклад, переїзд. Всі вони робляться під час виконання. Це можна зробити вручну або компілятором. Є можливість оновлення з ризиком зіпсувати (а саме DLL пекло).

Статичне пов'язування робиться під час компіляції, то ви повідомляєте компілятору, де є всі функціональні частини, і доручаєте їм їх інтегрувати. Немає ніякого пошуку, неясності, можливості оновлення без перекомпіляції. Всі ваші залежності фізично однакові із зображенням програми.

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