Fai riferimento a come se il codice è specifico per una CPU, perché deve essere specifico anche per un sistema operativo. Questa è in realtà una domanda più interessante che molte delle risposte qui hanno assunto.
Modello di sicurezza della CPU
Il primo programma eseguito sulla maggior parte delle architetture della CPU viene eseguito all'interno di quello che viene chiamato l'anello interno o l'anello 0 . Il modo in cui uno specifico arco della CPU implementa gli anelli varia, ma risulta che quasi tutte le moderne CPU hanno almeno 2 modalità di funzionamento, una con privilegi e che esegue un codice 'bare metal' che può eseguire qualsiasi operazione legale che la CPU può eseguire e l'altra è non attendibile ed esegue codice protetto che può eseguire solo un set definito di funzionalità sicure. Tuttavia, alcune CPU hanno una granularità molto più elevata e per utilizzare le VM in modo sicuro sono necessari almeno 1 o 2 anelli extra (spesso etichettati con numeri negativi), ma questo va oltre lo scopo di questa risposta.
Dove arriva il sistema operativo
Primi SO a tasking singolo
Nei primissimi DOS e altri primi sistemi basati su tasking singolo tutto il codice veniva eseguito nell'anello interno, ogni programma che avessi mai eseguito aveva il pieno potere sull'intero computer e poteva fare letteralmente qualsiasi cosa se si comportava male, inclusa la cancellazione di tutti i tuoi dati o persino il danneggiamento dell'hardware in alcuni casi estremi come l'impostazione di modalità di visualizzazione non valide su schermi di visualizzazione molto vecchi, peggio, ciò potrebbe essere causato semplicemente da un codice errato senza malizia.
Questo codice era in gran parte indipendente dal sistema operativo, a condizione che tu avessi un caricatore in grado di caricare il programma in memoria (abbastanza semplice per i primi formati binari) e il codice non si basava su alcun driver, implementando tutto l'accesso hardware stesso dovrebbe essere eseguito qualsiasi sistema operativo purché sia eseguito nell'anello 0. Nota, un sistema operativo molto semplice come questo è solitamente chiamato monitor se viene semplicemente utilizzato per eseguire altri programmi e non offre alcuna funzionalità aggiuntiva.
Moderni sistemi operativi multitasking
I sistemi operativi più moderni tra cui UNIX , le versioni di Windows che iniziano con NT e vari altri sistemi operativi ora oscuri hanno deciso di migliorare questa situazione, gli utenti volevano funzionalità aggiuntive come il multitasking in modo da poter eseguire più di un'applicazione contemporaneamente e protezione, quindi un bug ( o codice dannoso) in un'applicazione non potrebbe più causare danni illimitati alla macchina e ai dati.
Ciò è stato fatto usando gli anelli di cui sopra, il sistema operativo avrebbe avuto l'unico posto in esecuzione nell'anello 0 e le applicazioni sarebbero state eseguite negli anelli esterni non attendibili, in grado di eseguire solo un insieme limitato di operazioni consentite dal sistema operativo.
Tuttavia, questa maggiore utilità e protezione ha avuto un costo, i programmi ora dovevano lavorare con il sistema operativo per eseguire attività che non potevano svolgere autonomamente, ad esempio non potevano più assumere il controllo diretto sul disco rigido accedendo alla sua memoria e modificando arbitrariamente dati, invece hanno dovuto chiedere al sistema operativo di eseguire queste attività per loro in modo che potesse verificare che fossero autorizzati a eseguire l'operazione, non modificando i file che non appartenevano a loro, avrebbe anche verificato che l'operazione fosse effettivamente valida e non lascerebbe l'hardware in uno stato indefinito.
Ciascun sistema operativo ha deciso un'implementazione diversa per queste protezioni, in parte in base all'architettura per la quale il sistema operativo è stato progettato e in parte basato sulla progettazione e sui principi del sistema operativo in questione, UNIX, ad esempio, ha posto l'accento sulle macchine utili per l'uso multiutente e focalizzate le funzionalità disponibili per questo mentre Windows è stato progettato per essere più semplice, per funzionare su hardware più lento con un singolo utente. Il modo in cui i programmi di spazio utente parlano anche con il sistema operativo è completamente diverso su X86 come sarebbe su ARM o MIPS, ad esempio, costringendo un sistema operativo multipiattaforma a prendere decisioni basate sulla necessità di lavorare sull'hardware a cui è destinato.
Queste interazioni specifiche del sistema operativo sono generalmente chiamate "chiamate di sistema" e comprendono il modo in cui un programma di spazio utente interagisce completamente con l'hardware attraverso il sistema operativo, sostanzialmente differiscono in base alla funzione del sistema operativo e quindi un programma che fa il suo lavoro attraverso le chiamate di sistema deve essere specifico del sistema operativo.
Il programma di caricamento
Oltre alle chiamate di sistema, ciascun sistema operativo fornisce un metodo diverso per caricare un programma dal supporto di memoria secondario e nella memoria , per essere caricabile da un sistema operativo specifico il programma deve contenere un'intestazione speciale che descriva al sistema operativo come potrebbe essere caricato ed eseguito.
Questa intestazione era abbastanza semplice che scrivere un caricatore per un formato diverso era quasi banale, tuttavia con formati moderni come elfo che supportano funzionalità avanzate come collegamenti dinamici e dichiarazioni deboli è ora quasi impossibile per un sistema operativo tentare di caricare binari che non sono stati progettati per questo, questo significa che, anche se non ci sono incompatibilità di chiamate di sistema, è immensamente difficile persino posizionare un programma in ram in un modo in cui può essere eseguito.
biblioteche
I programmi raramente usano le chiamate di sistema direttamente, tuttavia ottengono quasi esclusivamente la loro funzionalità anche se le librerie che avvolgono le chiamate di sistema in un formato leggermente più amichevole per il linguaggio di programmazione, ad esempio, C ha la libreria standard C e glibc sotto Linux e librerie simili e win32 sotto Windows NT e versioni successive, la maggior parte degli altri linguaggi di programmazione hanno anche librerie simili che avvolgono la funzionalità del sistema in modo appropriato.
Queste librerie possono persino superare i problemi multipiattaforma come sopra descritto, esistono una serie di librerie progettate per fornire una piattaforma uniforme alle applicazioni e gestire internamente le chiamate a una vasta gamma di sistemi operativi come SDL , ciò significa che sebbene i programmi non possono essere compatibili con i binari, i programmi che usano queste librerie possono avere un sorgente comune tra le piattaforme, rendendo il porting semplice come la ricompilazione.
Eccezioni a quanto sopra
Nonostante tutto quello che ho detto qui, ci sono stati tentativi di superare i limiti di non essere in grado di eseguire programmi su più di un sistema operativo. Alcuni buoni esempi sono il progetto Wine che ha emulato con successo sia il caricatore del programma win32, il formato binario e le librerie di sistema che consentono ai programmi Windows di essere eseguiti su vari UNIX. Esiste anche un livello di compatibilità che consente a diversi sistemi operativi BSD UNIX di eseguire software Linux e, naturalmente, lo spessore di Apple che consente di eseguire il vecchio software MacOS su MacOS X.
Tuttavia, questi progetti funzionano attraverso enormi livelli di sforzo di sviluppo manuale. A seconda della differenza tra i due sistemi operativi, la difficoltà varia da uno spessore abbastanza piccolo all'emulazione quasi completa dell'altro sistema operativo, che è spesso più complessa della scrittura di un intero sistema operativo in sé e quindi questa è l'eccezione e non la regola.