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 ?

89voto

sawdust Points 16268

En tant que personne ayant écrit des programmes qui s'exécutent sans système d'exploitation, je propose une réponse définitive.

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

Cela dépend de la façon dont ce programme a été écrit et construit.
Vous pourriez écrire un programme (en supposant que vous ayez les connaissances nécessaires) qui ne nécessite pas du tout de système d'exploitation.
Un tel programme est décrit comme autonome .
Les chargeurs de démarrage et les programmes de diagnostic sont des utilisations typiques des programmes autonomes.

Cependant, le programme typique écrit et construit dans un environnement de système d'exploitation hôte s'exécutera par défaut dans ce même environnement de système d'exploitation hôte.
Des décisions et des actions très explicites sont nécessaires pour écrire et construire un programme autonome.


... la sortie du compilateur est le code machine (exécutable) qui, je le pensais, était des instructions pour le CPU directement.

Correct.

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.

Il s'agit d'une restriction imposée par un mode du processeur que le système d'exploitation utilise pour exécuter les programmes, et facilitée par certains outils de construction tels que les compilateurs et les bibliothèques.
Il ne s'agit pas d'une limitation intrinsèque à tous les programmes jamais écrits.


Ainsi, lorsque nous compilons un code source simple, par exemple avec une simple fonction printf(), et que la compilation produit le code machine exécutable, chaque instruction de ce code machine sera-t-elle directement exécutée 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 ?

Chaque instruction est exécutée par le CPU.
Une instruction qui n'est pas prise en charge ou qui est illégale (par exemple, un processus ne dispose pas de privilèges suffisants) provoquera une exception immédiate, et le CPU exécutera à la place une routine pour gérer cette condition inhabituelle.

A printf() ne doit pas être utilisée comme un exemple de "code source simple" .
La traduction d'un langage de programmation de haut niveau orienté objet en code machine peut ne pas être aussi triviale que vous le laissez entendre.
Ensuite, vous choisissez l'une des fonctions les plus complexes d'une bibliothèque d'exécution qui effectue des conversions de données. et I/O.

Notez que votre question stipule un environnement avec un OS (et une bibliothèque d'exécution).
Une fois que le système a démarré et que le système d'exploitation a pris le contrôle de l'ordinateur, des restrictions sont imposées sur ce qu'un programme peut faire (par exemple, les E/S doivent être effectuées par le système d'exploitation).
Si vous prévoyez d'exécuter un programme autonome (c'est-à-dire sans système d'exploitation), vous ne devez pas démarrer l'ordinateur pour exécuter le système d'exploitation.


... que se passe-t-il après que le code machine soit chargé en mémoire ?

Cela dépend de l'environnement.

Pour un programme autonome, il peut être exécuté, c'est-à-dire que le contrôle est transféré en sautant à l'adresse de départ du programme.

Pour un programme chargé par le système d'exploitation, le programme doit être lié dynamiquement aux bibliothèques partagées dont il dépend. Le système d'exploitation doit créer un espace d'exécution pour le processus qui exécutera le programme.

Passera-t-il par le noyau ou parlera-t-il directement au processeur ?

Le code machine est exécuté par l'unité centrale.
Ils ne "passer par le noyau" mais ils ne le font pas non plus "parler au processeur" .
Le code machine (composé du code op et des opérandes) est une instruction adressée au CPU qui est décodée et l'opération est effectuée.

Peut-être que le prochain sujet que vous devriez étudier est Modes de fonctionnement du CPU .

40voto

Ana cleto Points 11

Le noyau est "juste" plus de code. C'est juste que ce code est une couche qui vit entre les parties les plus basses de votre système et le matériel réel.

Tout fonctionne directement sur le CPU, il suffit de passer par des couches de celui-ci pour faire quoi que ce soit.

Votre programme "a besoin" du noyau de la même manière qu'il a besoin des bibliothèques C standard pour utiliser le système de gestion de l'information. printf en premier lieu.

