Geoff Chappell, Software Analyst
From a modern perspective, the compiling and linking of 32-bit code was still very primitive in 1993 when Windows NT 3.1 was released as the first Windows that’s its own operating system. The 32-bit code for the Windows that ran on DOS had plausibly all been written in assembly language. The Device Driver Kit (DDK) for this variety of Windows was still years from acknowledging that 32-bit code for a Virtual Device Driver (VxD) in ring 0 might be written in C. Though the new Windows had a kernel, drivers and applications all in C from the start, the programming support was surely understood as primitive even from the perspective of the time. Notably, if the 32-bit C compiler was yet capable of doing 64-bit arithmetic, its ability was so recent that the Windows NT 3.1 kernel is written not to use it and the the DDK for Windows NT 3.1 defines LONGLONG and ULONGLONG as double for the i386 processor, presumably for lack of a built-in 64-bit integral type.
Something else that looks to have been relatively new in 1993 is that debugging information could be removed from the executable to a separate symbol file. Pre-release builds of the Windows NT 3.1 kernel, as can be found on the Internet at websites that preserve what they call abandonware, have the debugging information in the executable as described by the Common Object File Format (COFF). Its removal to a separate file in the released Windows NT 3.1 looks to have been new enough that the .DBG files for both NTOSKRNL.EXE and NTKRNLMP.EXE are too primitive for Microsoft’s linker to dump in any detail: feed them to dumpbin /all and the linker faults with an “Internal error during DumpDebugFile”. Among their problems by modern reckoning is that they have zero for the SectionAlignment in the IMAGE_SEPARATE_DEBUG_HEADER and their IMAGE_DEBUG_DIRECTORY for IMAGE_DEBUG_TYPE_MISC is misformed. Still, they are easily enough inspected by sight. They can even be edited so that Microsoft’s linker parses them without faulting.
What inspecting them will get for you most obviously is the matching of Microsoft’s names to the addresses of routines and variables. Of interest here is that the COFF symbol table also has IMAGE_SYM_CLASS_FILE records that name the source files that define these routines and variables. In these particular .DBG files, the names are observed to be fully qualified for source files in C but only relative for assembly-language source files. For both the debugger and the reverse engineer, it is all but mechanical to determine which routines and variables are in which source files and to put it all together for a map of where Microsoft has these source files at the time of compilation.
Thus did Microsoft from the start publish its source tree for the Windows kernel—not the source code or the source files, of course, but the directory structure in which those files were organised. For the tree below, I don’t go as far as showing which routines and variables are in which source files, just the tree of files in directories. If you browse this page with scripts enabled, then you should be able to expand the branches that interest you and collapse those that don’t.
Presumably, the i386 is in each case a subdirectory of one of the many subdirectories of D:\nt\private\ntos, but although the particular subdirectories for some can be inferred confidently, I don’t think it can be for all.
Two files are named only as “i386\raise.asm”. They are distinct. They each define only one routine: ExRaiseException and RtlRaiseException. These do eventually become exported functions but in version 3.10 they are internal routines. Almost certainly, these assembly-language source files are in the ex and krtl subdirectories.