Архитектурно в чем разница между общим объектом (SO) и библиотекой динамических ссылок (DLL)?

#windows #linux #dll #operating-system #shared-libraries

#Windows #linux #dll -файл #операционная система #разделяемые библиотеки

Вопрос:

Вопрос в значительной степени содержится в названии: с точки зрения реализации на уровне операционной системы, чем отличаются общие объекты и библиотеки DLL?

Причина, по которой я спрашиваю об этом, заключается в том, что я недавно прочитал эту страницу о расширении Python, в которой говорится:

Unix и Windows используют совершенно разные парадигмы для загрузки кода во время выполнения. Прежде чем пытаться создать модуль, который можно динамически загружать, ознакомьтесь с тем, как работает ваша система.

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

В Windows файл библиотеки динамических ссылок (.dll) не имеет непостоянных ссылок. Вместо этого доступ к функциям или данным осуществляется через таблицу поиска. Таким образом, код DLL не обязательно исправлять во время выполнения, чтобы ссылаться на память программы; вместо этого код уже использует таблицу поиска DLL, а таблица поиска изменяется во время выполнения, чтобы указывать на функции и данные.

Кто-нибудь может подробнее рассказать об этом? В частности, я не уверен, что понимаю описание общих объектов, содержащих ссылки на то, что они ожидают найти. Аналогично, DLL звучит для меня практически как один и тот же механизм.

Является ли это полным объяснением того, что происходит? Есть ли лучшие? Есть ли на самом деле какая-либо разница?

Я знаю, как ссылаться на DLL или общий объект, и пару механизмов (списки .def, dllexport / dllimport) для записи DLL, поэтому я явно не ищу инструкции в этих областях; Я больше заинтригован тем, что происходит в фоновом режиме.

(Редактировать: еще один очевидный момент — я знаю, что они работают на разных платформах, используют разные типы файлов (ELF vs PE), несовместимы с ABI и т.д. …)

Комментарии:

1. DLL закрыта, все ее символы разрешены (компоновщик знает, где их найти).

2. Для меня это звучит очень странно. У DLL есть висячие ссылки, конечно, есть. Они должны быть разрешены загрузчиком.

3. Извините, отправил комментарий по ошибке и не смог его отредактировать. Конечно, DLL может иметь непостоянные ссылки, но DLL знает, куда (на какую конкретную другую DLL) указывает каждая из них. В то время как с .so, висячая ссылка разрешается первым символом с таким именем, где бы он ни был найден. Если это происходит в самом исполняемом файле, а не в каком-либо другом .итак, это тоже нормально.

Ответ №1:

DLL — это практически тот же механизм, который используется файлами .so или .dylib (macOS), поэтому очень сложно точно объяснить, в чем различия.

Основное различие заключается в том, что отображается по умолчанию из файлов каждого типа. файлы .so экспортируют связь на уровне языка (gcc), что означает, что (по умолчанию) все символы C amp; c , которые являются «внешними», доступны для связывания при извлечении .so. Это также означает, что, поскольку разрешение файлов .so по сути является этапом связывания, загрузчику все равно, из какого файла .so получен символ. Он просто выполняет поиск в указанных файлах .so в некотором порядке, следуя обычным правилам шага ссылки, которым соответствуют файлы .a.

С другой стороны, DLL-файлы являются функцией операционной системы, полностью отделенной от этапа компоновки языка. MSVC использует файлы .lib для связывания как статических, так и динамических библиотек (каждый файл dll генерирует сопряженный файл .lib, который используется для связывания), поэтому результирующая программа полностью «связана» (с языковой точки зрения) после ее сборки.

Однако на этапе компоновки были разрешены символы в библиотеках, представляющих библиотеки DLL, что позволило компоновщику создать таблицу импорта в PE-файле, содержащую явный список библиотек DLL и точки входа, на которые ссылается каждая библиотека DLL. Во время загрузки Windows не нужно выполнять «ссылку» на разрешение символов из разделяемых библиотек: этот шаг уже был выполнен — загрузчик Windows просто загружает DLL и подключает функции напрямую.

Комментарии:

1. Я понимаю, я думаю, что это имеет смысл. Я оставлю вопрос открытым на день или два, чтобы посмотреть, привлекает ли он какие-либо более подробные ответы, но я думаю, что понял это из этого. Еще раз спасибо.

2. Но разве невозможно иметь несколько взаимозаменяемых DLL-файлов (т. Е. Один и тот же интерфейс, разная реализация) в Windows? Если расположение символов в DLL запечено в исполняемый файл, то как две библиотеки DLL могут иметь одинаковый интерфейс, не имея этих символов в одном и том же расположении? Или они находятся в одном и том же месте? Или такая функциональность возможна только с loadLibrary и т.д.?

3. @cheshirekow: Для статически связанных DLL (тех, которые разрешаются включаемой библиотекой) адреса были исправлены => заменяющая DLL должна иметь одинаковые адреса для каждой экспортируемой функции. Для динамически загружаемых DLL (например, LoadLibrary , COM , …) GetProcAdress() разрешает адрес во время выполнения => вручную!