Le code réel de votre programme s'exécute sur l'unité centrale, mais les branchements que ce code effectue pour imprimer quelque chose à l'écran passent par le code de l'interface C printf par l'intermédiaire de divers autres systèmes et interpréteurs, qui effectuent chacun leur propre traitement pour déterminer la valeur exacte de la fonction comment hello world! s'imprime réellement sur votre écran.

Supposons que vous ayez un programme de terminal fonctionnant sur un gestionnaire de fenêtre de bureau, fonctionnant sur votre noyau qui, à son tour, fonctionne sur votre matériel.

Il y a beaucoup d'autres choses qui se passent, mais restons simples...

  1. Dans votre programme terminal, vous exécutez votre programme pour imprimer hello world!
  2. Le terminal voit que le programme a écrit (via les routines de sortie C) hello world! à la console
  3. Le programme de terminal s'adresse au gestionnaire de fenêtre du bureau en disant "J'ai obtenu hello world! écrit à moi, pouvez-vous le mettre en position x , y s'il vous plaît ?"
  4. Le gestionnaire de fenêtres du bureau s'adresse au noyau en disant "un de mes programmes veut que ton périphérique graphique mette du texte à cette position, fais-le mec !".
  5. Le noyau transmet la demande au pilote de périphérique graphique, qui la formate de manière à ce que la carte graphique puisse la comprendre.
  6. Selon la façon dont la carte graphique est connectée, d'autres pilotes de périphériques du noyau doivent être appelés pour transmettre les données sur les bus de périphériques physiques tels que PCIe, en s'assurant par exemple que le bon périphérique est sélectionné et que les données peuvent passer par les ponts ou les convertisseurs appropriés.
  7. Le matériel affiche des trucs.

<strong>Il s'agit d'une simplification massive à des fins de description uniquement. Voici les dragons.</strong>

En fait, tout ce que vous faites qui nécessite un accès matériel, qu'il s'agisse d'un écran, de blocs de mémoire, de bits de fichiers ou de quoi que ce soit d'autre a de passer par un pilote de périphérique dans le noyau pour découvrir exactement comment pour parler à l'appareil concerné. Qu'il s'agisse d'un pilote de système de fichiers au-dessus d'un pilote de contrôleur de disque dur SATA, lui-même situé au-dessus d'un périphérique de pont PCIe.

Le noyau sait comment relier tous ces dispositifs entre eux et présente une interface relativement simple permettant aux programmes de faire des choses sans avoir à savoir comment faire toutes ces choses eux-mêmes.

Les gestionnaires de fenêtres de bureau fournissent une couche qui permet aux programmes de ne pas avoir à savoir comment dessiner les fenêtres et de bien jouer avec d'autres programmes qui essaient d'afficher des choses en même temps.

Enfin, le programme de terminal signifie que votre programme n'a pas besoin de savoir comment dessiner une fenêtre, ni comment parler au pilote de carte graphique du noyau, ni toute la complexité liée à la gestion des tampons d'écran et de la synchronisation de l'affichage et à l'agitation des lignes de données vers l'écran.

Tout est géré par des couches et des couches de code.

21voto

Jamie Hanrahan Points 22184

Cela dépend de l'environnement. Dans de nombreux ordinateurs plus anciens (et plus simples !), comme l'IBM 1401, la réponse serait "non". Votre compilateur et votre éditeur de liens émettaient un "binaire" autonome qui fonctionnait sans aucun système d'exploitation. Lorsque votre programme s'arrêtait de fonctionner, vous en chargiez un autre, qui fonctionnait également sans système d'exploitation.

Un système d'exploitation est nécessaire dans les environnements modernes car vous n'exécutez pas un seul programme à la fois. Le partage du ou des cœurs de l'unité centrale, de la mémoire vive, du périphérique de stockage de masse, du clavier, de la souris et de l'écran, entre plusieurs programmes à la fois, nécessite une coordination. Le système d'exploitation s'en charge. Ainsi, dans un environnement moderne, votre programme ne peut pas simplement lire et écrire sur le disque ou le SSD, il doit demander au système d'exploitation de le faire en son nom. Le système d'exploitation reçoit ces demandes de tous les programmes qui veulent accéder au périphérique de stockage, met en œuvre des éléments tels que les contrôles d'accès (il ne peut pas permettre aux utilisateurs ordinaires d'écrire dans les fichiers du système d'exploitation), les met en file d'attente sur le périphérique et trie les informations renvoyées vers les bons programmes (processus).

