Position-independent code
Author
Albert FloresPosition-independent code (PIC) (kód nezávislý na umístění) nebo position-independent executable (PIE) (spustitelný program nezávislý na umístění) je ve výpočetní technice strojový kód, který lze provádět při umístění na libovolné adrese ve vnitřní paměti. PIC se často používá pro sdílené knihovny, takže stejný kód z knihovny může být zaveden na libovolnou adresu, která se nepřekrývá s jinou používanou pamětí (například jinou sdílenou knihovnou). PIC se také používal na starších počítačových systémech, které neměly jednotku správy paměti (MMU), aby na systémech bez MMU mohl operační systém chránit aplikace i když jsou v jednom adresním prostoru.
Kód nezávislý na umístění lze provádět bez úprav při umístění na libovolnou adresu v paměti. Tím se liší od absolutního kódu, který musí být zaveden na určitou adresu, aby fungoval správně, a kódu relokabilního při zavedení (LTL), v němž linker nebo zavaděč upraví adresní konstanty v programu po jeho načtení na určitou adresu, aby odpovídaly umístění na této adresa a program bylo možné spustit. +more Generování kódu nezávislého na umístění je často implicitním chováním překladačů, ale může představovat omezení pro použití některých vlastností určitých jazyků, např. zákaz používání absolutních adres (kód nezávislý na umístění musí používat relativní adresy). Instrukce, které se odkazují na absolutní adresy se někdy provádějí rychleji, a jejich nahrazení ekvivalentními instrukcemi, které používají relativní adresy, může způsobit poněkud pomalejší provádění, i když u moderních procesorů je rozdíl prakticky zanedbatelný.
Historie
Strojový kód prvních počítačů, např. IBM 701 (uvedeného 29. +more dubna 1952) nebo UNIVAC I (uvedeného 31. března 1951), byl pozičně závislý: program musel být sestaven tak, aby se mohl načíst a spustit na jedné určité adrese. Tyto počítače neměly operační systém a neumožňovaly multitasking. Programy se načítaly do hlavní paměti (nebo byly dokonce uloženy na magnetickém bubnu a prováděny přímo z něj) a v libovolném okmžiku mohl být spuštěn pouze jeden program. V takovém operačním kontextu nebyl kód nezávislý na umístění potřebný.
IBM System/360 (uvedený 7. dubna 1964) byl již navržen s adresováním podobným jako UNIVAC III, které umožňovalo použití kódu nezávislého na umístění; používá tak zvané zkrácené adresování, při němž se adresy v paměti počítají jako součet obsahu bázového registru a posunutí. +more Na začátku programu musí programátor zajistit adresovatelnost dat naplněním bázového registru; o obsahu bázového registru programátor informuje také assembler pseudoinstrukcí USING. Správnou hodnotu bázového registru lze získat z registru, který obsahuje adresu vstupního bodu programu (typicky R15), nebo je možné použít instrukci [url=https://en. wikibooks. org/wiki/360_Assembly/360_Instructions/BALR]BALR (Branch And Link, Registr form)[/url] (s hodnotou 0 v R2), která uloží adresu následující instrukce do bázového registru, který se pak explicitně nebo implicitně používá v každé instrukci, která se odkazuje na adresy v programu. Může se používat více bázových registrů pro kód nebo data. Takové instrukce zabírají méně paměti, protože místo úplné 24-, 31-, 32- nebo 64bitové adresy (která by zabrala 4 nebo 8 bytů) obsahují číslo bázového registru (kódované 4 bity) a 12bitové posunutí, čili odkaz na dresu vyžaduje pouze dva byty.
Tato technika programování je standardem na systémech IBM S/360 a je dostupná i na novějších systémech až po IBM System/z. Při kódování v jazyce symbolických adres programátor musí zajistit adresovatelnost dat, jak je popsáno výše a další bázové registry používat pro přístup k datům v dynamicky alokované paměti. +more Překladače automaticky zabezpečují tento způsob adresování.
První operační systémy pro IBM System/360 (uvedené v roce 1966) nepoužívaly virtuální paměť (protože ji první modely System S/360 nepodporovaly), ale umožňovaly umístění programů na libovolnou (nebo automaticky zvolenou) adresu v paměti při zavádění příkazem PHASE jazyka Job Control Language.
Na systémech S/360 bez virtuální paměti tak program mohl být zaveden na jakoukoli adresu v paměti, vyžadoval však souvislý úsek paměti tak velký, aby se do něj vešel. Kvůli načítání a uvolňování paměti pro různě velké moduly mohlo docházet k fragmentaci paměti. +more Fragmentaci odstraňuje (resp. redukuje na velikost stránky) použití virtuální paměti.
DOS/360 a OS/360 nepodporoval PIC; tranzientní volání supervisoru (SVC) v OS/360 nemohly obsahovat relokabilní adresní konstanty a mohly se spustit v libovolnému tranzientní oblasti bez provedení relokace.
V řadě IBM System/360 byla virtuální paměť poprvé použita na Modelu 67 (v roce 1965), pro podporu prvního víceúlohového operačního systému se sdílením času TSS/360. Pozdější verze DOS/360 (DOS/VS atd. +more) a pozdější operační systémy firmy IBM již všechny používaly virtuální paměť. Zkrácené adresování zůstalo součástí základní architektury, a je stále výhodné, když je třeba zavést více modulů do stejného virtuálního adresního prostoru.
Pro srovnání, na prvních systémech se segmentací paměti, např. Burroughs MCP na Burroughs B5000 (1961) a Multics (1964), a systémech se stránkováním paměti, např. +more IBM TSS/360 (1967) nebo systémech používajících bázovací a mezní registr, např. GECOS na GE 625 a EXEC na UNIVAC 1107, byl kód také nezávislý na umístění, protože adresy v program byly relativní vůči aktuálnímu segmentu.
Objev dynamického překladu adres (který provádí jednotka správy paměti, MMU) původně omezoval potřebu kódu nezávislého na umístění, protože každý proces mohl mít vlastní nezávislý adresní prostor. Spuštění více úloh současně, které používají stejný kód, způsobuje plýtvání fyzickou pamětí. +more Pokud dvě úlohy spouští zcela identické programy, dynamický překlad adres poskytuje řešení tím, že umožňuje systému jednoduše namapovat konkrétní adresu dvou různých úloh na stejné byty reálné paměti, která obsahuje jedinou kopii programu.
Různé programy mohou sdílet společný kód. Například program pro výpočet výplat a program pro zpracování faktur mohou obsahovat stejný třídicí podprogram. +more Sdílený modul (sdílená knihovna je forma sdíleného modulu) bude načten pouze jednou, a namapován do dvou adresních prostorů.
Technické detaily
Při volání procedur ze sdílené knihovny se typicky používají pomocí malých stubů uložených ve spojovací tabulce procedur, který volají vlastní funkci. To umožňuje především, aby sdílená knihovna mohla dědit některá volání funkcí z dříve načtené knihovny.
Reference na data z kódu nezávislého na umístění se obvykle provádějí nepřímo pomocí Globálních tabulek posunutí , které obsahují adresy všech globálních proměnných, k nimž se přistupuje. Každá překladová jednotka nebo cílový modul má jednu GOT, která je umístěna na pevném posunutí od kód (toto posunutí není známo, dokud knihovna není slinkována). +more Když linker spojuje moduly a vytváří sdílenou knihovnu, slučuje tabulky GOT a nastavuje cílové offsety v kódu, takže není potřeba nastavovat offsety, když se sdílená knihovna později zavádí.
Pozičně nezávislé funkce přistupují ke globálním datům určením absolutní adresy tabulky GOT podle aktuální hodnoty programového čítače. Ta se často zjišťuje voláním fiktivní funkce, při kterém se uloží návratová adresa na zásobník (na architektuře X86), do určitého standardního registru (na architekturách SPARC a MIPS) nebo do speciálního registru (na architektuře IBM POWER/PowerPC/Power ISA), odkud může být pak zkopírována do předdefinovaného standardního registru nebo přímo uložena do standardního registru (architektury PA-RISC, Alfa, ESA/390 a z/Architecture). +more Některé architektury procesorů, např. Motorola 68000, Motorola 6809, WDC 65C816, Knuthův MMIX, ARM a X86-64 umožňují odkazovat se na data posunutím vůči čítači instrukcí. Cílem je, aby kód nezávislý na umístění byl menší a vyžadoval méně registrů, a tedy aby byl efektivnější.
Windows DLL knihovny
Dynamicky linkované knihovny (DLL) v Microsoft Windows používají instrukci CALL s operačním kódem E8 (blízké volání s relativní adresou, posunutí je relativní vůči následující instrukci). Adresy v těchto instrukcích nemusí být při zavádění DLL měněny.
Některé globální proměnné (například pole řetězcových literálů, tabulky virtuálních funkcí) obsahují adresy objektů v datové sekci nebo v kódové sekci dynamické knihovny; adresy uložené v globální proměnné proto musí být aktualizovány, aby obsahovaly adresu, na kterou byla DLL zavedena. Dynamický zavaděč vypočítá adresu, na kterou ukazuje globální proměnná a výsledek uloží do této globální proměnné; tuto úpravu spouští copy-on-write paměťové stránky, která obsahující takovou globální proměnnou. +more Stránky s kódem a stránky s globálními proměnnými that neobsahuje ukazatele kódovat nebo globální data zůstává sdílené mezi procesy. Tato operace musí být provedena v jakémkoli OS, který může načítat dynamické knihovna na libovolnou adresu.
Ve Windows Vista a novějších verzích Windows se relokace DLL knihoven a spustitelných programů provádí správcem paměti jádra, který umožňuje sdílení relokovaných programů více procesy. Obrazy jsou vždy relokované z upřednostňované bázové adresy, čímž se dosahuje Address space layout randomization (ASLR).
Verze Windows před Windows Vista vyžadují, aby systémové knihovny DLL byly během linkování předlinkovány na nekonfliktní pevné adresy, aby nedocházelo k běhové relokaci obrazů. Běhové relokace v těchto starších verzích Windows byly prováděny DLL zavaděčem v kontextu každého procesu, a výsledné relokované části každého obrazu již nemohly být sdílené mezi procesy.
Zpracovávání DLL knihoven ve Windows se odlišuje od dřívější procedury v OS/2, z něhož bylo přebráno. OS/2 používá třetí možnost a snaží se načítat DLL, které nejsou nezávislé na umístění, do vyhrazené „sdílené oblasti“ v paměti, a mapuje je, když jsou zavedeny. +more Všichni uživatelé DLL mohou používat tutéž kopii v paměti.
Multics
V OS Multics má konceptuálně každá procedura kódový segment a spojovací segment. Kódový segment obsahuje pouze kód a spojovací sekci slouží jako šablona pro nový spojovací segment. +more Registr ukazatele 4 (PR4) ukazuje na spojovací segment procedury. Volání procedury napřed uloží PR4 na zásobník a pak do něj načte ukazatel na spojovací segment volané procedury. Volání procedur používá dvojici nepřímých ukazatelů s příznakem, který při prvním volání způsobí přerušení, v jehož obsluze dynamický spojovací mechanismus přidá novou proceduru a její spojovací segment do tabulky známých segmentů , vytvoří nový spojovací segment, zavede čísla segmentů do spojovací sekce volající procedury a vynuluje příznak ve dvojici nepřímých ukazatelů.
TSS
V IBM S/360 Time Sharing System (TSS/360 a TSS/370) může mít každá procedura veřejnou sekci CSECT pouze pro čtení a zapisovatelnou soukromou sekci prototypovou sekci (PSECT). Volající zavede V-konstantu funkce do obecného registru číslo 15 (GR15) a zkopíruje R-konstantu PSECT funkce do 19. +more slova úložné oblasti, na kterou ukazuje GR13.
Dynamický zavaděč nenačítá stránky programu ani neresolvuje adresní konstanty dokud nedojde k prvnímu výpadku stránky.
{{Kotva|PIE}}Spustitelné programy nezávislé na umístění
Spustitelné programy nezávislé na umístění (PIE) jsou spustitelné binární programy tvořená kompletně z kódu nezávislého na umístění. Zatímco některé systémy spouštějí pouze PIC spustitelné programy, existují i jiné důvody, proč jsou používány. +more PIE programy se používají v některých bezpečnostně zaměřených distribucích Linuxu, které umožňují, aby PaX nebo Exec Shield používal Address space layout randomization která znemožňuje útočníkům zjistit, kde je proveditelný kód během bezpečnostních útoků zneužívajících exploity, které vyžadují znalost posunutí proveditelného kód v souboru, např. při return-to-libc útocích.
MacOS a IOS firmy Apple plně podporují PIE spustitelné programy od verze 10. 7 resp. +more 4. 3; pokud spustitelný program není nezávislý na umístění vkládán do Apple App Store, ale program není zamítnut.
OpenBSD používá PIE implicitně na většině architektur od OpenBSD 5. 3 vydaného 1. +more května 2013. Podpora pro PIE ve staticky linkovaných programech, např. spustitelných programech v adresářích /bin a /sbin, byl přidán ke konci roku 2014. OpenSUSE přidalo PIE jako implicitní v únoru 2015. V distribuci Fedora se implicitně vytvářejí programy jako PIE od verze 23. Ubuntu 17. 10 má PIE povoleno implicitně na všech architekturách. Nové profily Gentoo Linuxu nyní podporují PIE implicitně. Od července 2017 povoluje Debian PIE implicitně.
Android povolil podporu PIE v verzi Jelly Bean a odstranil podporu non-PIE linkeru v Lollipop.
Odkazy
Poznámky
Reference
Související články
Dynamický linker * Cílový soubor * Kódový segment
Externí odkazy
[url=http://www. gentoo. +moreorg/proj/en/hardened/pic-guide. xml]Introduction to Position Independent Code[/url] - Úvod do kódu nezávislého na umístění * [url=http://www. gentoo. org/proj/en/hardened/pic-internals. xml]Position Independent Code internals[/url] - Interní detaily kódu nezávislého na umístění * [url=https://web. archive. org/web/20150526050031/http://linux4u. jinr. ru/usoft/WWW/www_debian. org/Documentation/elf/node21. html]Programming in Assembly Language with PIC[/url] - Programování PIC v JSA * [url=https://eklitzke. org/position-independent-executables]The Curious Case of Position Independent Executables[/url] - Zajímavý případ spustitelných programů nezávislých na umístění.
Kategorie:Operační systém Kategorie:Programové knihovny Kategorie:Souborové formáty