ADVERTISEMENT

How to make a 32-bit program from a 64-bit version?

No, this is not possible. The reason why is quite broad, maybe even too broad for SuperUser, given that you would need to explain the fundamentals on how x86 and x64 were created, and how this influences programming in general.

But to explain briefly, it comes down to this:

In the past, we had 16-bit processors. Then intel made the first 32 bit processor, also known as x86. This is the 8086, 80286 (286 for short) etc... This was basically a modifcation to the 16 bit processors, with extra instruction sets added. With every new release of their processor series, Intel added more instruction sets to the processor family, which in the end caused the instructionset to contain many many instructions. Intel could not just remove old instruction sets because that would mean there was no backwards compatibility, and Intel wanted to keep supporting older processors.

As the processor is 32 bits, there is an upper limit, namely the highest 32-bit number. This means, that memory assignment only goes up to about 3,5GB.

Back in the days, computers were not so powerful, so if intel would aim for 64 bits from the start, it would mean that much more time was spent calculating the same numbers so performance would degrade simply because the numbers to calculate with are bigger.

Besides 32 bit processors worked quite well for a long time.

At some point, AMD entered the market and introduced the 64bit processor. AMD created their own instruction sets to allow working with 64 bits while keeping the intel instruction sets for 32 bits in tact to allow for backwards compatibility with 32 bits.

Given that they are in fact different instruction sets, a programmer who creates 32 bit programs will call different routines than when they create 64 bit programs.

Now that I explain why this is hard to do, lets continue to explain the problem from a programming perspective.

When you code a program, you write your code first. If your code is backwards compatible for 32 bits programs, you simply cannot use 64-bits numbers nor can you address more than 3,5gigs of memory at the same time. Basically, you cannot cross any limits that 32 bit programs face or your program will crash when done so.

As you now have code, only you can actually run your program. In order to make it so that other people can run your program, you have to compile the code into an executable. This means that the easy to read code is converted into instructions that the processor understands. During compile, you specify if your program is meant to run on x86 or x64, and the compiler will generate code using the instruction sets based on that processor architecture.

As you can see, you can't just modify an executable and make it work on a different executable. You first need to decompile the program to code, then recompile it using different instructions.

That said, given that a program that is compiled for x86 will natively work on x64, it is safe to assume that a programmer creates an x64 program because he is going to break limits of the x86 architecture. So even if you were to turn the x64 version into an x86 version, it is likely that the program will be unstable as you will cross the limitations of what a 32-bit program can do.


Theoretically it can be done!

There are ways to translate from a neutral bytecode/internal representation to a specific architecture's binary like how modern compilers/JITters work. There are also emulators that run programs for another architecture on the current one. Bochs and qemu are two of the most famous ones. See:

  • Running x86-64 ASM on a x86-32 processor
  • How to run Windows from an emulator on a non x86 host machine?

Despite that I've yet to see anyone writing a converter like that for a single binary, because basically you'll also need to emulate every system and library calls, in which case it'd be better to run the whole emulator anyway. Qemu also has the ability to emulate only the user space, so it's actually possible to run a program along with its required libraries without a full-fledged OS. But as always, emulation is not meant for performance-sensitive things like web browsing or media playing

However if your x86 PC is 32-bit only, that means it's already more than 10 years old. Pretty much any Intel CPUs from Pentium 4 Prescott in 2004 onward (apart from some early Atom CPUs) and all AMD CPUs from Athlon 64 in 2003 onward are 64-bit capable. It's time to update.

If your PC is new enough to support x86_64 and VT-x then you can run a 64-bit virtual machine inside a 32-bit host, however it's not recommended and the performance will be even worse than running a 64-bit host with a 32-bit VM inside. A 64-bit OS doesn't need twice the memory compared to a 32-bit one like many people thought, so even with only 2GB of RAM, a 64-bit OS is generally still faster due to twice the number of registers and many other things. Between 1 and 2GB of RAM it's arguable but I'd go for 64-bit


That said, regarding security measures, 32-bit OSes nowadays are often late on security patches because developers all run a 64-bit system. For example the Meltdown and Spectre patches are pushed for 32-bit Linux more than half a year after 64-bit Linux has been patched. Meltdown patches are provided for 64-bit Windows 10 build 1507 and up but 32-bit users are only protected since build 1511. And even if they're patched, such ancient machines will usually face a lot more performance impact because they don't have the new instructions and features to offset the slowdown. Due to that reason MS doesn't enable the patch on some old PCs unless explicitly told by the user. And beside performance drop, a 32-bit patch will be more likely to be buggy because of a significantly fewer number of testers. See Linux's 32-Bit Kernel Has Been Buggy Since Being Mitigated For Meltdown:

Not only did it take months after Intel's Meltdown vulnerability was published (and x86_64 being mitigated) to see Linux KPTI support for x86 32-bit to mitigate Meltdown (from January's disclosure to mainline readiness in July), but it turns out it ended up exposing a 32-bit only bug that has lived in the kernel from summer 2018 until now [28 July 2019] with the Linux 5.3.

Sometimes they won't be patched at all because there's not enough user base, thus little incentive to spend the massive effort. The issue is also impossible to fix without hardware support if it's a hardware bug. For example recent side-channel attacks like Spectre or L1TF also need an updated microcode, so if the CPU and/or mainboard manufacturer don't release a firmware update, you're out of luck! Those bugs affect CPUs in the last two decades, but it's not possible to provide patches for very old systems. Windows 7 also dropped Pentium 3 support because it's too hard to patch without SSE2 support, or because too few people running it on those CPUs.

32-bit Windows is also more vulnerable because:

  • It has less hot-patching capability. Only ~30% of the 32-bit Windows kernel is hot-patchable, compared to 100% of the 64-bit one. It also doesn't support Kernel Patch Protection
  • It doesn't require drivers to be signed like on 64-bit Windows
  • It has less space for ASLR to work

If you run a 64-bit OS in an emulator then it'll even be slower. And even if you accept the crawling speed and use an emulator then malwares on the host can still attack the virtual machine in such a vulnerable system. Again, time to update if you really care about security, or you'll have to live with less a secured system indefinitely

Further reading:

  • Is 32-bit safer than 64-bit?
  • Is 64-bit Windows Safer Than 32-bit?
  • Why the 64-bit Version of Windows is More Secure
  • How to convert 32-bit compiled binary to 64-bit

This is technically possible; the process is called binary translation.

You'll most often find this put into practice with emulators for disparate platforms (e.g. ARM on x86, x86 on ARM), or virtualisation where hardware acceleration is not available.

The biggest problem you'll face is that you cannot simply run most programs in a vacuum. They depend on the operating system's ABI, which typically varies between architectures. This means you end up needing to add a translation layer for all interactions with the OS (API calls, etc.), at which point you might as well emulate the entire OS ... which is described in phuclv's answer.