stringtranslate.com

Перемещение (вычисления)

Перемещение — это процесс назначения адресов загрузки для позиционно-зависимого кода и данных программы и корректировка кода и данных для отражения назначенных адресов. [1] [2] До появления многопроцессорных систем и до сих пор во многих встроенных системах адреса для объектов были абсолютными, начиная с известного местоположения, часто с нуля. Поскольку многопроцессорные системы динамически связываются и переключаются между программами, возникла необходимость в возможности перемещать объекты с использованием позиционно-независимого кода . Компоновщик обычно выполняет перемещение совместно с разрешением символов , процессом поиска файлов и библиотек для замены символических ссылок или имен библиотек фактическими используемыми адресами в памяти перед запуском программы.

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

Сегментация

Объектные файлы сегментируются в различные типы сегментов памяти или секций. Примеры типов сегментов включают сегмент кода (.text) , инициализированный сегмент данных (.data) , неинициализированный сегмент данных (.bss) или другие, установленные программистом, такие как общие сегменты или именованные статические сегменты.

Таблица переездов

Таблица перемещений представляет собой список указателей, созданных транслятором (компилятором или ассемблером ) и сохраненных в объектном или исполняемом файле. Каждая запись в таблице, или «исправление», представляет собой указатель на абсолютный адрес в объектном коде, который должен быть изменен, когда загрузчик перемещает программу, чтобы она ссылалась на правильное местоположение. Исправления предназначены для поддержки перемещения программы как целостной единицы. В некоторых случаях каждое исправление в таблице само по себе относится к базовому адресу, равному нулю, поэтому сами исправления должны быть изменены по мере перемещения загрузчика по таблице. [2]

В некоторых архитектурах исправление, которое пересекает определенные границы (например, границу сегмента) или не выровнено по границе слова, является недопустимым и помечается компоновщиком как ошибка. [3]

DOS и 16-битная Windows

Дальние указатели ( 32-битные указатели с сегментом :offset, используемые для адресации 20-битного пространства памяти размером 640 КБ , доступного программам DOS ), которые указывают на код или данные внутри исполняемого файла DOS ( EXE ), не имеют абсолютных сегментов, поскольку фактический адрес кода/данных зависит от того, где в памяти загружена программа, а это неизвестно, пока программа не загружена.

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

32-битная Windows

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

Как для DLL , так и для EXE-файлов, которые используют рандомизацию адресного пространства (ASLR), технологию предотвращения эксплойтов , представленную в Windows Vista , таблицы перемещения снова становятся обязательными из-за возможности динамического перемещения двоичного файла перед выполнением, даже если они по-прежнему первыми загружаются в виртуальное адресное пространство.

64-битная Windows

При запуске собственных 64-разрядных двоичных файлов в Windows Vista и более поздних версиях ASLR является обязательным [ требуется ссылка ] , и поэтому разделы перемещения не могут быть пропущены компилятором.

Unix-подобные системы

Исполняемый формат Executable and Linkable Format (ELF) и формат разделяемой библиотеки, используемые большинством Unix-подобных систем, позволяют определять несколько типов перемещения. [4]

Процедура переезда

Компоновщик считывает информацию о сегментах и ​​таблицы перемещения в объектных файлах и выполняет перемещение следующим образом:

Пример

Следующий пример использует архитектуру MIX Дональда Кнута и язык ассемблера MIXAL. Принципы одинаковы для любой архитектуры, хотя детали будут меняться.

Смотрите также

Ссылки

  1. ^ "Типы объектного кода". Справочное руководство по загрузчику приложений iRMX 86 (PDF) . Intel . стр. 1-2–1-3. Архивировано (PDF) из оригинала 2020-01-11 . Получено 2020-01-11 . […] Абсолютный код и абсолютный объектный модуль — это код, который был обработан LOC86 для выполнения только в определенном месте памяти. Загрузчик загружает абсолютный объектный модуль только в определенное место, которое модуль должен занимать. Позиционно-независимый код (обычно называемый PIC) отличается от абсолютного кода тем, что PIC может быть загружен в любое место памяти. Преимущество PIC над абсолютным кодом заключается в том, что PIC не требует резервирования определенного блока памяти. Когда загрузчик загружает PIC, он получает сегменты памяти iRMX 86 из пула задания вызывающей задачи и загружает PIC в сегменты. Ограничение, касающееся PIC, заключается в том, что, как и в модели сегментации PL/M-86 COMPACT […], он может иметь только один сегмент кода и один сегмент данных, вместо того, чтобы позволять базовым адресам этих сегментов, а следовательно, и самим сегментам, динамически изменяться. Это означает, что программы PIC обязательно имеют длину менее 64 Кбайт. Код PIC может быть создан с помощью элемента управления BIND LINK86. Локализуемый во время загрузки код (обычно называемый кодом LTL) является третьей формой объектного кода. Код LTL похож на PIC тем, что код LTL может быть загружен в любое место памяти. Однако при загрузке кода LTL загрузчик изменяет базовую часть указателей, так что указатели не зависят от начального содержимого регистров в микропроцессоре. Из-за этой корректировки (корректировки базовых адресов) код LTL может использоваться задачами, имеющими более одного сегмента кода или более одного сегмента данных. Это означает, что программы LTL могут иметь длину более 64 Кбайт. FORTRAN 86 и Pascal 86 автоматически создают код LTL, даже для коротких программ. Код LTL может быть создан с помощью элемента управления BIND LINK86. […]
  2. ^ ab Levine, John R. (2000) [октябрь 1999]. "Глава 1: Связывание и загрузка и Глава 3: Объектные файлы". Линкеры и загрузчики. Серия Моргана Кауфмана по программной инженерии и программированию (1-е изд.). Сан-Франциско, Калифорния, США: Morgan Kaufmann . стр. 5. ISBN 1-55860-496-0. OCLC  42413382. Архивировано из оригинала 2012-12-05 . Получено 2020-01-12 .Код: [1][2] Опечатки: [3]
  3. ^ Borland (1999-09-01) [1998-07-02]. "Статья Borland № 15961: Борьба с сообщениями 'Fixup Overflow'". community.borland.com . База данных технической информации - Продукт: Borland C++ 3.1. TI961C.txt № 15961. Архивировано из оригинала 2008-07-07 . Получено 2007-01-15 .
  4. ^ "Исполняемый и компонуемый формат (ELF)" (PDF) . skyfree.org . Спецификация переносимых форматов стандартов интерфейса инструментов (TIS), версия 1.1. Архивировано (PDF) из оригинала 2019-12-24 . Получено 2018-10-01 .

Дальнейшее чтение