June 27th, 2019
mind blown1 reaction

Why does the Get­Version function report the major version in the low-order byte, and the minor version in the high-order byte?

Laura Butler wonders whose idea it was to have the Get­Version function report the major version in the low-order byte, and the minor version in the high-order byte. This is completely messed up: You clearly should put the major version in the high-order byte and the minor version in the low-order byte, so that you can do things like

if (HypotheticalBetterGetVersion() >= 0x030A) {
  // version is at least 3.10
}

Instead, as things stand today, the major version in the low-order byte, and the minor version in the high-order byte, so version 3.10 is reported as the value 0x0A03, which leads to mistakes like this:

// Code in italics is wrong
if (GetVersion() >= 0x0A03) {
  // incorrect check for version ≥ 3.10
}

Why is the version number reported in such a strange way?

Rewind to MS-DOS.

MS-DOS has a Get Version system call, and it returns the operating system version in the same reversed way, with the major version in the low-order byte, and the minor version in the high-order byte.

The thinking was that programs will almost always be checking the major version exclusively, because the only time you’d need to check the minor version is if you needed to check for some feature that was added in a minor version. But by definition, minor versions don’t add many features (right?), so checking for the minor version should be very rare.

During this era, programs were written in assembly language, and that’s the detail that shines light on the unusual format of the version number.

On the 8086, the 16-bit AX register can be treated as a 16-bit value, or it can be treated as two 8-bit values. If you treat it as two 8-bit values, then the high-order byte is called AH, and the low-order byte is called AL.

The 8086 instructions to compare the values in these registers are encoded as follows:

Instruction Encoding
CMP AL, 03h 3C 03
CMP AH, 03h 80 FC 03

Since almost everyone will be comparing the major version, we should put the major version in the location that is most efficient to consume, and that would be the AL register. Putting the value there permits a shorter instruction encoding than if the value had been in the AH register.

It saves a byte!

The IBM PC came in two memory configurations, 16KB and 64KB. If you had shelled out the big bucks for the 64KB version, that one byte is 0.0015% of your total memory. Scaled to a modern 8GB system, choosing this format for the version number saves 128KB.

Windows adopted the version numbering scheme from MS-DOS, and that’s why the Get­Version function returns the major and minor versions in reverse order.

Topics

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

17 comments

Discussion is closed. Login to edit/delete existing comments.

Sort by :
  • Daniel Marschall

    Hello, I have a question in regards Version-Information. I have looked at the version information of the SQL Server 2017 setup (original filename “SqlSetupBootstrapper.exe”) which has the version attribute “GoldenBits” with value “True”. I did not find any information about “GoldenBits”. I am curious what purpose it has, or if it is just some kind of easteregg 🙂

  • John Elliott

    Thought I’d posted this before, but perhaps it got filtered as spam.

    I suspect, based on comments in the published MS-DOS 2.0 source, that MS-DOS (2.x+) returns the major version in AL for compatibility with MS-DOS 1, which doesn’t implement that function, and returns AL=0 leaving AH unchanged. In practice this means it returns 3000h. So if MS-DOS 2 had returned the major version in AH, there would have had to be special case checks for a major version of 30h; but by returning the major version in AL, checks for ‘AL >= 2’ will work as expected.

    • Raymond ChenMicrosoft employee Author

      Sorry, it got held for too many links. I fixed the formatting and approved it.

  • John Elliott

    The published MSDOS 2.x source code for the Get_Version function says:
    <code>
    And looking at the MS-DOS 1.25 source in the same release:
    <code>
    So... that suggests MSDOS 2.0 returned the major version in AL for backward compatibility: MSDOS 1.x would return AH=30h, AL=00h. And if you're checking for 'major version >= 2' you don't want to be special-casing 'except if major version = 30h'.

    Read more
  • Yuhong Bao

    This reminds me of the “Windows 3.95” debacle. I wonder how many software required Windows 3.1 in 1993 and 1994.

    • Jernej Simončič

      That was done because programs did comparisons like `if (version.major >= 3 && version.minor >=1)`