Pretend that EAX holds the hex number 5A6822. What does MOV EDX,EAX do? 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? 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. 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. 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 45We'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 45So, 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: 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.
Previous Lesson: Redefining Registers Next Lesson: Redefining Negatives Table of Contents |