News:

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

indirect assignment

Started by clutch, March 20, 2008, 03:10:21 PM

Previous topic - Next topic

clutch

I am reading iczelions win32 asm tutorials and have a question about some code that I cannot understand that is not explained in the tutorial. I am reading tutorial 3 and here is the program:


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib            ; calls to functions in user32.lib and kernel32.lib
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

.DATA                     ; initialized data
ClassName db "SimpleWinClass",0        ; the name of our window class
AppName db "Our First Window",0        ; the name of our window

.DATA?                ; Uninitialized data
hInstance HINSTANCE ?        ; Instance handle of our program
CommandLine LPSTR ?
.CODE                ; Here begins our code
start:
invoke GetModuleHandle, NULL            ; get the instance handle of our program.
                                                                       ; Under Win32, hmodule==hinstance mov hInstance,eax
mov hInstance,eax
invoke GetCommandLine                        ; get the command line. You don't have to call this function IF
                                                                       ; your program doesn't process the command line.
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT        ; call the main function
invoke ExitProcess, eax                           ; quit our program. The exit code is returned in eax from WinMain.

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX                                            ; create local variables on stack
    LOCAL msg:MSG
    LOCAL hwnd:HWND

    mov   wc.cbSize,SIZEOF WNDCLASSEX                   ; fill values in members of wc
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInstance
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_WINDOW+1
    mov   wc.lpszMenuName,NULL
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc                       ; register our window class
    invoke CreateWindowEx,NULL,\
                ADDR ClassName,\
                ADDR AppName,\
                WS_OVERLAPPEDWINDOW,\
                CW_USEDEFAULT,\
                CW_USEDEFAULT,\
                CW_USEDEFAULT,\
                CW_USEDEFAULT,\
                NULL,\
                NULL,\
                hInst,\
                NULL
    mov   hwnd,eax
    invoke ShowWindow, hwnd,CmdShow               ; display our window on desktop
    invoke UpdateWindow, hwnd                                 ; refresh the client area

    .WHILE TRUE                                                         ; Enter message loop
                invoke GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                invoke TranslateMessage, ADDR msg
                invoke DispatchMessage, ADDR msg
   .ENDW
    mov     eax,msg.wParam                                            ; return exit code in eax
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_DESTROY                           ; if the user closes our window
        invoke PostQuitMessage,NULL             ; quit our application
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam     ; Default message processing
        ret
    .ENDIF
    xor eax,eax
    ret
WndProc endp

end start



I am a C++ programmer learning Assembly for the first time and I can understand everything in this program except for this:


  push  hInstance
  pop   wc.hInstance


it looks like some kind of indirect assignment. but I don't understand how exactly the assignment happens. I know its assigning hInstance to wc.hInstance and that you can't use mov to assign a memory address to a memory address but fail to see how this notion of pushing and popping makes the assignment happen. could someone please explain this for me? thanks.

BogdanOntanu

Quote
  push  hInstance
  pop   wc.hInstance

That is simply wc.hInstance = hinstance;

The reason for PUSH/POP si an "optimization". There is no ASM instruction for direct moving from memory to memory. instead you have to go through using a register like this:

mov eax, hInstance
mov wc.hInstance,eax


For some reasons some people prefer the PUSH/POP pair of instructions for obtaining the exact same result. Instead of using a register to store the intermediate result this PUSH/POP method does use the stack for intermediate storage. There are less characters to type and registers are not made "dirty" by this method but that can be slower at execution time.

Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

jj2007

  push  hInstance
  pop   wc.hInstance


There is a macro for easier typing:
m2m wc.hInstance, hInstance does the push/pop sequence,
mrm wc.hInstance, hInstance uses eax for the assignment.
The latter is faster but make sure you don't need the value in eax afterwards.
See also the ACD convention: eAx, eCx and eDx are promiscuous registers and will be changed by Win APIs.



clutch

thanks for the replies but I still don't see how the assignment happens.

you push hInstance onto the stack, then you pop wc.hInstance off the stack (I didn't even know it was on the stack, but okay). how the heck does an assignment happen? to me these just look like random instructions that would do nothing but push and pop two variables on the stack.

is it just a replacement for mov for the special case of assigning memory to memory?

could I rewrite the first mov instruction to look like this:


mov eax, SIZEOF WNDCLASSEX
push wc.cbSize
pop eax


I don't see why you would want to, why use 3 (or 2 in the case of BogdanOntanu's example using mov) instructions when you can use one single mov (and not muck up the eax register), but I'm just trying to understand the concept. would that work?

jj2007

Quote from: clutch on March 20, 2008, 09:41:54 PM

mov eax, SIZEOF WNDCLASSEX
push wc.cbSize
pop eax


Well, it's the other way round:

mov eax, SIZEOF WNDCLASSEX
push eax
pop wc.cbSize


Other example:

mov My1stVar, 12345678
push My1stVar
pop My2ndVar

From the viewpoint of My2ndVar, this is the same as:

push 12345678
pop My2ndVar

Try to see it as follows: You push the 32-bit number 12345678 into a dark hole called "stack". A second later, a guy called My2ndVar goes into that hole, and when coming out, he suddenly carries the number 12345678...

clutch

okay I see it now. thanks jj2007.

looking at the layout of the actual values in your other examples helped alot. got alittle confused by the fact that hInstance is being used for the assignment (a global that appeared to be never initialized) and not hInst. but then I noticed WinMain is called with hInstance. :red

Its all clear now and I now know how to assign memory to memory. :bg

hutch--

Easy,


    push some_value    ; copy a value onto the stack
    pop another_value ; copy from stack back to another value
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php