J'essaie de déterminer les détails techniques de la raison pour laquelle les logiciels produits à l'aide de langages de programmation pour certains systèmes d'exploitation ne fonctionnent qu'avec eux.
D'après ce que j'ai compris, les fichiers binaires sont spécifiques à certains processeurs en raison du langage machine spécifique qu'ils maîtrisent et des jeux d'instructions différents entre les différents processeurs. Mais d'où vient la spécificité du système d'exploitation? J'avais l'habitude de supposer que c'était des API fournies par le système d'exploitation, mais j'ai vu ce diagramme dans un livre:
Systèmes d'exploitation - Composants internes et principes de conception 7ème édition - W. Stallings (Pearson, 2012)
Comme vous pouvez le constater, les API ne font pas partie du système d'exploitation.
Si par exemple je construis un programme simple en C en utilisant le code suivant:
#include<stdio.h>
main()
{
printf("Hello World");
}
Le compilateur fait-il quelque chose de spécifique à l'OS lors de la compilation?
la source
printf
de msvcr90.dll n'est pas la même chose queprintf
de libc.so.6)Réponses:
Vous mentionnez comment, si le code est spécifique à une CPU, pourquoi doit-il l'être également à un système d'exploitation? C’est en fait une question plus intéressante que beaucoup des réponses proposées ici.
Modèle de sécurité du processeur
Le premier programme exécuté sur la plupart des architectures de CPU s'exécute dans ce qu'on appelle l'anneau interne ou anneau 0 . La manière dont une arche de processeur spécifique implémente des anneaux varie, mais il est évident que presque tous les processeurs modernes ont au moins deux modes de fonctionnement, l'un privilégié, qui exécute un code «bare metal» pouvant effectuer toutes les opérations légales que le processeur peut effectuer et l'autre. non approuvé et exécute un code protégé qui ne peut exécuter qu'un ensemble de capacités sécurisé défini. Certains processeurs ont cependant une granularité beaucoup plus élevée et pour pouvoir utiliser les VM de manière sécurisée, il faut au moins 1 ou 2 sonneries supplémentaires (souvent étiquetées avec des nombres négatifs), mais cela dépasse le cadre de cette réponse.
Où l'OS entre en jeu
Premiers systèmes d'exploitation à tâche unique
Dans les tout premiers systèmes DOS et autres systèmes basés sur des tâches uniques, tout le code était exécuté dans l'anneau interne. Chaque programme que vous exécutiez disposait alors du pouvoir absolu sur tout l'ordinateur et pouvait littéralement faire n'importe quoi s'il se comportait mal, y compris effacer toutes vos données ou même endommager le matériel. dans quelques cas extrêmes tels que la définition de modes d'affichage non valides sur de très vieux écrans, cela pourrait être dû à un code buggy sans aucune malveillance.
Ce code était en fait largement indépendant des systèmes d’exploitation, tant que vous disposiez d’un chargeur capable de charger le programme en mémoire (assez simple pour les premiers formats binaires) et que le code ne reposait sur aucun pilote, implémentant tous les accès matériels auxquels il était destiné. n’importe quel système d’exploitation tant qu’il est exécuté dans l’anneau 0. Remarque: un système d’exploitation très simple comme celui-ci est généralement appelé moniteur s’il est simplement utilisé pour exécuter d’autres programmes sans offrir aucune fonctionnalité supplémentaire.
Systèmes d'exploitation multitâches modernes
Des systèmes d’exploitation plus modernes, notamment UNIX , des versions de Windows commençant par NT et divers autres systèmes d’exploitation devenus obscurs, ont décidé d’améliorer cette situation. Les utilisateurs souhaitaient des fonctionnalités supplémentaires telles que le multitâche afin de pouvoir exécuter plusieurs applications à la fois et une protection, de sorte qu'un bogue ( code malveillant) dans une application ne peut plus causer de dommages illimités à la machine et aux données.
Cela a été fait en utilisant les anneaux mentionnés ci-dessus, le système d'exploitation prendrait la place unique dans l'anneau 0 et les applications s'exécuteraient dans les anneaux externes non fiables, ne pouvant effectuer qu'un ensemble restreint d'opérations autorisées par le système d'exploitation.
Cependant, cette utilité et cette protection accrues avaient un coût, les programmes devaient désormais travailler avec le système d'exploitation pour effectuer des tâches qu'ils n'étaient pas autorisés à effectuer eux-mêmes; ils ne pouvaient par exemple plus prendre le contrôle direct du disque dur en accédant à sa mémoire et en modifiant les paramètres de façon arbitraire. données, au lieu de cela, ils ont dû demander au système d’exécuter ces tâches pour pouvoir vérifier s’ils étaient autorisés à effectuer l’opération, sans modifier les fichiers qui ne leur appartenaient pas, cela vérifierait également la validité de l’opération et ne laisserait pas le matériel dans un état non défini.
Chaque système d’exploitation a choisi une implémentation différente pour ces protections, basée en partie sur l’architecture pour laquelle le système d’exploitation avait été conçue et basée en partie sur la conception et les principes du système d’exploitation en question. les fonctionnalités disponibles pour cela alors que Windows a été conçue pour être plus simple, pour fonctionner sur du matériel plus lent avec un seul utilisateur. La manière dont les programmes de l'espace utilisateur communiquent également avec le système d'exploitation est complètement différente sur X86 comme sur ARM ou MIPS, par exemple, obligeant un système d'exploitation multi-plateforme à prendre des décisions en fonction du besoin de travailler sur le matériel pour lequel il est ciblé.
Ces interactions spécifiques au système d'exploitation sont généralement appelées "appels système" et englobent la manière dont un programme d'espace utilisateur interagit complètement avec le matériel via le système d'exploitation. Elles diffèrent fondamentalement en fonction de la fonction du système d'exploitation. être spécifique à l'OS.
Le chargeur de programme
En plus des appels système, chaque système d' exploitation fournit une méthode différente pour charger un programme à partir du support de stockage secondaire , et dans la mémoire , pour être chargeable par un système d' exploitation spécifique , le programme doit contenir un en- tête spécial décrit à l'OS comment elle peut être chargé et couru.
Cet en-tête était assez simple pour écrire un chargeur pour un format différent était presque trivial. Cependant, avec les formats modernes tels que elf qui supporte des fonctionnalités avancées telles que la liaison dynamique et les déclarations faibles, il est maintenant presque impossible pour un système d'exploitation d'essayer de charger des fichiers binaires ce qui signifie que même s'il n'y avait pas d'incompatibilités entre les appels système, il est extrêmement difficile de placer un programme en mémoire de manière à ce qu'il puisse être exécuté.
Bibliothèques
Les programmes utilisent rarement les appels système directement, cependant, ils obtiennent presque exclusivement leurs fonctionnalités bien que les bibliothèques encapsulent les appels système dans un format légèrement plus convivial pour le langage de programmation, par exemple, C possède la bibliothèque standard C et la glibc sous Linux et les bibliothèques win32 sous Windows NT et supérieur, la plupart des autres langages de programmation ont également des bibliothèques similaires qui encapsulent les fonctionnalités du système de manière appropriée.
Ces bibliothèques peuvent même, dans une certaine mesure, résoudre les problèmes multi-plateformes décrits ci-dessus. Il existe une gamme de bibliothèques conçues pour fournir une plate-forme uniforme aux applications tout en gérant en interne les appels vers une large gamme de systèmes d’exploitation tels que SDL . les programmes ne peuvent pas être compatibles binaires, les programmes qui utilisent ces bibliothèques peuvent avoir une source commune entre les plates-formes, ce qui rend le portage aussi simple que la recompilation.
Exceptions à ce qui précède
Malgré tout ce que j'ai dit ici, il y a eu des tentatives pour surmonter les limitations de l'impossibilité d'exécuter des programmes sur plusieurs systèmes d'exploitation. Parmi les bons exemples, citons le projet Wine, qui a émulé avec succès le chargeur de programme win32, le format binaire et les bibliothèques système permettant aux programmes Windows de s'exécuter sous divers UNIX. Il existe également une couche de compatibilité permettant à plusieurs systèmes d’exploitation BSD UNIX d’exécuter un logiciel Linux et, bien entendu, au propre logiciel d’impression d’Apple permettant d’exécuter un ancien logiciel MacOS sous MacOS X.
Cependant, ces projets nécessitent des efforts de développement manuels considérables. En fonction de la différence entre les deux systèmes d’exploitation, la difficulté varie d’une cale d’impression assez petite à une émulation presque complète de l’autre système d’exploitation, qui est souvent plus complexe que l’écriture de tout un système d’exploitation. C’est donc une exception et non la règle.
la source
Je pense que vous lisez trop dans le diagramme. Oui, un système d’exploitation spécifiera une interface binaire pour l’appel des fonctions du système d’exploitation. Il définira également un format de fichier pour les exécutables, mais fournira également une API, dans le sens de fournir un catalogue de fonctions pouvant être appelées par une application pour appeler des services OS.
Je pense que le diagramme tente simplement de souligner que les fonctions du système d'exploitation sont généralement appelées par un mécanisme différent de celui d'un simple appel à une bibliothèque. La plupart des systèmes d’exploitation courants utilisent des interruptions de processeur pour accéder aux fonctions du système d’exploitation. Les systèmes d'exploitation modernes ne permettent pas à un programme utilisateur d'accéder directement à un matériel. Si vous voulez écrire un caractère sur la console, vous devrez demander au système d'exploitation de le faire pour vous. L'appel système utilisé pour écrire sur la console varie d'un système d'exploitation à l'autre. Par conséquent, voici un exemple de la raison pour laquelle le logiciel est spécifique à un système d'exploitation.
printf est une fonction de la bibliothèque d'exécution C et, dans une implémentation typique, une fonction assez complexe. Si vous google, vous pouvez trouver la source de plusieurs versions en ligne. Voir cette page pour une visite guidée d'un . Au sol, il passe un ou plusieurs appels système et chacun de ces appels est spécifique au système d'exploitation hôte.
la source
Probablement. À un moment donné pendant le processus de compilation et de liaison, votre code est transformé en un binaire spécifique au système d'exploitation et lié à toutes les bibliothèques requises. Votre programme doit être enregistré dans un format que le système d'exploitation attend afin que le système d'exploitation puisse le charger et commencer à l'exécuter. De plus, vous appelez la fonction de bibliothèque standard
printf()
, qui est mise en œuvre à un certain niveau en termes de services fournis par le système d'exploitation.Les bibliothèques fournissent une interface - une couche d’abstraction du système d’exploitation et du matériel - qui permet de recompiler votre programme pour un système d’exploitation ou un matériel différent. Mais cette abstraction existe au niveau source: une fois que le programme est compilé et lié, il est connecté à une implémentation spécifique de cette interface spécifique à un système d'exploitation donné.
la source
Il y a un certain nombre de raisons, mais l'une des plus importantes est que le système d'exploitation doit savoir lire la série d'octets constituant votre programme en mémoire, rechercher les bibliothèques associées à ce programme et les charger en mémoire, et puis commencez à exécuter votre code de programme. Pour ce faire, les créateurs du système d'exploitation créent un format particulier pour cette série d'octets afin que le code du système d'exploitation sache où rechercher les différentes parties de la structure de votre programme. Parce que les principaux systèmes d'exploitation ont des auteurs différents, ces formats ont souvent peu à faire les uns avec les autres. En particulier, le format exécutable Windows a peu de points communs avec le format ELF utilisé par la plupart des variantes Unix. Donc, tout ce chargement, cette liaison dynamique et ce code doivent être spécifiques au système d'exploitation.
Ensuite, chaque système d'exploitation fournit un ensemble de bibliothèques différent pour communiquer avec la couche matérielle. Ce sont les API que vous mentionnez, et ce sont généralement des bibliothèques qui présentent une interface plus simple au développeur tout en la traduisant en appels plus complexes et plus spécifiques dans les profondeurs du système d’exploitation lui-même, ces appels étant souvent non documentés ou sécurisés. Cette couche est souvent assez grise, avec les API "OS" les plus récentes, construites partiellement ou entièrement sur des API plus anciennes. Par exemple, sous Windows, bon nombre des API les plus récentes créées par Microsoft au cours des années sont essentiellement des couches superposées aux API Win32 d’origine.
Un problème qui ne se pose pas dans votre exemple, mais c’est l’un des problèmes les plus importants auxquels les développeurs sont confrontés est l’interface avec le gestionnaire de fenêtres, qui permet de présenter une interface graphique. Que le gestionnaire de fenêtres fasse partie du "système d'exploitation" dépend parfois de votre point de vue, ainsi que du système d'exploitation lui-même, l'interface graphique de Windows étant intégrée au système d'exploitation à un niveau plus profond, tandis que les interfaces graphiques de Linux et OS X sont plus directement séparé. Ceci est très important car ce que les gens appellent généralement "le système d'exploitation" est une bête bien plus grosse que ce que les manuels ont tendance à décrire, car elle inclut de très nombreux composants au niveau de l'application.
Enfin, il n’est pas strictement un problème de système d’exploitation, mais un aspect important de la génération de fichiers exécutables réside dans le fait que différentes machines ont des cibles en langage assembleur différentes et que, par conséquent, le code objet généré doit être différent. Ce n'est pas à proprement parler un problème de "système d'exploitation" mais plutôt un problème de matériel, mais cela signifie que vous aurez besoin de versions différentes pour différentes plates-formes matérielles.
la source
Une autre de mes réponses :
Le système d'exploitation fournit donc des services aux applications afin que celles-ci n'aient pas à faire un travail redondant.
Votre exemple de programme en C utilise printf, qui envoie des caractères à stdout, une ressource spécifique au système d'exploitation qui affiche les caractères sur une interface utilisateur. Le programme n'a pas besoin de savoir où se trouve l'interface utilisateur - cela pourrait être sous DOS, dans une fenêtre graphique, il pourrait être redirigé vers un autre programme et utilisé comme entrée dans un autre processus.
Parce que le système d'exploitation fournit ces ressources, les programmeurs peuvent accomplir beaucoup plus avec peu de travail.
Cependant, même démarrer un programme est compliqué. Le système d’exploitation s'attend à ce que le fichier exécutable contienne au début certaines informations lui indiquant comment le démarrer, et dans certains cas (environnements plus avancés tels que Android ou iOS), quelles ressources seront nécessaires et nécessiteront une approbation, car elles touchent des ressources extérieures au système. "sandbox" - une mesure de sécurité destinée à protéger les utilisateurs et les autres applications contre les programmes malveillants.
Ainsi, même si le code machine exécutable est identique et qu’aucune ressource système n’est requise, un programme compilé pour Windows ne fonctionnera pas sur un système d’exploitation OS X sans émulation ou couche de traduction supplémentaire, même sur le même matériel.
Les premiers systèmes d'exploitation de type DOS pouvaient souvent partager des programmes, car ils implémentaient la même API dans le matériel (BIOS) et le système d'exploitation connecté au matériel pour fournir des services. Ainsi, si vous avez écrit et compilé un programme COM (qui n'est qu'une image mémoire d'une série d'instructions de processeur), vous pouvez l'exécuter sur CP / M, MS-DOS et plusieurs autres systèmes d'exploitation. En fait, vous pouvez toujours exécuter des programmes COM sur des machines Windows modernes. D'autres systèmes d'exploitation n'utilisent pas les mêmes points d'ancrage de l'API du BIOS. Par conséquent, les programmes COM ne s'exécutent pas sur eux sans, encore une fois, une couche d'émulation ou de traduction. Les programmes EXE suivent une structure qui comprend beaucoup plus que de simples instructions de processeur. Par conséquent, les problèmes d’API ne s’exécutent pas sur une machine qui ne comprend pas comment le charger en mémoire et l’exécuter.
la source
En fait, la vraie réponse est que si tous les OS ne comprend la même mise en page de fichier binaire exécutable, et vous ne vous limite aux fonctions normalisées (comme dans la bibliothèque standard C) que le système d' exploitation fourni (quels systèmes d' exploitation ne fournissent), votre logiciel serait , en fait, sur n'importe quel OS.
Bien sûr, la réalité est que ce n'est pas le cas. Un
EXE
fichier n'a pas le même format qu'unELF
fichier, même si les deux contiennent du code binaire pour le même processeur. * Chaque système d'exploitation doit donc pouvoir interpréter tous les formats de fichier, ce qu'ils n'ont tout simplement pas fait dans la début, et il n'y avait aucune raison pour qu'ils le fassent plus tard (presque certainement pour des raisons commerciales plutôt que techniques).De plus, votre programme doit probablement faire des choses que la bibliothèque C ne définit pas (même pour des choses simples comme lister le contenu d’un répertoire), et dans ce cas, chaque système d’exploitation fournit ses propres fonctions permettant d’atteindre votre objectif. tâche, ce qui signifie naturellement qu’il n’y aura pas de plus petit dénominateur commun à utiliser (à moins que vous ne définissiez ce dénominateur vous-même).
Donc, en principe, c'est parfaitement possible. En fait, WINE exécute les exécutables Windows directement sur Linux.
Mais c'est une tonne de travail et (généralement) injustifiée sur le plan commercial.
* Remarque: Un fichier exécutable est bien plus qu'un simple code binaire. Une tonne d'informations indique au système d'exploitation les bibliothèques dont dépend le fichier, la quantité de mémoire de pile dont il a besoin, les fonctions qu'il exporte vers d' autres bibliothèques qui peuvent en dépendre, le système d'exploitation peut trouver des informations de débogage pertinentes, " re-localiser » le fichier dans la mémoire si nécessaire, comment faire correctement le travail de gestion des exceptions, etc. , etc .... à nouveau, il pourrait être un format unique pour ce que tout le monde est d' accord, mais il n'y a tout simplement pas.
la source
Le diagramme comporte la couche "application" (la plupart du temps) séparée de la couche "système d'exploitation" par les "bibliothèques", ce qui implique que "application" et "système d'exploitation" n'ont pas besoin de se connaître. C'est une simplification dans le diagramme, mais ce n'est pas tout à fait vrai.
Le problème est que la "bibliothèque" a en réalité trois parties: l'implémentation, l'interface vers l'application et l'interface vers le système d'exploitation. En principe, les deux premiers peuvent être rendus "universels" en ce qui concerne le système d'exploitation (cela dépend de l'endroit où vous le découpez), mais la troisième partie - l'interface avec le système d'exploitation - ne le peut généralement pas. L’interface avec le système d’exploitation dépendra nécessairement du système d’exploitation, des API qu’il fournit, du mécanisme de conditionnement (par exemple, le format de fichier utilisé par la DLL Windows), etc.
Étant donné que la "bibliothèque" est généralement mise à disposition sous forme de package unique, cela signifie qu'une fois que le programme sélectionne une "bibliothèque" à utiliser, il s'engage dans un système d'exploitation spécifique. Cela se produit de deux manières: a) le programmeur choisit complètement à l'avance, puis la liaison entre la bibliothèque et l'application peut être universelle, mais la bibliothèque elle-même est liée au système d'exploitation; ou b) le programmeur configure les choses de manière à ce que la bibliothèque soit sélectionnée lors de l'exécution du programme, mais le mécanisme de liaison lui - même, entre le programme et la bibliothèque, dépend du système d'exploitation (par exemple, le mécanisme DLL sous Windows). Chacune a ses avantages et ses inconvénients, mais de toute façon, vous devez faire un choix à l’avance.
Cela ne veut pas dire que c'est impossible, mais il faut être très intelligent. Pour résoudre le problème, vous devez choisir la bibliothèque au moment de l'exécution et vous devez créer un mécanisme de liaison universel qui ne dépend pas du système d'exploitation (vous devez donc le maintenir, beaucoup plus de travail). Parfois, ça vaut le coup.
Vous n'avez pas à le faire, mais si vous allez faire l'effort de le faire, il y a de bonnes chances que vous ne vouliez pas être lié à un processeur spécifique non plus, alors vous allez écrire une machine virtuelle et vous allez compiler votre programme au format de code neutre du processeur.
A présent, vous devriez avoir remarqué où je vais. Les plateformes de langage comme Java font exactement cela. Le runtime Java (bibliothèque) définit la liaison indépendante du système d'exploitation entre votre programme Java et la bibliothèque (comment le runtime Java ouvre et exécute votre programme) et fournit une implémentation spécifique au système d'exploitation actuel. .NET fait la même chose dans une certaine mesure, sauf que Microsoft ne fournit pas de "bibliothèque" (runtime) pour autre chose que Windows (mais les autres le font - voir Mono). Et, en réalité, Flash fait la même chose, bien que sa portée soit plus limitée que celle du navigateur.
Enfin, il existe des moyens de faire la même chose sans mécanisme de liaison personnalisé. Vous pouvez utiliser des outils classiques, mais reporter l'étape de liaison à la bibliothèque jusqu'à ce que l'utilisateur sélectionne le système d'exploitation. C'est exactement ce qui se passe lorsque vous distribuez le code source. L'utilisateur prend votre programme et le lie au processeur (le compile) et au système d'exploitation (le lie) lorsqu'il est prêt à l'exécuter.
Tout dépend de la manière dont vous coupez les calques. À la fin de la journée, vous avez toujours un périphérique informatique fabriqué avec un matériel spécifique exécutant un code machine spécifique. Les couches constituent principalement un cadre conceptuel.
la source
Le logiciel n'est pas toujours spécifique au système d'exploitation. Les deux Java et version antérieure du système p-code (et même ScummVM) permettent un logiciel qui est portable sur les systèmes d' exploitation. Infocom (fabricants de Zork et de Z-machine ) disposait également d'une base de données relationnelle basée sur une autre machine virtuelle. Cependant, à un certain niveau, quelque chose doit traduire même ces abstractions en instructions à exécuter sur un ordinateur.
la source
Vous dites
Mais le programme que vous donnez à titre d'exemple fonctionnera sous de nombreux systèmes d'exploitation, et même dans certains environnements sans système d'exploitation.
La chose importante ici est la distinction entre le code source et le binaire compilé. Le langage de programmation C est spécifiquement conçu pour être indépendant du système d’exploitation sous forme de source. Pour ce faire, il laisse l'interprétation de choses comme "imprimer sur la console" jusqu'à l'implémenteur. Mais C peut être conforme à quelque chose qui est spécifique à l'OS (voir les autres réponses pour les raisons). Par exemple, les formats exécutables PE ou ELF.
la source
D'autres personnes ont bien couvert les détails techniques, je voudrais mentionner une raison moins technique, le côté UX / UI:
Ecrivez une fois, sentez-vous maladroit partout
Chaque système d'exploitation possède ses propres API d'interface utilisateur et normes de conception. Il est possible d'écrire une interface utilisateur pour un programme et de le faire fonctionner sur plusieurs systèmes d'exploitation. Cependant, cela garantit presque que le programme ne se sentira pas à sa place partout. Faire une bonne interface utilisateur nécessite de peaufiner les détails pour chaque plate-forme prise en charge.
Beaucoup d’entre eux sont de petits détails, mais ne vous y trompez pas et vous allez frustrer vos utilisateurs:
Même s'il est techniquement possible d'écrire une base de code d'interface utilisateur qui fonctionne partout, il est préférable d'effectuer des réglages pour chaque système d'exploitation pris en charge.
la source
Une distinction importante à ce stade consiste à séparer le compilateur de l'éditeur de liens. Il est probable que le compilateur produise plus ou moins le même résultat (les différences sont principalement dues à divers
#if WINDOWS
s). L'éditeur de liens, quant à lui, doit gérer tout ce qui est spécifique à la plate-forme - relier les bibliothèques, créer le fichier exécutable, etc.En d'autres termes, le compilateur s'intéresse principalement à l'architecture du processeur, car il produit le code exécutable réel et doit utiliser les instructions et les ressources du processeur (notez que le bytecode de l'IL ou de la JVM de .NET serait considéré comme un jeu d'instructions d'un processeur virtuel. dans cette vue). C'est pourquoi vous devez compiler le code séparément pour
x86
etARM
, par exemple.L'éditeur de liens, d'un autre côté, doit prendre toutes ces données brutes et ces instructions et les mettre dans un format que le chargeur (de nos jours, ce serait presque toujours le système d'exploitation) peut comprendre, ainsi que lier toutes les bibliothèques liées de manière statique. (qui inclut également le code requis pour la liaison dynamique, l’allocation de mémoire, etc.).
En d'autres termes, vous pourriez être en mesure de compiler le code une seule fois et de le faire fonctionner à la fois sous Linux et Windows - mais vous devez le lier deux fois, en produisant deux exécutables différents. Maintenant, dans la pratique, vous devez aussi souvent tenir compte du code (c'est là que les directives du (pré) compilateur entrent), de sorte que même la compilation d'un lien à deux fois n'est pas très utilisée. Sans compter que les gens traitent la compilation et la liaison en une seule étape lors de la construction (tout comme vous ne vous souciez plus des parties du compilateur lui-même).
Les logiciels de l'époque DOS étaient souvent plus portables-binaires, mais vous devez comprendre qu'ils ont également été compilés non pas pour DOS ou Unix, mais pour un certain contrat commun à la plupart des PC de style IBM - décharger ce que sont aujourd'hui les appels d'API à interruptions logicielles. Cela ne nécessitait pas de liaison statique, car il suffisait de définir les registres nécessaires, par exemple
int 13h
pour appeler des fonctions graphiques, et la CPU venait de sauter à un pointeur de mémoire déclaré dans la table d'interruption. Bien sûr, encore une fois, la pratique était beaucoup plus délicate, car pour obtenir des performances allant du pédalier au métal, il fallait écrire toutes ces méthodes vous-même, mais cela revenait à contourner le système d'exploitation. Et bien sûr, quelque chose nécessite invariablement une interaction avec l'API du système d'exploitation: la terminaison du programme. Néanmoins, si vous utilisiez les formats les plus simples disponibles (par exemple,COM
sous DOS, qui n’a pas d’en-tête, juste des instructions) et ne veut pas sortir, eh bien, chanceux! Et bien sûr, vous pouvez également gérer la terminaison appropriée dans le runtime, de sorte que vous puissiez avoir le code pour la terminaison Unix et la terminaison DOS dans le même exécutable, et détecter au moment de l'exécution lequel utiliser :)la source