Hi, I noticed today that the two dwords in a qword are read in a different direction. for example if I would have
integer64 dq 00001001000001110001101011010101 01100101100101000111001100101010b
Then my integer64 is being read as 01100101100101000111001100101010 00001001000001110001101011010101
Why does this happen ?
Maybe is it because lea eax,integer64
makes eax point to the last dword ? Or is this something because the hex codes are being read from right to left (for the arguments)?
(read my signature)
Quotedq 00001001000001110001101011010101 01100101100101000111001100101010b
First, I have to assume that the spaces left between the two 32-bit segments were not in your original script; otherwise, your assembler should have raised an exception with the spaces not being numerical characters.
Secondly, I have to assume that you have "printed out" the two dwords separately to get your reported result.
You must remember that numbers are kept in the "little endian" order in memory. If you had inspected the content of your memory where that qw was kept, you should have seen it stored as:
1010, 0010, 0011, 0111, 0100, 1001, 0101, 0110, 0101, 1101, 1010, 0001, 0111, 0000, 1001, 0000
As Raymond stated, what you are seeing is a result of the little-endian byte order used by x86 processors, where multi-byte values are stored in memory with the least significant byte at the lowest address, opposite of the order of the bytes in a register and the order in which we write numbers.
http://en.wikipedia.org/wiki/Endianness
include \masm32\include\masm32rt.inc
HEXDUMP MACRO address, paragraphs, zerobase
invoke HexAsciiDump, address, paragraphs, zerobase
ENDM
.data
_word dw 0102h,0,0,0,0,0,0,0
_dword dd 01020304h,0,0,0
_qword dq 0102030405060708h,0
.code
;-----------------------------------------------------------------------
; This longer name avoids a conflict with the MASM32 HexDump procedure.
;-----------------------------------------------------------------------
HexAsciiDump proc startAddress:DWORD, nParagraphs:DWORD, fZeroBase:DWORD
push ebx
push edi
push esi
mov esi, startAddress
xor ebx, ebx
.WHILE ebx < nParagraphs
mov eax, esi
mov ecx, ebx
shl ecx, 4
.IF fZeroBase
printf( "%08X ", ecx )
.ELSE
add eax, ecx
printf( "%08X ", eax )
.ENDIF
xor edi, edi
.WHILE edi < 16
mov ecx, ebx
shl ecx, 4
add ecx, edi
movzx eax, BYTE PTR [esi+ecx]
printf( "%02X ", eax )
.IF edi == 7
printf( "- " )
.ENDIF
inc edi
.ENDW
printf( " " )
xor edi, edi
.WHILE edi < 16
mov ecx, ebx
shl ecx, 4
add ecx, edi
movzx eax, BYTE PTR [esi+ecx]
.IF eax > 31 && eax < 127
printf( "%c", eax )
.ELSE
printf( "." )
.ENDIF
inc edi
.ENDW
printf( "\n" )
inc ebx
.ENDW
pop esi
pop edi
pop ebx
ret
HexAsciiDump endp
start:
HEXDUMP OFFSET _word, 1, 0
HEXDUMP OFFSET _dword, 1, 0
HEXDUMP OFFSET _qword, 1, 0
inkey
exit
end start
00403000 02 01 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
00403010 04 03 02 01 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
00403020 08 07 06 05 04 03 02 01 - 00 00 00 00 00 00 00 00 ................
But why does it happen for qwords and not for dwords? I print each bit seperately by the way
I think you missed this
Quote
Code: [Select]
00403000 02 01 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
00403010 04 03 02 01 00 00 00 00 - 00 00 00 00 00 00 00 00 ................
00403020 08 07 06 05 04 03 02 01 - 00 00 00 00 00 00 00 00 ................
If I use this instruction (esi points to the beginning of the Qword)
mov edx,[esi]
Then edx contains the first 32 bits in Big Endian (as I had stored them). is this due to characteristics of the mov instruction or am I still missing something ?
Edit:
I'm still wondering: If I would want to go through all of the bits of the 64bit integer, how would I do it ? (from lsb to msb, 2bytes at a time)
Would the following instruction fit ?
mov dx,[esi+2*ebx]
(if ebx increases from 0 to 3)
The order is indeed a bit confusing. The best option to understand it is to use OllyDbg (http://www.ollydbg.de/version2.html). Just run Olly, open the executable, press F8 and see how the registers change.
include \masm32\include\masm32rt.inc
.686p
.xmm
.code
src1 dq 01234567890abcdefh
dq 0
src2 dq 0debc0a9067452301h
dq 0
start:
mov ebx, offset src1
; in Olly, select ebx, then right-click, follow in dump
mov ecx, 0
mov cl, [ebx]
mov cx, [ebx]
mov ecx, [ebx]
movq xmm1, [ebx]
mov esi, offset src2
; in Olly, select esi, then right-click, follow in dump
mov eax, 0
mov al, [esi]
mov ax, [esi]
mov eax, [esi]
movq xmm0, [esi]
exit
end start
actually, i've gotten so used to it, it would seem awkward the other way around - lol
i remember "Little Endian" by intEL :P
Quote from: dedndave on April 30, 2014, 08:44:37 AM
actually, i've gotten so used to it, it would seem awkward the other way around
Yes, but it's only a habit and/or a convention. I guess it would be more consistent if we displayed everything from left to right, dumps and registers alike, i.e. if the least 2 bytes are 1234h, then al = 12, ax = 1234, eax=12340000
(I'm sure somebody will pop up and teach us why this would be 'against nature' 8))
The little-endian storage order is a design optimization that avoids having the operand address change with the operand size.
Thanks a lot guys, the answers really helped me a lot in understanding this :)