Составители:
Рубрика:
но упрощает создание генератора кода. Недостатком такого подхода явля-
ется увеличение размеров PE-файлов.
2.1.2.2. Выбор базового адреса образа PE-файла в памяти
Давайте обсудим, каким образом загрузчик определяет базовый ад-
рес, по которому нужно загрузить PE-файл. Для exe-файлов это тривиаль-
ная задача: в заголовках файла присутствует поле ImageBase, содержащее
значение базового адреса. Так как для выполнения exe-файла создается
отдельный процесс со своим виртуальным адресным пространством, то
обычно не возникает никаких проблем с тем чтобы отобразить файл в это
адресное пространство по заданному адресу. Как правило, все exe-файлы
содержат в поле ImageBase значение 0x400000.
А вот выбор базового адреса для dll-файла куда сложнее. Дело в том,
что динамическая библиотека, как правило, загружается в адресное про-
странство уже существующего процесса, и хотя dll-файл тоже содержит
некоторое значение в поле ImageBase, очень часто может так получиться,
что этот адрес уже занят чем-то другим (например, по нему уже загружена
другая динамическая библиотека). Что же делать загрузчику, если он не
может загрузить dll-файл по заданному адресу? Ему ничего не остается,
как загрузить этот файл по какому-то другому адресу. Но тут возникает но-
вая проблема – в файле могут содержаться инструкции с абсолютными ад-
ресами (это, в основном, инструкции абсолютных переходов, инструкции
вызова подпрограмм, а также инструкции для работы с глобальными дан-
ными). При загрузке динамической библиотеки по другому адресу все ад-
реса, содержащиеся в этих инструкциях, становятся неправильными, и за-
грузчик вынужден их поправить. Для того, чтобы загрузчик мог это сде-
лать, в файле содержится таблица релокаций, в которой прописаны RVA
всех абсолютных адресов.
2.1.2.3. Импорт функций
В PE-файле существует специальная секция «.idata», описывающая
функции, который этот файл импортирует из динамических библиотек.
Описание импортируемых функций в секции «.idata» приводит к тому, что
библиотеки загружаются загрузчиком операционной системы еще до за-
пуска программы. В принципе, необязательно описывать каждую импор-
тируемую функцию в этой секции, так как динамические библиотеки
можно загружать с помощью функции LoadLibrary из Win32 API прямо во
время выполнения программы.
В процессе загрузки программы осуществляется связывание (binding)
функций, импортируемых из динамических библиотек. Связывание под-
разумевает загрузку соответствующих динамических библиотек и состав-
ление таблицы адресов импорта (Import Address Table – IAT). Адрес каж-
Структура программных компонентов
39
ный виртуальный адрес элемента в памяти (Relative Virtual Address – RVA)
и смещение элемента в файле (file offset).
RVA некоторого элемента PE-файла – это разность виртуального ад-
реса данного элемента и базового адреса, по которому PE-файл загружен
в память. Например, если файл загружен по адресу 0x400000, и некоторый
элемент в нем располагается по адресу 0x402000, то RVA этого элемента
равен (0x402000 – 0x400000) = 0x2000.
Смещение элемента в файле представляет собой количество байт, ко-
торое надо отсчитать от начала файла, чтобы попасть на начало элемента.
Смещения используются гораздо реже, чем RVA, потому что основное их
назначение состоит в обеспечении соответствия положения секций PE-
файла в файле на диске и в памяти.
Загрузчик формирует образ PE-файла в памяти таким образом, что
соблюдается следующее правило: пусть ox и oy – смещения каких-то эле-
ментов в файле, а rx и ry – RVA этих элементов, тогда если ox < oy, то
rx < ry.
2.1.2.1. Секции
Секция в PE-файле представляет либо код, либо некоторые данные
(глобальные переменные, таблицы импорта и экспорта, ресурсы, таблица
релокаций). Каждая секция имеет набор атрибутов, задающий ее свойст-
ва. Атрибуты секции определяют, доступна ли секция для чтения и запи-
си, содержит ли она исполняемый код, должна ли она оставаться в памя-
ти после загрузки исполняемого файла, могут ли различные процессы ис-
пользовать один экземпляр этой секции и т.д.
Исполняемый файл всегда содержит, по крайней мере, одну секцию,
в которой помещен исполняемый код. Кроме этого, как правило, в испол-
няемом файле содержится секция с данными, а динамические библиотеки
обязательно включают отдельную секцию с таблицей релокаций.
Каждая секция имеет имя. Оно не используется загрузчиком и пред-
назначено главным образом для удобства человека. Разные компиляторы
и компоновщики дают секциям различные имена. Например, компонов-
щик от Microsoft размещает код в секции «.text», константы – в секции
«.rdata», таблицы импорта и экспорта – в секциях «.idata» и «.edata», таб-
лицу релокаций – в секции «.reloc», ресурсы – в секции «.rsrc». В то же
время компоновщик фирмы Borland использует имена «CODE» для сек-
ций, содержащих код, и «DATA» для секций с данными.
Выравнивание секций в исполняемом файле на диске и в образе фай-
ла в памяти чаще всего отличается. В памяти они, как правило, выровне-
ны по границам страниц. В принципе, возможно сгенерировать PE-файл
с одинаковым выравниванием секций как на диске, так и в памяти. Сме-
щения элементов в таком файле будут совпадать с их RVA, что существен-
38
CIL и системное программирование в Microsoft .NET
38 CIL и системное программирование в Microsoft .NET Структура программных компонентов 39 ный виртуальный адрес элемента в памяти (Relative Virtual Address – RVA) но упрощает создание генератора кода. Недостатком такого подхода явля- и смещение элемента в файле (file offset). ется увеличение размеров PE-файлов. RVA некоторого элемента PE-файла – это разность виртуального ад- реса данного элемента и базового адреса, по которому PE-файл загружен 2.1.2.2. Выбор базового адреса образа PE-файла в памяти в память. Например, если файл загружен по адресу 0x400000, и некоторый Давайте обсудим, каким образом загрузчик определяет базовый ад- элемент в нем располагается по адресу 0x402000, то RVA этого элемента рес, по которому нужно загрузить PE-файл. Для exe-файлов это тривиаль- равен (0x402000 – 0x400000) = 0x2000. ная задача: в заголовках файла присутствует поле ImageBase, содержащее Смещение элемента в файле представляет собой количество байт, ко- значение базового адреса. Так как для выполнения exe-файла создается торое надо отсчитать от начала файла, чтобы попасть на начало элемента. отдельный процесс со своим виртуальным адресным пространством, то Смещения используются гораздо реже, чем RVA, потому что основное их обычно не возникает никаких проблем с тем чтобы отобразить файл в это назначение состоит в обеспечении соответствия положения секций PE- адресное пространство по заданному адресу. Как правило, все exe-файлы файла в файле на диске и в памяти. содержат в поле ImageBase значение 0x400000. Загрузчик формирует образ PE-файла в памяти таким образом, что А вот выбор базового адреса для dll-файла куда сложнее. Дело в том, соблюдается следующее правило: пусть ox и oy – смещения каких-то эле- что динамическая библиотека, как правило, загружается в адресное про- ментов в файле, а rx и ry – RVA этих элементов, тогда если ox < oy, то странство уже существующего процесса, и хотя dll-файл тоже содержит rx < ry. некоторое значение в поле ImageBase, очень часто может так получиться, что этот адрес уже занят чем-то другим (например, по нему уже загружена 2.1.2.1. Секции другая динамическая библиотека). Что же делать загрузчику, если он не Секция в PE-файле представляет либо код, либо некоторые данные может загрузить dll-файл по заданному адресу? Ему ничего не остается, (глобальные переменные, таблицы импорта и экспорта, ресурсы, таблица как загрузить этот файл по какому-то другому адресу. Но тут возникает но- релокаций). Каждая секция имеет набор атрибутов, задающий ее свойст- вая проблема – в файле могут содержаться инструкции с абсолютными ад- ва. Атрибуты секции определяют, доступна ли секция для чтения и запи- ресами (это, в основном, инструкции абсолютных переходов, инструкции си, содержит ли она исполняемый код, должна ли она оставаться в памя- вызова подпрограмм, а также инструкции для работы с глобальными дан- ти после загрузки исполняемого файла, могут ли различные процессы ис- ными). При загрузке динамической библиотеки по другому адресу все ад- пользовать один экземпляр этой секции и т.д. реса, содержащиеся в этих инструкциях, становятся неправильными, и за- Исполняемый файл всегда содержит, по крайней мере, одну секцию, грузчик вынужден их поправить. Для того, чтобы загрузчик мог это сде- в которой помещен исполняемый код. Кроме этого, как правило, в испол- лать, в файле содержится таблица релокаций, в которой прописаны RVA няемом файле содержится секция с данными, а динамические библиотеки всех абсолютных адресов. обязательно включают отдельную секцию с таблицей релокаций. Каждая секция имеет имя. Оно не используется загрузчиком и пред- 2.1.2.3. Импорт функций назначено главным образом для удобства человека. Разные компиляторы В PE-файле существует специальная секция «.idata», описывающая и компоновщики дают секциям различные имена. Например, компонов- функции, который этот файл импортирует из динамических библиотек. щик от Microsoft размещает код в секции «.text», константы – в секции Описание импортируемых функций в секции «.idata» приводит к тому, что «.rdata», таблицы импорта и экспорта – в секциях «.idata» и «.edata», таб- библиотеки загружаются загрузчиком операционной системы еще до за- лицу релокаций – в секции «.reloc», ресурсы – в секции «.rsrc». В то же пуска программы. В принципе, необязательно описывать каждую импор- время компоновщик фирмы Borland использует имена «CODE» для сек- тируемую функцию в этой секции, так как динамические библиотеки ций, содержащих код, и «DATA» для секций с данными. можно загружать с помощью функции LoadLibrary из Win32 API прямо во Выравнивание секций в исполняемом файле на диске и в образе фай- время выполнения программы. ла в памяти чаще всего отличается. В памяти они, как правило, выровне- В процессе загрузки программы осуществляется связывание (binding) ны по границам страниц. В принципе, возможно сгенерировать PE-файл функций, импортируемых из динамических библиотек. Связывание под- с одинаковым выравниванием секций как на диске, так и в памяти. Сме- разумевает загрузку соответствующих динамических библиотек и состав- щения элементов в таком файле будут совпадать с их RVA, что существен- ление таблицы адресов импорта (Import Address Table – IAT). Адрес каж-
Страницы
- « первая
- ‹ предыдущая
- …
- 24
- 25
- 26
- 27
- 28
- …
- следующая ›
- последняя »