News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

high-order and low-order byte

Started by Telefunken, July 22, 2006, 12:02:57 AM

Previous topic - Next topic

Telefunken

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

hutch--

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.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Telefunken

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?

hutch--

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.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

dsouza123

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

Telefunken

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 :)

Ian_B

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

dsouza123

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

Telefunken

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?

Ian_B

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

Telefunken

Ian_B, thank you for explaining this to me. I wouldn't have known otherwise. How exactly does movzx work?

Ian_B

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

Telefunken

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

zooba

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

Dasar

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.