У розробці програмного забезпечення переміщення — це процес призначення адрес завантаження для позиційно-залежного коду та даних програми і коригування коду та даних відповідно до призначених адрес.
Компонувальник зазвичай виконує переміщення разом із розв'язанням символів — процесом пошуку у файлах і бібліотеках для заміни символічних посилань або імен бібліотек фактичними придатними для використання адресами в пам'яті перед запуском програми.
Переміщення зазвичай виконується компонувальником під час компонування, але також може виконуватися під час завантаження переміщувальним завантажувачем або під час виконання самою запущеною програмою за допомогою самопереміщення.
Сегментація
Об'єктний модуль зазвичай поділяється на різні сегменти пам'яті або типи секцій. Прикладами типів сегментів є сегмент коду (.text), сегмент ініціалізованих даних (.data), сегмент неініціалізованих даних (.bss) або інші, визначені програмістом, такі як спільні сегменти або іменовані статичні сегменти.
Таблиця переміщень Таблиця переміщень — це список адрес, створений компілятором або асемблером і збережений в об'єктному або виконуваному файлі. Кожен запис у таблиці посилається на абсолютну адресу в об'єктному коді, яку необхідно змінити, коли завантажувач переміщує програму, щоб вона посилалася на правильне розташування. Записи в таблиці переміщень називаються виправленнями (fixups) і призначені для підтримки переміщення програми як єдиного цілого. У деяких випадках кожне виправлення в таблиці саме є відносним до базової адреси, що дорівнює нулю, тому самі виправлення потрібно змінювати в міру того, як завантажувач проходить таблицю.
У деяких архітектурах виправлення, яке перетинає певні межі (наприклад, межу сегмента) або не вирівняне за межею слова, є неприпустимим і позначається компонувальником як помилка.
DOS та 16-бітна Windows
Далекі вказівники (32-бітний вказівник із сегмент:зсув, який використовується для адресації 20-бітного адресного простору пам'яті обсягом 640 КБ, доступного програмам DOS) — що вказують на код або дані всередині виконуваного файлу DOS (.EXE) — не мають абсолютних сегментів, оскільки фактична адреса коду або даних залежить від того, де програма завантажується в пам'ять, а це невідомо до моменту завантаження програми.
Натомість сегменти у файлі DOS EXE є відносними значеннями. Ці сегменти потрібно виправити після завантаження виконуваного файлу в пам'ять. Завантажувач EXE використовує таблицю переміщень, щоб знайти сегменти, які потрібно скоригувати.
Windows
У 32-бітних операційних системах Windows не обов'язково надавати таблиці переміщень для EXE-файлів, оскільки вони є першим образом, завантаженим у віртуальний адресний простір, і тому будуть завантажені за бажаною базовою адресою.
Як для DLL, так і для EXE, які використовують рандомізацію розташування адресного простору ASLR — метод утруднення експлойтів, запроваджений у Windows Vista, — таблиці переміщень знову стають обов'язковими через можливість динамічного переміщення двійкового файлу перед його виконанням, навіть попри те, що він усе ще є першим об'єктом, завантаженим у віртуальний адресний простір.
Виконувані файли Windows можуть бути позначені як сумісні з ASLR. У Windows 8 та новіших версіях існує можливість увімкнути ASLR навіть для програм, не позначених як сумісні. Для успішного запуску в цьому середовищі секції переміщень не можуть бути вилучені компілятором.
Unix-подібні системи
Формат Executable and Linkable Format (ELF) для виконуваних файлів і спільних бібліотек, який використовується більшістю Unix-подібних систем, дозволяє визначати кілька типів переміщень.
Подібно до ситуації у Windows, бібліотеки повинні бути переміщуваними (містити позиційно-незалежний код і відповідні таблиці), тоді як виконувані файли можуть бути переміщуваними для ASLR за бажанням. Переміщувані виконувані файли також називаються позиційно-незалежними виконуваними файлами.
Процедура переміщення
Компонувальник зчитує інформацію про сегменти та таблиці переміщень в об'єктних файлах і виконує переміщення шляхом:
об'єднання всіх сегментів спільного типу в один сегмент цього типу; призначення неперекривних адрес часу виконання кожному сегменту та кожному символу, призначаючи всьому коду (функціям) і даним (глобальним змінним) унікальні адреси часу виконання; звернення до таблиці переміщень для зміни посилань на символи в даних та об'єктному коді так, щоб вони вказували на призначені адреси часу виконання.
Приклад Наступний приклад використовує архітектуру MIX та мову асемблера MIXAL Дональда Кнута. Принципи є однаковими для будь-якої архітектури, хоча деталі відрізнятимуться.
(A) Програма SUBR компілюється для створення об'єктного файлу (B), показаного як у вигляді машинного коду, так і у вигляді асемблерного коду. Компілятор може позначити початок скомпільованого коду в довільному місці, часто в позиції 1, як показано на рисунку. Позиція 13 містить машинний код інструкції переходу до оператора ST у позиції 5. (C) Якщо SUBR пізніше компонується з іншим кодом, вона може бути розміщена в іншому місці, ніж 1. У цьому прикладі компонувальник розміщує її в позиції 120. Адресу в інструкції переходу, яка тепер знаходиться в позиції 133, необхідно перемістити, щоб вона вказувала на нове розташування коду оператора ST, тепер 125. [1 61, показане в інструкції, є машинним кодом MIX для представлення 125]. (D) Коли програма завантажується в пам'ять для виконання, вона може бути завантажена в інше місце, ніж те, яке призначив компонувальник. У цьому прикладі SUBR тепер знаходиться в позиції 300. Адресу в інструкції переходу, яка тепер знаходиться в позиції 313, потрібно знову перемістити, щоб вона вказувала на оновлене розташування ST, 305. [4 49 є машинним представленням MIX числа 305].
Альтернативи
Деякі архітектури повністю уникають переміщення, відкладаючи призначення адрес до моменту виконання, наприклад у стекових машинах із арифметикою нульової адреси або в деяких сегментованих архітектурах, де кожна одиниця компіляції завантажується в окремий сегмент.
Див. також
Збирання сміття Relocatable Object Module Format Статична бібліотека
Примітки