En outre, les ordinateurs modernes (contrairement au 1401, par exemple) prennent en charge la connexion d'une très grande variété de périphériques d'E/S, et pas seulement ceux qu'IBM vous vendait autrefois. Votre compilateur et votre éditeur de liens ne peuvent pas connaître toutes les possibilités. Par exemple, votre clavier peut être interfacé via PS/2, ou USB. Le système d'exploitation vous permet d'installer des "pilotes de périphérique" spécifiques aux périphériques qui savent comment parler à ces périphériques, mais qui présentent au système d'exploitation une interface commune pour la classe de périphérique. Ainsi, votre programme, et même le système d'exploitation, n'ont pas à faire quoi que ce soit de différent pour recevoir des frappes d'un clavier USB ou PS/2, ou pour accéder, par exemple, à un disque SATA local ou à un périphérique de stockage USB ou à un stockage situé quelque part sur un NAS ou un SAN. Ces détails sont gérés par les pilotes de périphériques pour les différents contrôleurs de périphériques.

Pour les périphériques de stockage de masse, le système d'exploitation fournit sur chacun d'eux un pilote de système de fichiers qui présente la même interface pour les répertoires et les fichiers, quels que soient l'endroit et la manière dont le stockage est mis en œuvre. Là encore, le système d'exploitation se préoccupe des contrôles d'accès et de la sérialisation. En général, par exemple, le même fichier ne devrait pas être ouvert en écriture par plus d'un programme à la fois sans passer par quelques étapes (mais les lectures simultanées sont généralement acceptables).

Donc, dans un environnement moderne polyvalent, oui, vous avez vraiment besoin d'un système d'exploitation. Mais même aujourd'hui, il existe des ordinateurs tels que les contrôleurs en temps réel qui ne sont pas assez compliqués pour en avoir besoin.

Dans l'environnement Arduino, par exemple, il n'y a pas vraiment de système d'exploitation. Bien sûr, il y a un tas de code de bibliothèque que l'environnement de construction incorpore dans chaque "binaire" qu'il construit. Mais comme il n'y a pas de persistance de ce code d'un programme à l'autre, il ne s'agit pas d'un système d'exploitation.

10voto

Link Points 81

Je pense que de nombreuses réponses comprennent mal la question, qui se résume à ceci :

Un compilateur produit du code machine. Ce code machine est-il exécuté directement par une unité centrale, ou est-il "interprété" par le noyau ?

