The operating systems in the Windows NT lineage have supported multiple processor architectures for nearly all of its existence. There was a brief period of darkness when Compaq ceased production of Alpha AXP systems and before Intel released its Itanium processors. But even during that period, the Alpha AXP systems were still being used, just not in ways visible to the public: They were being used to develop 64-bit Windows. So there was never a period of time where Windows developers weren’t developing for multiple processor architectures. How did this work? Did every developer have a machine of every architecture in their office to validate their work on every processor?
No, it didn’t work that way.
Most developers had an Intel-class system as their primary machine, and another Intel-class system as their test machine. Some developers had a second test machine which was one of the other architectures. And some developers were all-in and had a non-Intel-class system as their primary machine.
I believe Jon Vert, the original author of the Windows NT blue screen, had a MIPS system as his primary system, and then when support for MIPS was dropped, he switched to an Alpha AXP as his main machine. That’s dedication to the non-Intel architectures.
For a long time, Windows NT did not have cross-compilers. If you wanted to compile for MIPS, you needed to have a MIPS system, for example. Every team knew who their representatives were for the non-Intel architectures, and if you needed to test your changes on one of those systems, you would ask them to build a binary for you, and you could go to their office to run your changes on a test system.
Most of the time, this step wasn’t necessary. Since Windows NT was designed as a portable operating system, the architectural differences rarely showed up in how you wrote your code, so if it worked on one 32-bit architecture, it probably worked on the others. We used the same principle when porting Windows to 64-bit: The vast majority of the work was in the initial port from 32-bit processors to 64-bit Alpha AXP. The port from 64-bit Alpha AXP to 64-bit Intel Itanium was handled almost entirely by the kernel team, since it is deep inside the kernel that the architectural differences become significant.
There are still places where architectural differences are visible in high-level code, however. The two biggest ones were multithreading and misaligned data. The Intel processors have rather strict memory models, so you didn’t observe race conditions that would be problems on systems with weaker memory models. And the Intel processors are quite forgiving of misaligned data, so code that used misaligned pointers would run just fine on an Intel system and then crash horribly on a processor that enforces alignment more strictly. To catch those types of issues, we had to exercise vigilance during code reviews and supplement it with a lot of testing to exercise the new code paths.
The Windows division still works this way. Windows supports Intel x86-32, Intel x86-64, ARM AArch32, and ARM AArch64. Most developers have an Intel x86-64 system as their main system and run Intel x86-32 and Intel x86-64 virtual machines for testing. Developers who are working with ARM-specific features will usually have an Intel x86-64 system as their main system and an ARM test system. Fortunately, we now have cross-compiling, so you no longer need to have a build environment on your ARM system. You can build an ARM binary on your Intel system.
Bonus reading: Anybody who writes #pragma pack(1)
may as well just wear a sign on their forehead that says “I hate RISC.”
Any chance that Microsoft has secretly been maintaining ports for architectures like PowerPC or MIPS, much like Apple did for Intel when they bought NeXT?
Or perhaps Microsoft has worked experimentally on some other architectures, such as RISC-V or MIPS64?
Apple did it for a CPU architecture that was very much alive and was clearly a future (and past) target. I think MIPS CPUs are no longer made. PowerPC doesn’t really exist any more in the desktop market, and Windows NT never supported the big POWER variation still used by IBM. But it wouldn’t surprise me if MSFT had a working Windows for RISC-V. (I am hoping they do and will eventually release it.)
I think early on many 386 systems would only support up to 16MB of RAM.
Is this out-of-date? There is no x86-32 version of Windows 11, and even AArch32 was only supported by Windows 10 IoT Core. Are development builds still being maintained for these architectures even if they aren’t being released?
I take “Windows supports Intel x86-32…” to mean that it supports running 32-bit code on x86-64bit Intel processors, NOT that the Windows code base is compiled for x86-32 hardware.
x86-32 Windows 10 is still in support and receiving regular security updates to my understanding.
There was an insider preview build of Windows 10 ARM32 that could run on the Surface RT, and ARM32 binaries still work on Windows 10 and 11 on ARM64 devices until Windows 11 24H2. Similarly, Windows 10 on x86-32 is still in support until later this year, and there’s currently no sign of Windows 11 dropping support for running x86-32 apps like it did with ARM32 apps.
If you have access to the people who did it, I’d love to hear what the bootstrap sequence was for NT on a new CPU architecture, given that you didn’t have cross-compilation.
Did you have some form of limited cross-compiler (e.g. no optimizer) to get you far enough that you could compile natively, and then switched to native compilation? Or did you have some form of more esoteric workflow?
Having cross-compiling sucks. Not having cross-compiling sucks.
Wait a minute; how did you bootstrap Windows NT on a new target processor if you couldn’t cross compile?
Bonus note. I only ever used #pragma pack(1) for on-disk structures; and that’s mostly gone because of endianness. It only ever caused a problem when moving to 64 bit because the alignment demand for 64 bit integers changed.