A végrehajtható fájl olyan utasításkészlet, amely egy adott feladat végrehajtására készteti a számítógépet [1] . A szöveges fájloktól eltérően , amelyeket emberi olvasásra terveztek, a végrehajtható fájlokat úgy tervezték, hogy a processzor elolvassa (és hajtsa végre) .
Az "utasítások" alatt hagyományosan a gépi kódot értik , amelyet közvetlenül egy fizikai processzor hajt végre [2] . Egyes esetekben egy köztes programnyelvi szkriptből (például bytecode ) származó utasításokat tartalmazó fájl is végrehajthatónak tekinthető.
A végrehajtható fájlokat kézzel is létre lehet hozni gépi nyelven, de ezt a megközelítést általában nem alkalmazzák a kód szintaxisának és olvashatóságának hiánya miatt , így sokkal kényelmesebb a végrehajtható programokat magas szintű programozási nyelven fejleszteni . könnyen érthető. Egyes esetekben a forráskód assembly nyelvű lehet , amely továbbra is ember által olvasható marad, miközben továbbra is úgy tervezték, hogy gépi kódú utasításokkal működjön.
A magas szintű nyelvi kódokat gépi kódú objektumfájlokká fordítják , amelyek nem futtathatók. A kód ezután végrehajtható fájlba kapcsolható. Ezt a folyamatot assembly nyelven linkelésnek nevezik . Az objektumfájlokat az operációs rendszertől függően általában konténer formátumban tárolják (amelyben egy fájlban különböző adatok találhatók), mint például az Executable and Linkable Format (ELF) Unix-szerű rendszerek vagy a Portable Executable (PE) Windows esetén . [3] . Struktúrát ad a natív kódnak azáltal, hogy részekre osztja, például .text (futtatható kód), .data (inicializált globális és statikus változók) és .rodata (csak olvasható adatok, például konstansok és karakterláncok).
A végrehajtható fájlok általában tartalmaznak egy futási környezetet , amely megvalósítja a futási környezet programozási nyelvét és fordítói szolgáltatásait (például ütemezés , kivételkezelés , statikus konstruktorok és destruktorok hívása stb.), valamint az operációs rendszerrel való interakciót, különösen az argumentumátadást, a környezeteket és a visszatérési kódot . más, a programozó által nem meghatározott, de a későbbi munka, például az erőforrások végrehajtása szempontjából értékes programkezdő és -végi függvényekkel. C - ben ezt úgy hajtja végre, hogy a linker a crt0 objektumfájlt egy végrehajtható fájlba kapcsolja, amely tartalmazza a végrehajtási pontot , elvégzi a beállítást, és a futásidejű könyvtár meghívásával kilép [4] .
Így a végrehajtható fájlok általában további gépi kódot tartalmaznak, amelyet a fordító bizonyos módon generál a forráskódból. Ezt bizonyos esetekben célszerű kihagyni, például beágyazott rendszerek fejlesztésekor, vagy egyszerűen csak azért, hogy megértsük, hogyan működik a fordítás, a linkelés és a betöltés. C-ben megkerülheti a szabványos futásidőt egy linker szkript közvetlen megadásával, például meghív mainegy függvényt a program futtatásához, és visszaadja a kilépési állapotot a kernelnek [5] .
Ahhoz, hogy egy operációs rendszer , firmware vagy rendszerbetöltő hajtsa végre , a végrehajtható fájlnak meg kell felelnie az Application Binary Interface (ABI) [6] követelményeinek . Az egyszerű felületeken a fájl a memóriába való betöltésével, a címtér elejére ugrással és onnan végrehajtott végrehajtással történik. Bonyolultabb felületeken a végrehajtható fájlok további adatokkal rendelkeznek, amelyek külön belépési pontot határoznak meg. Például az ELF-ben a belépési pont a fejlécben van megadva e_entry, amely megadja azt a (virtuális) memóriacímet, ahol a végrehajtásnak el kell indulnia. A GCC-ben a bemenetet a linker állítja be a _start.