En gros, le CPU exécute directement le code machine . Il serait nettement plus lent de demander au noyau d'exécuter toutes les applications. Cependant, il y a quelques mises en garde.

  1. Lorsqu'un système d'exploitation est présent, les programmes d'application ne peuvent généralement pas exécuter certaines instructions ou accéder à certaines ressources. Par exemple, si une application exécute une instruction qui modifie la table d'interruption du système, l'unité centrale de traitement sautera plutôt vers un gestionnaire d'exception du système d'exploitation afin de mettre fin à l'application fautive. De même, les applications ne sont généralement pas autorisées à lire/écrire dans la mémoire du périphérique. (L'accès à ces régions de mémoire spéciales est la façon dont le système d'exploitation communique avec des périphériques tels que la carte graphique, l'interface réseau, l'horloge système, etc.

  2. Les restrictions qu'un système d'exploitation impose aux applications sont réalisées par des caractéristiques spéciales de l'unité centrale, telles que les modes de privilège, la protection de la mémoire et les interruptions. Bien que n'importe quel CPU d'un smartphone ou d'un PC possède ces caractéristiques, certains CPU ne les possèdent pas. Ces unités centrales ont en effet besoin de noyaux spéciaux qui "interprètent" le code des applications afin d'obtenir les caractéristiques souhaitées. Un exemple très intéressant est le Gigatron Il s'agit d'un ordinateur à 8 instructions que vous pouvez construire à partir de puces et qui émule un ordinateur à 34 instructions.

  3. Certains langages comme Java se "compilent" en quelque chose appelé Bytecode, qui n'est pas vraiment du code machine. Bien que dans le passé, ils étaient interprétés pour exécuter les programmes, de nos jours, quelque chose appelé Compilation juste-à-temps est généralement utilisé pour qu'ils finissent par s'exécuter directement sur le CPU en tant que code machine.

  4. L'exécution d'un logiciel dans une machine virtuelle nécessitait auparavant que son code machine soit "interprété" par un programme appelé un "logiciel de commande". Hyperviseur . En raison de l'énorme demande de l'industrie pour les VM, les fabricants de CPU ont ajouté des fonctions comme VTx à leurs CPU pour permettre à la plupart des instructions d'un système invité d'être exécutées directement par le CPU. Cependant, lors de l'exécution de logiciels conçus pour une incompatible CPU dans une machine virtuelle (par exemple, en émulant une NES), le code machine devra être interprété.

5voto

Alex Points 6039

Lorsque vous compilez votre code, vous créez du code dit "objet" qui (dans la plupart des cas) dépend des bibliothèques du système ( printf par exemple), puis votre code est enveloppé par le linker qui ajoutera une sorte de chargeur de programme que votre système d'exploitation particulier peut reconnaître (c'est pourquoi vous ne pouvez pas exécuter un programme compilé pour Windows sur Linux par exemple) et savoir comment déballer votre code et l'exécuter. Votre programme est donc comme la viande à l'intérieur d'un sandwich et ne peut être mangé qu'en bloc, dans son intégralité.

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.

C'est à moitié vrai ; si votre programme est un pilote en mode noyau, vous pouvez accéder directement au matériel si vous savez comment "parler" au matériel, mais généralement (surtout pour le matériel non documenté ou compliqué) les gens utilisent des pilotes qui sont des bibliothèques du noyau. De cette façon, vous pouvez trouver des fonctions API qui savent comment parler au matériel d'une manière presque humainement lisible sans avoir besoin de connaître les adresses, les registres, le timing et tout un tas d'autres choses.

chaque instruction de ce code machine pourra-t-elle être 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 ?

Eh bien, le noyau est comme une serveuse, dont la responsabilité est de vous conduire à une table et de vous servir. La seule chose qu'il ne peut pas faire, c'est manger pour vous, vous devez le faire vous-même. Il en va de même pour votre code, le noyau va décompresser votre programme dans une mémoire et lancer votre code qui est un code machine exécuté directement par le CPU. Un noyau a juste besoin de vous superviser - ce que vous êtes autorisé et ce que vous n'êtes pas autorisé à faire.

il n'explique pas si le code machine qui est généré après la compilation est une instruction pour le CPU directement ou s'il devra à nouveau passer par le noyau pour créer l'instruction correcte pour le CPU ?

Le code machine qui est généré après la compilation est une instruction adressée directement à l'unité centrale. Aucun doute là-dessus. La seule chose que vous devez garder à l'esprit, c'est que tout le code dans le fichier compilé n'est pas le code réel de la machine/du CPU. Le linker a enveloppé votre programme de quelques méta-données que seul le noyau peut interpréter, comme un indice - ce qu'il faut faire avec votre programme.

Que se passe-t-il après le chargement du code machine dans la mémoire ? Passera-t-il par le noyau ou parlera-t-il directement au processeur ?

Si votre code n'est qu'un simple opcode comme l'addition de deux registres, il sera exécuté directement par le CPU sans l'aide du noyau, mais si votre code utilise des fonctions de bibliothèques, ces appels seront assistés par le noyau, comme dans l'exemple de la serveuse, si vous voulez manger dans un restaurant, ils vous donneront des outils - fourchette, cuillère (et ce sont toujours leurs biens) mais ce que vous en ferez, cela dépend de votre "code".

Eh bien, juste pour prévenir les flammes dans les commentaires - il s'agit d'un modèle vraiment très simplifié qui, je l'espère, aidera le PO à comprendre les choses de base, mais les bonnes suggestions pour améliorer cette réponse sont les bienvenues.

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