Как загрузчик отображает DLL в обработку адресного пространства - PullRequest
8 голосов
/ 03 декабря 2008

Мне любопытно узнать, как загрузчик отображает DLL для обработки адресного пространства. Как загрузчик делает это волшебство. Пример высоко ценится.

Заранее спасибо.

Ответы [ 4 ]

9 голосов
/ 16 июня 2011

Ладно, я предполагаю, что здесь есть сторона Windows. Когда вы загружаете PE-файл, происходит следующее: загрузчик (содержащийся в NTDLL) будет делать следующее:

  1. Найдите каждую из DLL, используя семантику поиска DLL (специфичную для системы и уровня исправления), известные библиотеки DLL отчасти освобождены от этого
  2. Отображение файла в память (MMF), где страницы копируются при записи (CoW)
  3. Перейдите в каталог импорта и для каждого начала импорта (рекурсивно) в точке 1.
  4. Разрешить перемещения, которые в большинстве случаев представляют собой лишь очень ограниченное число объектов, поскольку сам код является позиционно-независимым кодом (PIC)
  5. (IIRC) исправляет EAT от RVA (относительный виртуальный адрес) до VA (виртуальный адрес в текущем пространстве памяти процесса)
  6. Исправление IAT (таблица адресов импорта) для ссылки на импорт с их фактическим адресом в пространстве памяти процесса
  7. Для вызова DLL DLLMain() для EXE создайте поток, начальный адрес которого находится в точке входа PE-файла (это также упрощено, поскольку фактический начальный адрес находится внутри kernel32.dll для процессов Win32)

Теперь, когда вы компилируете код, это зависит от компоновщика, на который ссылается внешняя функция. Некоторые компоновщики создают заглушки, так что - теоретически - попытка проверить адрес функции по NULL всегда скажет, что это не NULL. Это странная вещь, о которой вы должны знать, если и когда ваш компоновщик затронут. Другие ссылаются на запись IAT напрямую, и в этом случае адрес функции без ссылки (например, DLL с задержкой загрузки) может иметь значение NULL, а обработчик SEH затем вызовет помощника с задержкой загрузки и (попытается) разрешить адрес функции перед возобновлением выполнения в указать это не удалось.

В вышеописанном процессе задействовано много красной ленты, которую я упрощенно назвал.

Суть того, что вы хотели знать, заключается в том, что отображение в процессе происходит как MMF , хотя вы можете искусственно имитировать поведение с кучей пространства. Однако, если вы помните пункт о CoW, в этом суть идеи DLL. Фактически, та же самая копия (большей части) страниц библиотеки DLL будет совместно использоваться процессами, которые загружают определенную библиотеку DLL. Страницы, которые не являются общими, - это те, на которые мы писали, например, при разрешении перемещений и подобных вещей. В этом случае каждый процесс имеет - теперь измененную - копию исходной страницы.

И предупреждение относительно упаковщиков EXE на DLL. Они побеждают именно этот механизм CoW, который я описал, поскольку они выделяют пространство для распакованного содержимого DLL в куче процесса, в который загружается DLL. Таким образом, хотя фактическое содержимое файла по-прежнему отображается как MMF и используется совместно, распакованное содержимое занимает один и тот же объем памяти для каждого процесса, загружающего DLL, вместо того, чтобы делиться этим.

7 голосов
/ 03 декабря 2008

Какой уровень детализации вы ищете? На базовом уровне все динамические компоновщики работают примерно одинаково:

  1. Динамические библиотеки компилируются в перемещаемый код (например, с использованием относительных переходов вместо абсолютных).
  2. Компоновщик находит пустое пространство подходящего размера в карте памяти приложения и считывает код DLL и любые статические данные в это пространство.
  3. Динамическая библиотека содержит таблицу смещений для начала каждой экспортируемой функции, а вызовы функций DLL в клиентской программе исправляются во время загрузки с новым адресом назначения в зависимости от того, где была загружена библиотека.
  4. Большинство динамических систем компоновки имеют систему для установки предпочтительного базового адреса для конкретной библиотеки. Если библиотека загружена по ее предпочтительному адресу, то перемещение в шагах 2 и 3 можно пропустить.
3 голосов
/ 03 декабря 2008

Если вам действительно интересно, вам следует прочитать книгу Линкеры и загрузчики .

2 голосов
/ 03 декабря 2008

Предполагая, что это в Windows (DLL намекает на это), вы можете прочитать страницу документации Microsoft Динамическое связывание во время выполнения . подробно не указывает, как DLL отображается в адресном пространстве; Я полагаю, вам не нужно это знать.

...