Чому не всі складені коди позиції незалежні?


85

Під час компіляції спільних бібліотек у gcc параметр -fPIC компілює код як незалежний від позиції. Чи є якась причина (продуктивність чи інша), чому ви не скомпілювали б усі позиції коду незалежними?


2
Але Wowest - це не зовсім правильно. Багато викликів та стрибків функцій використовують відносні стрибки, тому їм навіть не потрібна таблиця переходів після переміщення.
Невідомо

дивлячись на згенерований код збірки, виявляється, що адреса функції завантажується, коли код не fpic виявляється, це просто стрибок. Я неправильно розумію ваше твердження?
ojblass,

@ojblass, що я маю на увазі, це те, що деякі стрибки нагадують "стрибнути на 50 інструкцій попереду" або "перейти на 5 інструкцій назад" замість "перейти на 0x400000". Тож стверджувати, що вам доведеться завантажувати адресу щоразу за допомогою -fPIC, не зовсім вірно.
Невідомо

У статті Вікіпедії є хороший опис. В основному, на деяких архітектурах немає прямого способу перейти до відносної адреси. Отже, PIC є дорожчим у використанні на цих арх. Докладнішу інформацію див. У відповіді @ EvanTeran.
Олексій Шолік

Відповіді:


67

Це додає опосередкованості. За допомогою незалежного від позиції коду вам потрібно завантажити адресу вашої функції, а потім перейти до неї. Зазвичай адреса функції вже присутня в потоці інструкцій.


33

У цій статті пояснюється, як працює PIC, та порівнюється з альтернативою - перенесенням часу завантаження . Я думаю, це відповідає вашому питанню.


16
@ Нік: Я не згоден. Якщо це допомагає запитувачеві, це відповідь. Вказівка ​​на відповідну статтю чи дві може надати багато інформації.
Елі Бендерський

5
У цьому дописі немає висновку, лише посилання на статтю. Навіть уявлення про те, що PIC не використовується за замовчуванням через проблеми з продуктивністю.
Нік

10
Хоча це посилання може відповісти на питання, краще включити сюди основні частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться.
Роб

4
@Rob: продуктивною буде пропозиція редагування, а не використання коментарів для ниття. Цій відповіді 4 роки. Тоді у SO були менш жорсткі правила щодо того, як повинна виглядати відповідь
Елі Бендерський

6
Ця публікація з’явилася під "оглядом" із проханням зробити це, і я зробив. Хтось інший позначив це. "Нитячий коментар" автоматично виробляє SO, а не я.
Роб

27

Так, є причини ефективності. Деякі доступні фактично перебувають під іншим непрямим шаром, щоб отримати абсолютну позицію в пам'яті.

Існує також GOT (глобальна таблиця зсувів), яка зберігає зміщення глобальних змінних. Для мене це просто виглядає як таблиця виправлення IAT, яка класифікується як залежна від положення wikipedia та кількома іншими джерелами.

http://en.wikipedia.org/wiki/Position_independent_code


23

Крім прийнятої відповіді. Одна річ, яка сильно шкодить продуктивності коду PIC, - це відсутність "відносної адресації IP" на x86. За допомогою "відносної адресації IP" ви можете запитати дані, які становлять X байт з поточного вказівника інструкцій. Це зробило б код PIC набагато простішим.

Стрибки та дзвінки, як правило, відносно EIP, тому це насправді не створює проблем. Однак для доступу до даних знадобиться трохи додаткових хитрощів. Іноді реєстр буде тимчасово зарезервований як "базовий вказівник" на дані, які вимагає код. Наприклад, поширеною технікою є зловживання роботою викликів на x86:

call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp            ; now ebp holds the address of the first dataword
                   ; this works because the call pushes the **next**
                   ; instructions address
                   ; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way

Цей та інші прийоми додають рівень непрямості до доступу до даних. Наприклад, GOT (глобальна таблиця зсувів), що використовується компіляторами gcc.

x86-64 додав режим "RIP відносний", що робить речі набагато простішими.


1
IIRC MIPS також не має відношення до ПК, крім відносних стрибків
phuclv

1
Це загальний прийом, який використовується в оболонці для отримання адреси, з якої він виконується. Я використовував це в декількох рішеннях CTF.
sherrellbc

2

Оскільки реалізація повністю незалежного від позиції коду додає обмеження до генератора коду, що може запобігти використанню швидших операцій, або додає додаткові кроки для збереження цього обмеження.

