Redefining Memory
Backwards Confusion

Pretend that EAX holds the hex number 5A6822. What does MOV EDX,EAX do?

MOV EDX,EAX

That seems rather simple. Each of the 4 bytes inside EAX are copied into EDX, in the same order as they were originally.

Backwards Byte Order
Pretend that EAX holds the hex number 5A6822. What does MOV DWORD [49E6E8],EAX do?

MOV DWORD [49E6E8],EAX

Uh, what?
Yes - believe it or not, anytime you store numbers to memory, the bytes are loaded backwards.

But what if you store DWORD [49E6E8] back into some register? Let's say ECX.

MOV ECX,DWORD [49E6E8]

The bytes are loaded backwards again. That means ECX holds the correct number (5A6822), and so the following code still does exactly what it should do:
MOV EAX,5A6822            ;Store hex number 5A6822 to EAX.
MOV DWORD [49E6E8],EAX    ;Store contents of EAX to the DWORD at address 49E6E8.
MOV ECX,DWORD [49E6E8]    ;Store 5A6822 back into ECX.
Little Endianness
In x86 assembly, the byte order is backwards for memory locations. This means that numbers are loaded "little-end" first and "big-end" last if you're dealing with memory. The x86 assembly language is a little-endian assembly language.

The little end refers to the rightmost byte inside any register, and the big end refers to the leftmost byte.

MOV ECX,DWORD [49E6E8]

The reason the rightmost byte in a register is the little end is because changing the rightmost byte produces a little change in the whole number. If EAX holds 069AC030, and I add 1 to the little end byte, then the number becomes 069AC031. That's not much of a difference.

The leftmost byte is the big end because changing that byte produces a big change in the whole number. If EAX holds 069AC030, and I add 1 to the big end byte, then the number becomes 079AC030. That's a significant difference.

Some computer processors use big-endian memory locations instead of little-endian memory locations. For example, the Motorola 6800 uses big-endian memory, so all of its numbers are stored the sensible way (byte order is left to right) instead of the weird way (byte order is right to left).

Of course, x86 computer chips, which are the ones we will use, always work with little-endian memory. This means you have to remember that bytes are always stored into memory the weird way (backwards!).

When Is Little Endianness Important?
Take a look at the following piece of data. Yeah, I said data, not code.
Address    Bytes (written in little-endian)
49E66C     20 10 50 88
49E670     03 07 AB 45
We're just going to pretend that DWORD [49E66C] and DWORD [49E670] hold these bytes. In reality, DWORD [49E66C] is the player's X-velocity and DWORD [49E670] is the player's Y-velocity. Normally when the game is running, neither number would be so large.

We can also look at the same data in a different way by looking at 1 address at a time. Each address is worth 1 byte.
Address    Bytes
49E66C     20
49E66D     10
49E66E     50
49E66F     88
49E670     03
49E671     07
49E672     AB
49E673     45
So, what does the following code do?
MOV EAX,DWORD [49E66C]
MOV ECX,DWORD [49E670]
MOV EDX,DWORD [49E66F]
The result is best illustrated with a diagram:

Little endian storage

Therefore, the code actually does this:
MOV EAX,DWORD [49E66C]   ;Store hex number 88501020 to EAX.
MOV ECX,DWORD [49E670]   ;Store hex number 45AB0703 to ECX.
MOV EDX,DWORD [49E66F]   ;Store hex number AB070388 to EDX.
We now can tell that the player's X-velocity has a value of 88501020 (a really huge number!), and the player's Y-velocity is 45AB0703.
EDX holds the number AB070388, which is a meaningless combination of X-velocity and Y-velocity.

When Is Little Endianness Not Important?
SUB DWORD [49E66C],201
MOV EAX,DWORD [49E66C]
Imagine that DWORD [49E66C] holds the number 7301. What does the above code do?

It sets DWORD [49E66C] to the number 7100. In hex, 7301 - 201 = 7100.
After that, it stores the number 7100 to EAX.

In this case, you didn't have to think about little-endianness to predict what the instructions would do.
In reality, the hex number 201 is interpreted by the computer as the little-endian bytes 01 02 00 00, but for most purposes it doesn't matter if you ignore that fact.

Navigation
Previous Lesson: Redefining Registers
Next Lesson: Redefining Negatives
Table of Contents