Portable Executable

Z Wikipedie, otevřené encyklopedie
Skočit na: Navigace, Hledání

Portable Executable (PE) je souborový formát pro spustitelné soubory (EXE), objektové soubory (OBJ) a dynamické knihovny (DLL) používaný ve 32b a 64b verzích operačního systému Windows. Pojem „portable“ poukazuje na přenositelnost formátu mezi všemi 32b (a 64b) verzemi operačního systému Windows. PE formát je v zásadě datová struktura, která obsahuje informace potřebné pro zavaděč Windows: odkazy na dynamické knihovny (DLL), tabulky API export a import, resource management data a thread-local storage (TLS) data. Na operačním systému NT je PE formát použitý pro soubory EXE, DLL, OBJ, SYS a další. PE je modifikovaná verze Unixového formátu COFF.

Na operačních systémech Windows NT PE v současné době podporuje instrukční sady architektur IA-32, IA-64, a AMD64/EM64T (nebo „x86-64“). Dříve Windows 2000, Windows NT, a tedy i PE podporovaly také instrukční sady architektur MIPS, DEC Alpha a PowerPC. Protože PE je použit na Windows CE, pokračuje v podpoře několika variant architektury MIPS a také ARM a SuperH.

Přehled historie[editovat | editovat zdroj]

Microsoft se přesunul na PE formát s uvedením Windows NT 3.1. Všechny pozdější verze Windows (95, 98, ME) jej podporují. Je zatížený přechodem mezi systémy založenými na DOSu a NT. Např. hlavička PE/COFF stále obsahuje program MS-DOS, který implicitně zobrazí zprávu „This program cannot be run in DOS mode“ (Tento program nemůže být spuštěn v DOS módu). Formát PE se stále vyvíjí spolu s Windows - existují rozšíření jako .NET PE, 64b verze PE32+ (občas PE+) a specifikace pro Windows CE.

Technické detaily[editovat | editovat zdroj]

Soubor PE spočívá v množství hlaviček a sekcí, které společné říkají dynamickému linkeru, jak má být mapován do paměti. Protože soubor obsahuje několik různých sekcí, které potřebují různou ochranu paměti, začátek každé sekce musí být zarovnán na okraj stránky (page boundary). Např. sekce .text (kód programu) je typicky mapována jako spustitelná/pouze ke čtení (execute/readonly) a sekce .data (globální proměnné) jako nespustitelná/pro čtení i zápis (no-execute/readwrite). Nicméně, abychom se vyhnuli prázdnému místu mezi různými sekcemi, sekce nejsou na disku zarovnávány podle stránek. Dynamický linker musí mapovat každou sekci individuálně a přiřadit jí správná práva podle instrukcí v hlavičce.

Jedna sekce je import address table (IAT), ta použita jako vyhledávací tabulka, když aplikace volá funkci Windows API. Protože kompilovaný PE DLL/EXE soubor nemůže dopředu vědět, kde jsou ostatní DLL - to záleží na tom, jak byly umístěny do paměti, je potřeba použít nepřímý skok. Když dynamický linker nahrává moduly a spojuje je, zapíše instrukce skoku do IAT slotů, které ukazují na aktuální umístění cílové funkce. Takto přidá skok navíc za cenu vnitřního volání, snížení výkonu je většinou zanedbatelné a přinese to flexibilitu dynamických knihoven. Pokud kompiler dopředu ví, že volání bude uvnitř modulu (přes dllimport atribut), může vytvořit optimalizovaný kód, který jednoduše má za následek nepřímý opkód call.

PE soubory neobsahují kód nezávislý na pozici. Místo toho jsou kompilovány s preferovanými bázovými adresami a všechny adresy generované kompilátorem/linkerem jsou pevné dány. Pokud PE soubor nemůže být nahrán na preferovanou pozici (protože je už zabraná někým jiným), operační systém změní bázové adresy (rebasing). To zahrnuje přepočítání všech absolutních adres a modifikaci kódu pro použití s novými hodnotami. Loader porovná aktuální a proferované adresy a spočítá rozdíl. Ten je pak přidán k hodnotě preferované adresy a přijde s novou adresou proměnné. Všechna přemístění báze jsou uložena v seznamu a jsou přidána, když je potřeba, k existující poloze v poměti. Výsledný kód je nyní soukromý pro jeden proces a už nelze sdílet, tak jsou ztraceny výhody DLL šetřící paměť. Také se významně sníží rychlost nahrávání modulu. Z tohoto důvodu se snažíme vyhnout se rebázování, kdykoli je to možné, a DLL od Microsoftu mají bázové adresy předpočítané aby se nepřekrývaly. V případě, že není třeba přepočítávat báze, je PE výhodný efektivitou kódu, ale v případě rebázování paměti může být použití nákladné. Opakem je ELF (spustitelný formát souborů pro GNU/Linux), který používá kód plně nezávislý na pozici a tabulku (global offset table), poskytne jednodušší použití paměti v budoucnosti za cenu času spouštění programu.