Це може бути прийнятним компромісом, щоб отримати багатопроцесорну обробку без системи віртуальної пам’яті, де ви довіряєте процесам не вторгатись у пам’ять один одного і, можливо, доведеться завантажити певний додаток за будь-якою базовою адресою.

У багатьох сучасних системах компроміси з продуктивністю різні, і переїзд навантажувача часто є менш дорогим (він коштує будь-якого часу, коли код завантажується спочатку), ніж найкраще, що може зробити оптимізатор, якщо воно вільне. Крім того, наявність віртуальних адресних просторів приховує в першу чергу більшу частину мотивації незалежності позицій.


1

Крім того, апаратне забезпечення віртуальної пам’яті в більшості сучасних процесорів (використовується більшістю сучасних ОС) означає, що багато коду (всі програми користувацького простору, за винятком химерного використання mmap тощо) не повинні бути незалежними від позиції. Кожна програма отримує власний адресний простір, який, на її думку, починається з нуля.


4
Але навіть з VM-MMU код PIC необхідний для того, щоб одна і та ж бібліотека .so завантажувалася лише один раз в пам'ять, коли вона використовується різними виконуваними файлами.
мммммммм

1

position-independent code має накладні витрати на більшість архітектур, оскільки для цього потрібен додатковий регістр.

Отже, це для виконання.


0

В даний час операційна система та компілятор за замовчуванням роблять весь код як незалежний від позиції код. Спробуйте скомпілювати без прапорця -fPIC, код буде скомпільовано нормально, але ви просто отримаєте попередження. ОС, як Windows, використовує техніку, яка називається відображенням пам'яті для досягнення цього.


-5

Питання датується 2009 роком. Минуло десять років, і тепер весь код фактично не залежить від позиції. Зараз це забезпечується операційними системами та компіляторами. Немає можливості відмовитись. Весь код компілюється за допомогою PIE, а прапорець -no-pic / -no-pie ігнорується, як частина цього виправдання ASLR. Причиною цього є уповільнення раніше швидких програм та продаж нового обладнання під виглядом підвищеної безпеки. Це абсолютно ірраціонально, адже зараз великі обсяги пам'яті дозволяють нам взагалі позбутися пекла динамічного зв’язування, збираючи всі програми статично.

Те саме траплялося і раніше, коли люди мовчки приймали реальний режим та відбирання інших свобод. І я пам’ятаю, MMU зазнає значного уповільнення через перемикання контексту та затримку перекладу адрес. Ви не знайдете MMU у критично важливих системах, таких як ті, що використовуються вченими для вибірки фізичних експериментів.

Ви не скаржитесь, бо навіть не знаєте, що всі ці тренувальні колеса обмежують ваш код. Що я можу сказати? Насолоджуйтесь програмним забезпеченням PIC у 2 рази повільніше! Навіть більше, з появою LLVM, незабаром буде застосовано JIT (керований код), без доступу до вбудованої збірки x86, що ще більше уповільнить будь-який код C / C ++. "Ті, хто жертвує свободою заради безпеки, не заслуговують ні того, ні іншого".


Це лише констатація фактів: 10 років тому ПІК була необов’язковою, але сьогодні вона є типовою та обов’язковою. Я сумніваюся, що код, що не є PIE, буде підтримуватися в наступних випусках ОС. Так само, як підтримка реального режиму була припинена після Windows 9x. Тож питання використовувати чи не використовувати PIC стає більше теоретичною темою інформатики, якщо ви якимось чином не розблокуєте свою ОС і не ввімкнете підтримку для неї. Найголовніше, що люди повинні знати про PIC, - це те, що компілятори до цього часу підтримували статичну компіляцію, і це було досить повільно, і існували статичні версії більшості бібліотек DLL.
SmugLispWeenie

1
Ваші перші пара речень - це лише виклад фактів. Решта - думка, що межує із змовою.
Мітч Ліндгрен

Ну, просто поговоріть з людьми, запитайте їх думку щодо цього. Я особисто виявив, що PIC проти non-PIC також став питанням ідеології. PIC - це програмний еквівалент комунізму, де масово виробляється код, і всі отримують однакову копію. Non-PIC - це програмний еквівалент капіталізму, де існує багато конкуруючих версій одного і того ж коду. Тож люди з більш лівим мисленням підсвідомо підтримують PIC, щоб довести тезу про те, що їхня улюблена ідеологія може спрацювати принаймні в обчислювальній техніці. Ті самі люди не рекомендують вам говорити про використання особисто модифікованого libpng.
SmugLispWeenie

2
Чи можемо ми не мати політичних заяв на веб-сайті з програмування, будь ласка, дякую
Райан МакКемпбелл,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.