55 votes

Un exécutable aurait-il besoin d'un noyau d'OS pour fonctionner ?

Je sais que lorsque le code source, en C++ par exemple, est compilé, le résultat du compilateur est le code machine (exécutable) qui, je le pensais, était des instructions destinées directement au CPU. Récemment, je me suis renseigné sur les noyaux et j'ai découvert que les programmes ne peuvent pas accéder directement au matériel mais doivent passer par le noyau.

Ainsi, lorsque nous compilons un code source simple, disons avec juste une printf() et la compilation produit le code machine exécutable, chaque instruction de ce code machine sera-t-elle exécutée directement depuis la mémoire (une fois le code chargé en mémoire par le système d'exploitation) ou chaque commande du code machine devra-t-elle encore passer par le système d'exploitation (noyau) pour être exécutée ?

J'ai lu une question similaire . Il n'a pas expliqué si le code machine généré après la compilation est une instruction pour le CPU directement ou s'il doit à nouveau passer par le noyau pour créer l'instruction correcte pour le CPU. En d'autres termes, que se passe-t-il après le chargement du code machine en mémoire ? Passera-t-il par le noyau ou parlera-t-il directement au processeur ?

3voto

LawrenceC Points 70381

Ainsi, lorsque nous compilons un code source simple, disons avec une simple fonction printf(), et que la compilation produit le code machine exécutable, chaque instruction de ce code machine sera-t-elle exécutée directement depuis la mémoire (une fois le code chargé dans la mémoire par le système d'exploitation) ou chaque commande du code machine devra-t-elle encore passer par le système d'exploitation (noyau) pour être exécutée ?

Essentiellement, seuls les appels système vont au noyau. Tout ce qui a trait aux E/S ou à l'allocation/désallocation de mémoire donne généralement lieu à un appel système. Certaines instructions ne peuvent être exécutées qu'en mode noyau et provoquent le déclenchement d'une exception par le CPU. Les exceptions provoquent un passage en mode noyau et un saut vers le code du noyau.

Le noyau ne traite pas chaque instruction d'un programme. Il se contente d'effectuer les appels système et de basculer entre les programmes en cours d'exécution pour partager l'unité centrale.

L'allocation de mémoire en mode utilisateur (sans le noyau) n'est pas possible, si vous accédez à une mémoire à laquelle vous n'avez pas la permission d'accéder, la MMU, préalablement programmée par le noyau, le remarque et provoque une exception de "défaut de segmentation" au niveau du CPU, qui déclenche le noyau, et le noyau tue le programme.

Il n'est pas possible d'effectuer des E/S en mode utilisateur (sans le noyau). Si vous accédez à des ports d'E/S ou à des registres de périphériques, ou à des adresses connectées à des périphériques (l'un ou les deux étant nécessaires pour effectuer des E/S), ceux-ci déclenchent une exception de la même manière.


Un exécutable a-t-il besoin d'un noyau d'OS pour fonctionner ?

Dépend du type d'exécutable.

Les noyaux, en plus de gérer l'accès partagé à la RAM et au matériel, remplissent également une fonction de chargeur.

De nombreux "formats exécutables", comme ELF ou PE, contiennent des métadonnées dans le fichier exécutable en plus du code, et c'est au chargeur de les traiter. Lisez le les détails sanglants du format PE de Microsoft をご覧ください。

Ces exécutables font également référence à des bibliothèques (Windows .dll ou objet partagé Linux .so ) - leur code doit être inclus.

Si votre compilateur produit un fichier qui est censé être traité par un chargeur du système d'exploitation, et que ce chargeur n'est pas là, il ne fonctionnera pas.

  • Pouvez-vous inclure du code qui fait le travail du chargeur ?

Bien sûr. Vous devez convaincre le système d'exploitation d'exécuter votre code brut sans traiter de métadonnées. Si votre code appelle les API du noyau, ça ne fonctionnera toujours pas.

  • Et s'il n'appelle pas les API du noyau ?

Si vous chargez cet exécutable d'une manière ou d'une autre à partir d'un système d'exploitation (c'est-à-dire s'il permet de charger et d'exécuter du code brut), il sera toujours en mode utilisateur. Si votre code accède à des choses qui sont interdites en mode utilisateur, par opposition au mode noyau, comme de la mémoire non allouée ou des adresses/registres de périphériques d'E/S, il se plantera avec des violations de privilèges ou de segments (là encore, les exceptions vont en mode noyau et y sont traitées) et ne fonctionnera toujours pas.

  • Et si vous l'exécutez en mode noyau.

Alors, ça marchera.


3voto

dgnuff Points 351

TL;DR Non.

Le développement Arduino me vient à l'esprit comme un environnement actuel où il n'y a pas de système d'exploitation. Croyez-moi, sur l'une des ces bébés vous n'avez pas l'espace nécessaire pour un système d'exploitation.

De même, les jeux pour la Sega Genesis ne disposaient pas d'un système d'exploitation fourni par Sega. Il suffisait de créer son jeu en assembleur 68K, en écrivant directement sur le métal nu.

Ou là où je me suis fait les dents, en faisant du travail embarqué sur l'Intel 8051. Encore une fois, quand tout ce que vous avez est une eprom 2716 avec une empreinte de 2k * 8, vous n'avez pas la place pour un système d'exploitation.

Bien entendu, cela suppose une utilisation très large du mot "application". En guise de question rhétorique, il convient de se demander si un sketch Arduino est réellement une application.

3voto

Gábor Points 128

Je ne veux pas laisser entendre que les autres réponses ne sont pas bonnes en soi, mais elles fournissent beaucoup trop de détails qui, je le crains, sont encore très obscurs pour vous.

La réponse de base est que le code sera exécuté directement sur le processeur. Et non, le code machine ne "parlera" à personne, c'est l'inverse. Le processeur est le composant actif et tout ce que vous ferez dans votre ordinateur sera fait par ce processeur (je simplifie un peu les choses ici mais c'est bon pour le moment). Le processeur lira le code, l'exécutera et recrachera les résultats, le code machine n'est que de la nourriture pour le processeur.

Votre confusion provient de l'utilisation du mot "matériel". Bien que la division ne soit plus aussi nette qu'avant, il est préférable de penser en termes de périphériques plutôt que d'appeler tout simplement matériel. Ainsi, s'il y a un système d'exploitation ou un système similaire sur votre machine, votre programme doit utiliser ses services pour accéder aux périphériques, mais le processeur lui-même n'est pas un périphérique, c'est l'unité de traitement principale sur laquelle votre programme s'exécute directement.

Les noyaux, les systèmes d'exploitation et les couches intermédiaires similaires ne sont généralement utilisés que dans les grands systèmes où l'on s'attend à ce que plusieurs programmes soient exécutés et où le système doit gérer la manière dont ces programmes peuvent utiliser les périphériques de l'ordinateur (très souvent en même temps). Dans ces cas, les programmes en cours d'exécution ne peuvent accéder à ces périphériques qu'en utilisant le système qui décidera comment les partager et s'assurera qu'il n'y a pas de conflits. Les petits systèmes où il n'y a pas besoin de gestion entre les programmes concurrents parce qu'il n'y en a pas, n'ont souvent aucun système sous-jacent et le programme unique qui tourne normalement sur ces systèmes est plus ou moins libre de faire ce qu'il veut avec les périphériques.

2voto

Walter Mitty Points 614

Le BIOS qui s'exécute dans votre ordinateur à la mise sous tension est un code exécutable stocké en ROM. Il se compose d'instructions machine et de données. Il existe un compilateur (ou assembleur) qui assemble ce BIOS à partir du code source. Il s'agit d'un cas particulier.

Parmi les autres cas particuliers, citons le programme d'amorçage qui charge le noyau et le noyau lui-même. Ces cas particuliers sont généralement codés dans un langage autre que C++.

Dans le cas général, il est beaucoup plus pratique de demander au compilateur de produire des instructions qui invoquent des services système fournis par un noyau ou par des routines de bibliothèque. Cela rend le compilateur beaucoup plus léger. Cela rend également le code compilé plus léger.

À l'autre extrémité du spectre se trouve Java. En Java, le compilateur ne traduit pas le code source en instructions machine, comme on l'entend habituellement. Au contraire, le code source est traduit en "instructions machine" pour une machine imaginaire, appelée la machine virtuelle Java. Avant qu'un programme Java puisse s'exécuter, il doit être combiné avec le runtime Java, qui comprend un interpréteur pour la machine virtuelle Java.

2voto

Au bon vieux temps, votre programme était responsable de tout ce qui devait être fait pendant l'exécution de votre programme, soit en le faisant vous-même, soit en ajoutant à votre programme du code de bibliothèque écrit par d'autres. La seule chose qui tournait à côté de cela dans l'ordinateur était le code à lire dans votre programme compilé - si vous aviez de la chance. Sur certains ordinateurs, le code devait être introduit par des commutateurs avant de pouvoir en faire plus (le processus original de "bootstrap"), ou même tout votre programme introduit de cette façon.

On s'est rapidement aperçu qu'il était agréable d'avoir un code en cours d'exécution capable de charger et d'exécuter un programme. Plus tard, on s'est aperçu que les ordinateurs étaient suffisamment puissants pour permettre l'exécution de plusieurs programmes en même temps en faisant basculer l'unité centrale de traitement entre eux, surtout si le matériel pouvait aider, mais avec la complexité supplémentaire que les programmes ne marchent pas sur les pieds des autres (par exemple, comment gérer plusieurs programmes essayant d'envoyer des données à l'imprimante en même temps ?)

Tout cela a entraîné le déplacement d'une grande quantité de code d'aide des programmes individuels vers le "système d'exploitation", avec une manière standardisée d'invoquer le code d'aide à partir des programmes utilisateurs.

Et c'est là où nous en sommes aujourd'hui. Vos programmes tournent à plein régime, mais dès qu'ils ont besoin de quelque chose géré par le système d'exploitation, ils appellent des routines d'aide fournies par le système d'exploitation, et ce code n'est ni nécessaire ni présent dans les programmes utilisateurs eux-mêmes. Cela inclut l'écriture sur l'écran, la sauvegarde des fichiers, l'accès au réseau, etc.

Des micro-noyaux ont été écrits qui fournissent juste ce qui est nécessaire pour qu'un programme donné puisse fonctionner sans un système d'exploitation complet. Cela présente certains avantages pour les utilisateurs expérimentés tout en abandonnant la plupart des autres. Vous pouvez lire la page Wikipedia à ce sujet. https://en.wikipedia.org/wiki/Microkernel - si vous voulez en savoir plus.

J'ai expérimenté un micro-noyau capable d'exécuter une machine virtuelle Java, mais j'ai découvert par la suite que le meilleur endroit pour cela était Docker.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X