Can someone explain how to use high-order and low-order bytes? I might not be phrasing my question right but maybe someone can explain what they are. A lot of API functions return a value containing a high-order and low-order byte and I don't really know how to use them. For instance HKM_GETHOTKEY returns high-order byte containing modifier keys, and a low-order byte containing other keys. But how to seperate them and send them to RegisterHotKey is a mystery to me. I thought I'd start a new topic since the question is different.
Thanks :bg
Telefunken,
It has to do with the SIZE of the data you wish to access and what its original size happens to be. 4 of the general purpose registers can be accessed as 4 byte, 2 byte or 1 byte and this is basically how you access a low and high byte.
The AL part of EAX holds the LOW byte.
The AH part of EAX holds the HIGH byte.
Thanks for the reply. :bg
Sorry if I'm being to much of a nub. :red
I get what your saying, but I don't fully understand. Is there a website or something that explains it?
Sorry,
I should have made better sense of the reply.
With the 32 bit registers EAX ECD EDX and EBX they can all be split down to smaller parts becausae of the 8 and 16 bit registers that they also encompass. To use the EAX register as an example,
AL and AH are the same as AX ; 2 x 8 bit registers make a 16 bit register.
AX is the low WORD of EAX and to set or get the HIGH WORD of EAX,
you must rotate the register by 16 bits so that you access the other end of it as AX again.
Have a look at the help file in MASM32 from the HELP menu of the editor called ASM Intro help and look at the topic REGISTERS as this explains how the 32 bit registers work. Once you get the swing of it, its really simple.
The four bytes that make up the dword register eax from lowest to highest
0, 1, 2, 3 can be accessed four ways byte 0 or byte 1,the low word , the full dword
.data
var8lo db 021h
var8hi db 043h
var16 dw 04321h
var32 dd 087654321h
.code
mov al, var8lo ; store a byte in the lowest byte of eax ( byte 0)
mov ah, var8hi ; store a byte in the next byte of eax ( byte 1)
mov ax, var16 ; store a word in the lower word of eax ( word 0 which is also bytes 0, 1 )
mov eax, var32 ; store a dword in the full dword of eax ( bytes 0, 1, 2, 3 )
; ebx, ecx, edx components can be accessed the same way
Thanks Hutch for explaining and dsouza for showing me how to use them! I think I understand now.
Thanks again :U
But I have a question...
why is this not possible?
mov something1,al
mov something2,ah
Heh, oops, nevermind. I forgot that al and ah were only 1 byte. So i need to use db instead of dd, or dw :)
Quote from: Telefunken on July 22, 2006, 03:43:53 AMwhy is this not possible?
mov something1,al
mov something2,ah
Heh, oops, nevermind. I forgot that al and ah were only 1 byte. So i need to use db instead of dd, or dw :)
It IS possible. Assuming that something1 is a memory location, the assembler "knows" that AL and AH are byte-length registers, so it "understands" that you want to store a byte only. You don't need to specify BYTE PTR there. Just as if you wrote MOV something1, EAX it "knows" that EAX is a DWORD-sized register, so it will be storing all 4 bytes in EAX to the 4 consecutive memory bytes pointed to by something1.
Where you generally have to specify the DWORD PTR/WORD PTR/BYTE PTR modifier is where something1 was defined as a
different-sized variable to the size of data you are trying to store. So if you specified something1 as a DWORD variable in your data section, MASM will complain if you try to store AL there, because this is a single byte. In this way the BYTE PTR modifier is a sort of "cast", to use the C terminology, to temporarily resize the variable to accept the type of data you want to store there. It's a very basic form of type-checking which you can explicitly over-ride, in other words.
The other reason you may need the modifier is where the size of data you are trying to store is not explicit, for example if the value is immediate: MOV something1, 1 - does this mean a BYTE 1, a WORD 1 or a DWORD 1? The assembler needs to know, so again will demand that the memory location is "cast" to specify the data size.
Ian_B
This show the reverse of above, with variables/memory storage getting the values from different size registers,
really just separately accessable parts of a 32 bit general register.
Also showing overides of the natural size that the variables would get.
.data
get8lo db 0
get8hi db 0
get16 dw 0
get32 dd 0
barr db 12 dup (0)
.code
start:
mov eax, 087654321h
mov get8lo, al ; get8lo gets 21h, get8lo is a byte size variable so it naturally gets a value from a byte size (partial) register
mov get8hi, ah ; get8hi gets 43h
mov get16, ax ; get16 gets 4321h
mov get32, eax ; get32 gets 87654321h
mov byte ptr get16, ah ; copy 43h from ah to the low byte of get16, becoming 4343h
; overiding the natural size the word variable gets
mov dword ptr barr, eax ; copy 87654321h from eax to the first 4 bytes of barr an array of bytes
mov ax, 0fadeh ; only overwriting the lower word, eax now has 08765fadeh
mov word ptr barr+6, ax ; copy 0fadeh to barr starting at byte position 6, barr holds 21 43 65 87 00 00 de fa 00 00 00 00 low to high
; because Intel/AMD x86 is little endian (low byte is stored at a lower address)
; and the convention of reading/writing left to right, that is why barr was shown that way
; this is also the way debuggers/hexeditors I've used display values
; if shown high to low with the high address on the left then barr would be
; 00 00 00 00 fa de 00 00 87 65 43 21
I'm pretty sure I understand now. But, theres something that doesn't make sense to me.
invoke SendDlgItemMessage,hWin,1002,HKM_GETHOTKEY,0,0
mov hotkeytest,al
mov modkey1,ah
invoke RegisterHotKey,hWin,001h,modkey1,hotkeytest
For some reason, this won't work. Also when I look at this chunck of code in Olly, it looks like this
Starting with mov hotkeytest,al....
00401106 . A2 BE304000 MOV BYTE PTR DS:[4030BE],AL
0040110B . 8825 BD304000 MOV BYTE PTR DS:[4030BD],AH
00401111 . 6A 00 PUSH 0
00401113 . A0 BE304000 MOV AL,BYTE PTR DS:[4030BE]
00401118 . 66:0FB6C0 MOVZX AX,AL
0040111C . 66:50 PUSH AX
0040111E . 6A 00 PUSH 0 ; /Key = 00
00401120 . A0 BD304000 MOV AL,BYTE PTR DS:[4030BD] ; |
00401125 . 66:0FB6C0 MOVZX AX,AL ; |
00401129 . 66:50 PUSH AX ; |Modifiers
0040112B . 6A 01 PUSH 1 ; |HotKeyID = 1
0040112D . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401130 . E8 29040000 CALL <JMP.&user32.RegisterHotKey> ; \RegisterHotKey
Why is it pushing 0 after it pushes AX? I'm thinking it's some kind of buffer problem, but I am unsure. Any ideas?
Quote from: Telefunken on July 22, 2006, 03:48:33 PM
I'm pretty sure I understand now. But, theres something that doesn't make sense to me.
invoke SendDlgItemMessage,hWin,1002,HKM_GETHOTKEY,0,0
mov hotkeytest,al
mov modkey1,ah
invoke RegisterHotKey,hWin,001h,modkey1,hotkeytest
You are not matching the input parameters with those expected:
Quote from: MSDNBOOL RegisterHotKey( HWND hWnd,
int id,
UINT fsModifiers,
UINT vk
);
Quote from: user32.incRegisterHotKey PROTO :DWORD,:DWORD,:DWORD,:DWORD
So you should be pushing 4 DWORDs. Your modkey1 and hotkeytest variables MUST be defined as DWORDs to use them as function parameters in this way. Alternatively, if they are only byte-sized values (AL and AH) then convert them to full DWORDs before using and saving, which is what MASM has tried unsuccessfully to do:
invoke SendDlgItemMessage,hWin,1002,HKM_GETHOTKEY,0,0
; EITHER if hotkeytest and modkey1 are BYTE-length variables:
mov hotkeytest,al
mov modkey1,ah
movzx ecx, al ; convert byte to DWORD by extending with zeroes
movzx edx, ah
; OR if hotkeytest and modkey1 are DWORD-length variables:
movzx ecx, al ; convert byte to DWORD by extending with zeroes
movzx edx, ah
mov hotkeytest,ecx
mov modkey1,edx
invoke RegisterHotKey,hWin,1,edx,ecx
; 1 is a DWORD-sized 1 here as that is what was PROTOd for this function
Ian_B
Ian_B, thank you for explaining this to me. I wouldn't have known otherwise. How exactly does movzx work?
MOVZX extends a smaller register into a larger one by padding the top with zeroes. So:
MOV AL, 1 ; AL = 01H
MOVZX EAX, AL ; zero-extend AL into EAX, EAX now 00000001H
You can extend a BYTE into a WORD or DWORD, or a WORD into a DWORD:
MOVZX DX, AL ; WORD from BYTE
MOVZX EDX, DX ; DWORD from WORD
There's also a sign-extend version of this op, MOVSX. This uses the top bit of the smaller register to determine the sign and extends that sign through the larger register:
MOV AL, 130 ; AL = 082H, can be a negative value as top bit is set
MOVSX EAX, AL ; top bit extends to keep sign: EAX = 0ffffff82H
MOV CX, 1 ; CX is not negative, top bit unset
MOVSX EAX, CX ; sign bit extends: EAX = 00000001H
Ian_B
Thank you Ian_B, I got everything working :bg
Heres the code i ended up using:
invoke SendDlgItemMessage,hWin,1002,HKM_GETHOTKEY,0,0
movzx ecx, al ; convert byte to DWORD by extending with zeroes
movzx edx, ah
invoke RegisterHotKey,hWin,1,edx,ecx
Invoke appears to have trouble when pushing byte parameters in that it only extends them to a WORD, rather than a DWORD. Sometimes it tries to balance it up, but in most cases it doesn't appear to work properly.
The workaround is what you've done, move it into a register and use that instead.
Cheers,
Zooba :U
hi dsouza123
Quote; ebx, ecx, edx components can be accessed the same way
i want to ask about - esi - edi - , as i know i can't access them the same way you mentioned, so how can i access the low - high bytes of these registers ?
i think in put their data in eax or edx, and then do what i want , and then put them back to the ( edi - for example)
but i don't know if there is other ways ??
thank you.
Dasar,
You cannot access the content of ESP EBP ESI or EDI in that manner as it is built into the hardware this way. You can access these 4 registers as a WORD value as they have a corresponding SP BP SI and DI that are 16 bit but there are no BYTE sized versions of these registers.
Quote from: hutch-- on July 23, 2006, 07:28:02 AM
Dasar,
You cannot access the content of ESP EBP ESI or EDI in that manner as it is built into the hardware this way. You can access these 4 registers as a WORD value as they have a corresponding SP BP SI and DI that are 16 bit but there are no BYTE sized versions of these registers.
thank you
hutch..
but as i understood from what you said:
i can access these registers only as WORD value, so why they do "Extended" ? i mean why they didn't let it SP, BP, SI, DI, why they make them extended registers while we can't access them as DWORD value ???
or, do you mean that the
smallest value i can access in these registers is WORD value ?
maybe i misunderstood...
You misunderstood. He meant the smallest value you can access them as is a word value. The extended versions are dwords.
thanks
The registers EAX, EBX, ECX, EDX have four methods of full or partial access, example EAX, AX, AH, AL for 32, 16 low, 8, 8 lowest bits
The registers ESP, EBP, ESI, EDI have two methods full dword and low 16 bit/word, example ESI, SI.
There are different ways of getting at the parts of a register, some not directly accessable, without losing register contents.
.data
get8 db 0
get16 dw 0
get32 dd 0
.code
xchg eax, esi ; exchange eax and esi
mov get8, al ; get lowest byte
mov get8, ah ; get next to lowest byte
mov get16, ax ; get low word
xchg eax, esi ; re exchange eax and esi
xchg eax, esi
bswap eax ; swap byte order from 0, 1, 2, 3 to 3, 2, 1, 0 low to high (little endian) Intel to high to low (big endian)
mov get8, al ; get formerly highest byte
mov get8, ah ; get formerly next to highest byte
mov get16, ax ; get formerly high word with bytes swapped
mov get32, eax ; get dword in reverse byte order
bswap eax ; swap back to original order
xchg eax, esi
bswap esi
mov get32, esi ; less involved way to get esi in reverse byte order
bswap esi
; for ror and rol the carry and overflow flags will be overwritten
ror esi, 16
mov get16, si ; get high word
rol esi, 16
ror esi, 8
mov get16, si ; get word made of bytes 1 and 2 from bytes 0, 1, 2, 3 from low to high
rol esi, 8
mov get16, si ; get low word
; to get a single bit from a 32 bit register various flags overwritten
bt esi, 7 ; high bit of low byte copied to carry flag
setc get8 ; carry flag stored in bit 0 of byte, the full value of the byte is 0 or 1, if CF zero then byte gets 0, else not zero byte gets 1
test esi, 128 ; AND with value of only high bit of low byte set
setnz get8 ; reverse of zero flag value put in bit 0 of byte, the value of the byte is 0 or 1 if zero gets 0, not zero gets 1
add esi, 0 ; sign flag gets value of bit 31
sets get8 ; sign flag put in bit 0 of byte, value 0 or 1
There are other ways that may involve temporary storage in memory or the stack, there are also destructive methods.
edi, esi, eip, esp can be accesed at word level, using di, si, ip, sp; anyway, don't mess with eip and esp yet. if you want to work at byte level, yes, you can transfer edi\esi to eax\ebx\ecx... or di\si to ax\bx\cx... work with it and put it back. or you can put your value in memory, work with it and then, when it's final, put it in your edi\esi. Don't forget that you should preserve ebx, edi and esi values, so "uses ebx edi esi" would be a good ideea.
thank you for every one give me any info about my question ^_^