Vai al contenuto
Offerte

EXE su Linux senza Wine: perché è possibile ma non basta

In questo articolo Indice dei contenuti 3 sezioni

Chi ha provato almeno una volta a fare doppio clic su un file EXE su una distribuzione Linux conosce bene la sensazione: nulla accade, oppure il sistema chiede con quale programma aprirlo. Eppure il processore sotto il cofano è lo stesso, Intel o AMD, e le istruzioni contenute in quel file le conosce già benissimo. La domanda quindi è legittima, e la risposta è meno scontata di quanto sembri: far partire il codice di un programma Windows su Linux, senza Wine, è tecnicamente possibile. Il difficile viene dopo.

Non esistono istruzioni della CPU riservate a Windows e altre riservate a Linux. Un’operazione Assembly come ADD, MOV o JMP viene interpretata allo stesso modo, punto. La differenza nasce da come il programma è impacchettato e dai servizi che si aspetta di trovare intorno a sé. Un’applicazione Windows presume che il sistema operativo sappia aprire il suo eseguibile, sistemarne il codice in memoria, caricare le librerie giuste e rispondere quando chiede di aprire una finestra, leggere un file o creare un thread.

Formati diversi, aspettative diverse

Su Windows gli eseguibili usano il formato PE, cioè Portable Executable, quello dei classici file .exe e .dll. Contiene il codice macchina e una specie di indice che spiega al sistema quali parti sono programma, quali dati, quali librerie servono e da dove iniziare. Linux invece lavora soprattutto con il formato ELF, che raccoglie le stesse informazioni ma le organizza con regole proprie.

Quando si lancia un eseguibile entra in scena un componente chiamato loader, il caricatore. Legge la struttura del file, decide cosa finisce in memoria, assegna i permessi e prepara il terreno prima di passare il controllo al programma. Un loader PE scritto per Linux può fare una cosa che a prima vista sorprende: aprire un EXE, copiarne il codice in memoria e avviarlo davvero. È quello che sperimentano progetti come PELoader, LSW e, più di recente, Tawi.

Con un programma che fa solo calcoli matematici funziona. I guai iniziano appena l’applicazione chiede qualcosa al sistema operativo. Per scrivere su disco un programma Windows non impartisce comandi diretti alla CPU, chiama funzioni come CreateFileW o WriteFile. Su Linux quelle funzioni non esistono, ci sono interfacce equivalenti ma con nomi e regole differenti. Serve uno strato di compatibilità.

Il trucco delle richieste intercettate

Un programma Windows si appoggia pesantemente alle DLL, le Dynamic Link Library, raccolte di funzioni condivise tra più applicazioni. KERNEL32.dll è storicamente la più importante, poi ci sono USER32.dll per l’interfaccia grafica, ADVAPI32.dll per varie funzioni di sistema, WS232.dll per la rete. Il formato PE include una struttura chiamata Import Address Table, in pratica una tabella dove il sistema scrive gli indirizzi delle funzioni esterne. Un loader alternativo può sostituire quegli indirizzi con i propri: il programma crede di parlare con Windows, la richiesta viene deviata verso una funzione compatibile che a sua volta chiama il kernel Linux.

Sembra semplice. Non lo è, perché un percorso come C:UsersLuigidocumento.txt va tradotto in qualcosa tipo /home/luigi/documento.txt, e poi ci sono permessi, condivisione dei file, attributi, nomi dei dispositivi, gestione degli errori. Tutte cose che i due sistemi trattano in modo diverso. Non basta tradurre le API, bisogna tradurne il significato.

Perché Wine resta una macchina complicata

L’acronimo sta per Wine Is Not an Emulator e lo dice chiaramente: quando l’architettura coincide, non c’è alcuna traduzione istruzione per istruzione, il codice gira sul processore. Wine ricostruisce le interfacce, implementando componenti equivalenti a ntdll.dll, kernel32.dll, user32.dll, gdi32.dll, advapi32.dll e molte altre. Un ruolo chiave spetta a NTDLL, che su Windows sta al confine tra applicazioni e kernel NT.

Poi ci sono i concetti che su Linux proprio non esistono. Gli handle Windows non corrispondono ai file descriptor Unix, possono rappresentare file, processi, thread, eventi, mutex. Il registro di sistema non c’è affatto, e Wine ne mantiene una rappresentazione salvata su disco. Sul fronte grafico USER32 gestisce finestre e input, GDI il disegno 2D, mentre per i giochi progetti come DXVK e vkd3d-proton traducono Direct3D 9, 10, 11 e Direct3D 12 verso Vulkan. Restano audio, socket, COM, OLE, servizi, stampa, appunti e una lunga fila di dettagli minori che, mancando, mandano tutto a gambe all’aria.

Condividi:
197 Condivisioni