Что означает «статически связанное» и «динамически связанное»?

Я часто слышу термины «статически связанные» и «динамически связанные», часто ссылаясь на код, написанный на C , C ++ или C # , но я ничего не знаю об этом. Что они, о чем именно они говорят, и что они связывают?

5 Solutions collect form web for “Что означает «статически связанное» и «динамически связанное»?”

Есть (в большинстве случаев, при расчете интерпретируемого кода) два этапа при получении из исходного кода (что вы пишете) исполняемому коду (что вы запускаете).

Первая – это компиляция, которая превращает исходный код в объектные модули.

Во-вторых, связывание – это то, что объединяет объектные модули вместе для формирования исполняемого файла.

Различие заключается в том, что, помимо прочего, позволяет включить сторонние библиотеки в ваш исполняемый файл, если вы не видите их исходный код (например, библиотеки для доступа к базе данных, сетевые коммуникации и графические интерфейсы пользователя) или для компиляции кода на разных языках (например, 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 связаны друг с другом во время соединения (разработчиками). Так как пользователь обычно не может повторно связать исполняемый файл, они застряли в поведении библиотеки.

В динамическом случае основная программа связана с библиотекой импорта времени выполнения (то, что объявляет то, что находится в динамической библиотеке, но на самом деле не определяет ее). Это позволяет компоновщику связываться, даже если фактический код отсутствует.

Затем во время выполнения загрузчик операционной системы выполняет позднюю привязку основной программы к DLL с исполняемой средой C (библиотека динамических ссылок или разделяемая библиотека или другая номенклатура).

Владелец среды выполнения C может в любой момент отказаться от новой библиотеки DLL для обновления или исправления ошибок. Как было сказано ранее, это имеет как преимущества, так и недостатки.

Я думаю, что хороший ответ на этот вопрос должен объяснить, что такое связь.

Когда вы компилируете некоторый код C (например), он переводится на машинный язык. Просто последовательность байтов, которая при запуске заставляет процессор добавлять, вычитать, сравнивать, «переходить», читать память, записывать память, что-то вроде этого. Этот материал хранится в объектных (.o) файлах.

Теперь, давно, компьютерные ученые изобрели эту «подпрограмму». Выполнить-это-кусок-оф-кода и обратный-сюда. Незадолго до того, как они поняли, что наиболее полезные подпрограммы могут храниться в специальном месте и использоваться любой программой, которая в них нуждается.

Теперь в первые дни программисты должны были бы пробить по адресу памяти, на котором были расположены эти подпрограммы. Что-то вроде CALL 0x5A62 . Это было утомительно и проблематично, если бы эти адреса памяти нуждались в изменении.

Таким образом, процесс был автоматизирован. Вы пишете программу, которая вызывает printf() , и компилятор не знает адрес памяти printf . Таким образом, компилятор просто пишет CALL 0x0000 и добавляет примечание к объекту, в котором говорится: «Необходимо заменить это 0x0000 на место памяти printf ».

Статическая связь означает, что программа-компоновщик (один из GNU называется ld ) добавляет машинный код printf непосредственно в ваш исполняемый файл и изменяет 0x0000 на адрес printf . Это происходит, когда ваш исполняемый файл создается.

Динамическая связь означает, что вышеуказанный шаг не выполняется. В исполняемом файле все еще есть заметка, в которой говорится, что «необходимо заменить 0x000 на ячейку памяти printf». Загрузчик операционной системы должен найти код printf, загрузить его в память и исправить адрес CALL при каждом запуске программы .

Обычно для программ вызывать некоторые функции, которые будут статически связаны (стандартные библиотечные функции, такие как printf , обычно статически связаны) и другие функции, которые динамически связаны. Статические «становятся частью» исполняемого файла, а динамические «присоединяются» при запуске исполняемого файла.

Существуют преимущества и недостатки обоих методов, и существуют различия между операционными системами. Но так как вы не спросили, я закончу это здесь.

Статически связанные библиотеки связаны во время компиляции. Динамически связанные библиотеки загружаются во время выполнения. Статическая привязка выпекает бит библиотеки в ваш исполняемый файл. Динамическое связывание только печет в ссылке на библиотеку; биты для динамической библиотеки существуют в другом месте и могут быть заменены позже.

Поскольку ни одна из вышеперечисленных сообщений фактически не показывает, как статически связать что-то и увидеть, что вы сделали это правильно, поэтому я рассмотрю эту проблему:

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

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

Динамически связывать программу C

 gcc simpleprog.c -o simpleprog 

И запустите file в двоичном формате:

 file simpleprog 

И это покажет, что динамически связано что-то вроде:

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

Вместо этого давайте статически связать программу на этот раз:

 gcc simpleprog.c -static -o simpleprog 

Запуск файла в этом статически связанном двоичном файле будет выглядеть так:

 file simpleprog 

«simpleprog: 64-разрядный LSB-файл ELF, x86-64, версия 1 (GNU / Linux), статически связанная для GNU / Linux 2.6.26, BuildID [sha1] = 0x8c0b12250801c5a7c7434647b7dc65a644d6132b, не разделенная”

И вы можете видеть, что это счастливо статически связано. К сожалению, однако, не все библиотеки просто статически связывают этот путь и могут потребовать расширенных усилий с помощью libtool или связывания объектного кода и библиотек C вручную.

К счастью, многие встроенные библиотеки C, такие как musl предлагают статические ссылки для почти всех, если не всех их библиотек.

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

 strace ./simpleprog 

Теперь сравните с выходом strace в динамически связанной программе, и вы увидите, что стрейч статически связанной версии намного короче!

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

Динамическое связывание подразумевает знание того, как найти требуемую функциональность, в которой у вас есть только ссылка из вашей программы. Вы используете язык или ОС для поиска fragmentа кода в файловой системе, сети или скомпилированном кеше кода, сопоставляя ссылку, а затем предпринимаете несколько мер для ее интеграции с вашим программным изображением в памяти, например перемещением. Все они выполняются во время выполнения. Это можно сделать либо вручную, либо компилятором. Существует возможность обновления с риском взлома (а именно, аддона DLL).

Статическое связывание выполняется во время компиляции, которое вы сообщаете компилятору, где находятся все функциональные части, и инструктируйте его интегрировать их. Нет поиска, нет двусмысленности, нет возможности обновляться без перекомпиляции. Все ваши зависимости физически совпадают с вашим программным изображением.

Interesting Posts

Почему «защищенный» модификатор в Java разрешает доступ к другим classам в одном пакете?

Почему многие classы Collection в Java расширяют абстрактный class и реализуют интерфейс?

Как форматировать вывод печати или строку в фиксированную ширину?

Передача по ссылке в C

Как автоматически обрезать и центрировать изображение

Значение порта 0 в выводе netstat

XSL-FO: принудительная обертка на табличных записях

Когда ssh'ing, как я могу установить переменную среды на сервере, которая изменяется от сеанса к сеансу?

Как перечислить пользователей и группы группы безопасности AD, если не администратор домена

Как заставить applescript работать с Preview в Snow Leopard?

Несколько приложений, использующих одну и ту же базу данных входа в систему, регистрируя друг друга

Защищает ли RAID 1 от коррупции?

VirtualBox: Windows 7 говорит, что это не настоящая

Обходное решение для вывода аргумента шаблона в невыводимом контексте

В чем разница между 0.0.0.0, 127.0.0.1 и localhost?

Давайте будем гением компьютера.