Perché un programma eseguibile per una CPU specifica non funziona su Linux e Windows?

Un problema eseguibile come exe non funziona su Linux (senza vino). Durante la compilazione del codice sorgente il compilatore produce un codice object che è specifico per una particolare architettura della CPU. Ma la stessa applicazione non funziona con un altro sistema operativo con la stessa CPU. So che il codice potrebbe includere istruzioni specifiche per il sistema operativo che impediranno l’esecuzione dell’eseguibile. Ma che dire di un semplice programma 2 + 2? La parte confusa è che diavolo quel codice macchina impedisce di funzionare. Codice macchina specifico per CPU? Se togliamo il formato di file eseguibile potremmo vedere lo stesso codice macchina (come 2 + 2) per entrambi i sistemi operativi?

Un’altra domanda: che dire del linguaggio assembly? DO windows e Linux usano un linguaggio assembly diverso per la stessa CPU ?.

Ci sono molte differenze Tra loro:

  1. Formato eseguibile : ogni sistema operativo richiede che i file binari siano conformi a uno specifico formato binario. Per Windows, questo è il formato Portable Executable (PE). Per Linux, è la maggior parte delle volte ELF (supporta anche altri tipi).

  2. Interfaccia binaria di applicazione : ogni SO definisce un insieme di funzioni di sistema primarie e il modo in cui un programma le chiama. Questo è fondamentalmente diverso tra Linux e Windows. Mentre le istruzioni che calcolano 2 + 2 sono identiche su Linux e Windows nell’architettura x86, il modo in cui l’applicazione si avvia, il modo in cui stampa l’output e il modo in cui esce si differenzia tra i sistemi operativi.

Sì, sia i programmi Linux che Windows su architettura x86 utilizzano il set di istruzioni supportato dalla CPU, definito da Intel.

È dovuto alla differenza tra il modo in cui il programma viene caricato in memoria e le risorse date per l’esecuzione. Anche i programmi più semplici devono avere spazio di codice, spazio dati e la capacità di acquisire memoria di runtime e I / O. L’infrastruttura per eseguire queste attività di basso livello è completamente diversa tra le piattaforms, a meno che tu non abbia un qualche tipo di livello di adattamento, come WINE o Cygwin.

Supponendo, tuttavia, che si possano semplicemente inserire istruzioni CPU assemblate arbitrariamente nel segmento di codice di un processo in esecuzione e ottenere quel codice da eseguire, quindi, sì, lo stesso codice verrebbe eseguito su entrambe le piattaforms. Tuttavia, sarebbe piuttosto limitato, e fare cose complesse come i salti ai moduli esterni fallirebbe, a causa di come queste cose sono fatte in modo diverso su piattaforms diverse.

Problema 1 è il formato dell’immagine. Quando un’applicazione viene lanciata in esecuzione, l’OS deve caricare l’immagine dell’applicazione, trovare il punto di ingresso e lanciarlo da lì. Ciò significa che il sistema operativo deve comprendere il formato dell’immagine e ci sono diversi formati tra vari sistemi operativi.

Il problema 2 è l’accesso ai dispositivi. Una volta avviata un’applicazione può leggere e scrivere registri nella CPU e questo è tutto. Per fare qualcosa di interessante, come mostrare un personaggio su una console, ha bisogno di accedere ai dispositivi e questo significa che deve chiedere tale accesso dal sistema operativo. Ogni Os ha una API diversa che viene offerta per accedere a tali dispositivi.

Il problema 3 è istruzioni privilegiate. Il processo appena avviato avrebbe forse bisogno di una posizione di memoria per archiviare qualcosa, non può realizzare tutto con i regiestries. Ciò significa che è necessario allocare la RAM e impostare la conversione da VA a indirizzo fisico. Queste sono operazioni riservate che solo il sistema operativo può fare e, di nuovo, le API per accedere a questi servizi variano a seconda del sistema operativo.

La linea di fondo è che le applicazioni non sono scritte per una CPU, ma per una serie di servizi primitivi offerti dal sistema operativo. l’alternativa è scrivere le app rispetto a una serie di servizi primitivi offerti da una macchina virtuale, e questo porta ad app più o meno portatili, come le app Java.

Sì, ma il codice invariabilmente chiama le funzioni della libreria per fare praticamente qualsiasi cosa – come stampare “4” sul terminale. E queste librerie sono specifiche della piattaforma e differiscono tra Linux e Windows. Questo è il motivo per cui non è portatile, non è un problema a livello di istruzione.

Ecco alcuni dei motivi per cui riesco a pensare in cima alla mia testa:

  1. Diversi formati di contenitori (che finora sembra essere il principale elemento di differenziazione in questa risposta – tuttavia non è l’unica ragione).
  2. diversa semantica del linker dinamico .
  3. diverso ABI .
  4. diversi meccanismi di gestione delle eccezioni – windows ha SEH – su cui è costruita la gestione delle eccezioni C ++
  5. diverse semantiche delle chiamate di sistema e chiamate di sistema diverse, quindi diverse librerie di basso livello.

Alla seconda domanda: Windows gira solo su x86, x64 e IA64 (non sono sicuro delle versioni mobili). Per Linux, vedi qui .