Se stai parlando di convertire un eseguibile binario, è fattibile, ma non è facile.
È più facile su architetture con istruzioni a lunghezza fissa - che significa: non Intel. Questo perché è molto facile passare attraverso il codice e scoprire quali parti sono istruzioni e quali parti sono dati.
È effettivamente più facile fornire un livello di compatibilità, se, quando è in modalità 64 bit, la CPU è in grado di eseguire singoli processi in modalità 32 bit.
Si può anche fare quella che viene chiamata "ricompilazione dinamica" del codice binario. Questo è il modo in cui Rosetta era in grado di permettere ai binari PowerPC Mac OS X di funzionare su Intel Mac OS X fino a Mac OS X prima di Leopard (in realtà li avevo in esecuzione su Leopard, nel mio ufficio, ma B&I non voleva mantenere archivi binari separati).
In alternativa, è possibile emulare l'ambiente di esecuzione a 32 bit utilizzando un programma emulatore; per Intel, questo sarebbe probabilmente QEMU o qualcosa di simile.
Se state parlando di codice sorgente, è sia più facile, sia più difficile.
Potete ricompilare il codice sorgente con un compilatore che mira all'ambiente di esecuzione a 64, invece che all'ambiente di esecuzione a 32 bit.
Questo vi porterà in parte sulla strada giusta; sfortunatamente, non vi porterà fino in fondo, poiché molto codice fa supposizioni sulle dimensioni dei tipi di dati. Molto comune è la conversione tra puntatore e int, int e long, e simili promozioni e retrocessioni di tipo.
Queste possono risultare in una perdita di dati, una perdita di precisioni, o veri e propri errori nel codice - per esempio, codice usato per rappresentare bitfields e altri dati, che ora è della dimensione sbagliata.
C'è anche il problema dei dati esterni.
This is most obvious in networking, since the structures passed back and forth as packets tend to have very strict field size requirements.
You can also have a problem with external data prepresentation; if you saved something out as a:
- struct foo {
- long i;
- char str[20];
- ...
- };
This will not have the same on disk representation in ILP32 (Integer, Long, and Pointer are 32 bits) and LP64 (Integer is 32 bits; Long and Pointer are 64 bits).
ILP32 and LP64 are the most common ways of implementing 32 vs. 64 bit data types in most computer language implementation; there are actually other possibilities, which are less commonly used.
Inoltre, ci sono problemi tra le compilazioni a 32 e 64 bit che circondano il structure packing (quanto spazio viene allocato per arrivare ad un confine di allineamento interno alla struttura) e il structure padding (quanto spazio viene allocato alla fine della struttura, in modo tale che, in un array di strutture, il 0° e il 1° elemento abbiano gli stessi confini di allineamento), e così via.
Ci sono strumenti per automatizzare molto di questo lavoro; il più grande è quello di abilitare tutti gli avvisi di conversione di tipo e di dimensione nel vostro compilatore, e renderli errori. Ma ci sono anche strumenti di analisi statica, e ci sono strumenti di analisi del codice oggetto (binari con simboli, non necessariamente eseguibili, ma minimamente: unità di compilazione).
In breve, entrambi i tipi di conversione possono richiedere molto sforzo per essere realizzati*.
(*) Sì, ho fatto questo più volte, e su più architetture, nel corso della mia carriera.