Si j'écris un programme C et le compile dans un .exe
fichier, le .exe
le fichier contient des instructions brutes de la machine au CPU. (Je pense).
Si oui, comment est-il possible pour moi d'exécuter le fichier compilé sur n'importe quel ordinateur qui exécute une version moderne de Windows? Chaque famille de CPU a un jeu d'instructions différent. Alors, comment se fait-il qu'un ordinateur exécutant le système d'exploitation approprié puisse comprendre les instructions de mon .exe
fichier, quel que soit son processeur physique?
De plus, souvent sur les sites Web de la page "téléchargement" d'une application, vous avez un téléchargement pour Windows, pour Linux et pour Mac (souvent deux téléchargements pour chaque système d'exploitation, pour les ordinateurs 86 et 64 bits). Pourquoi n'y a-t-il pas beaucoup plus de téléchargements pour chaque famille de CPU?
Les exécutables dépendent à la fois du système d'exploitation et du processeur:
Jeu d'instructions: Les instructions binaires de l'exécutable sont décodées par le CPU selon un jeu d'instructions. La plupart des processeurs grand public prennent en charge les jeux d'instructions x86 ("32 bits") et/ou AMD64 ("64 bits"). Un programme peut être compilé pour l'un de ces ensembles d'instructions, mais pas pour les deux. Il existe des extensions à ces jeux d'instructions; leur prise en charge peut être interrogée lors de l'exécution. De telles extensions offrent un support SIMD, par exemple. L'optimisation des compilateurs peut essayer de tirer parti de ces extensions si elles sont présentes, mais offrent généralement également un chemin de code qui fonctionne sans aucune extension.
Format binaire: L'exécutable doit se conformer à un certain format binaire, ce qui permet au système d'exploitation de charger, initialiser et démarrer correctement le programme. Windows utilise principalement le format Portable Executable, tandis que Linux utilise ELF.
API système: Le programme utilise peut-être des bibliothèques, qui doivent être présentes sur le système d'exécution. Si un programme utilise des fonctions des API Windows, il ne peut pas être exécuté sur Linux. Dans le monde Unix, les API du système d'exploitation central ont été normalisées pour POSIX: un programme utilisant uniquement les fonctions POSIX pourra s'exécuter sur n'importe quel système Unix conforme, tel que Mac OS X et Solaris.
Donc, si deux systèmes offrent les mêmes API et bibliothèques système, s'exécutent sur le même jeu d'instructions et utilisent le même format binaire, un programme compilé pour un système s'exécutera également sur l'autre.
Cependant, il existe des moyens d'obtenir plus de compatibilité:
Les systèmes exécutés sur le jeu d'instructions AMD64 exécuteront généralement également des exécutables x86. Le format binaire indique le mode à exécuter. La gestion des programmes 32 bits et 64 bits nécessite un effort supplémentaire de la part du système d'exploitation.
Certains formats binaires permettent à un fichier de contenir plusieurs versions d'un programme, compilées pour différents jeux d'instructions. Ces "gros binaires" ont été encouragés par Apple lors de la transition de l'architecture PowerPC vers x86.
Certains programmes ne sont pas compilés en code machine, mais en une représentation intermédiaire. Ceci est ensuite traduit à la volée en instructions réelles, ou peut être interprété. Cela rend un programme indépendant de l'architecture spécifique. Une telle stratégie a été utilisée sur le système p UCSD.
Un système d'exploitation peut prendre en charge plusieurs formats binaires. Windows est assez rétrocompatible et prend toujours en charge les formats de l'ère DOS. Sous Linux, Wine permet de charger les formats Windows.
Les API d'un système d'exploitation peuvent être réimplémentées pour un autre système d'exploitation hôte. Sous Windows, Cygwin et le sous-système POSIX peuvent être utilisés pour obtenir un environnement (principalement) compatible POSIX. Sous Linux, Wine réimplémente de nombreuses API Windows.
Les bibliothèques multiplateformes permettent à un programme d'être indépendant des API du système d'exploitation. De nombreux langages de programmation ont des bibliothèques standard qui tentent d'atteindre cet objectif, par exemple Java et C.
Un émulateur simule un système différent en analysant le format binaire étranger, en interprétant les instructions et en proposant une réimplémentation de toutes les API requises. Les émulateurs sont couramment utilisés pour exécuter de vieux jeux Nitendo sur un PC moderne.
99% des PC actuels exécutant Windows ont un processeur 64 bits, qui est également capable d'exécuter un logiciel 32 bits. L'autre pour cent a des processeurs 32 bits. Le logiciel conçu pour les processeurs 32 bits fonctionne donc partout. Le logiciel conçu pour les processeurs 64 bits s'exécute sur tous les PC qui intéressent le créateur du logiciel.
MacOS X et iOS prennent en charge les "gros binaires" - ce que vous téléchargez peut contenir des versions pour différents processeurs. Personne ne construit plus d'applications pour les processeurs PowerPC, mais il y a quelques années, un exécutable pouvait contenir un PowerPC, un Intel 32 bits et une version Intel 64 bits, et le bon serait exécuté. Sur iOS de nos jours, lorsque vous téléchargez une application, vous obtiendrez une version adaptée au processeur de votre appareil. Téléchargez sur un autre appareil et vous obtenez une version différente. Totalement invisible pour l'utilisateur.