News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

I'm trying to undersand how the RET mnemonic works, when do I use it?

Started by pk1983, May 27, 2012, 06:25:37 AM

Previous topic - Next topic

pk1983

Hello, I have begun to learn assembly and I'm trying to understand the following code:

.386
.model flat, stdcall
option casemap :none
include E:\masm32\INCLUDE\windows.inc
include E:\masm32\INCLUDE\kernel32.inc
include E:\masm32\INCLUDE\user32.inc
includelib E:\masm32\LIB\kernel32.lib
includelib E:\masm32\LIB\user32.lib

WinMain proto :DWORD, :DWORD, :DWORD, :DWORD

.data
ClassName db "WinClass", 0
AppName db "Simple Window", 0
.data?
hInstance HINSTANCE ?

.code
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke WinMain, hInstance, NULL, NULL, 0
invoke ExitProcess, eax

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR,
CmdShow:DWORD
local wc:WNDCLASSEX
local msg:MSG
local hwnd:HWND

mov wc.cbSize, SIZEOF WNDCLASSEX
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

invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW\
or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,\
CW_USEDEFAULT, NULL, NULL, hInst, NULL
mov hwnd, eax

.while TRUE
invoke GetMessage, addr msg, NULL, 0, 0
.break .if (!eax)
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
.endw

mov eax, msg.wParam
ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.if uMsg == WM_DESTROY
invoke PostQuitMessage, 0
.else
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.endif
xor eax, eax
ret
WndProc endp
end start


As I understand it, the ret mnemonic returns to the next instruction that comes after the called function.

Why isn't there a ret mnemonic after the CreateWindowsEx function and the GetMessage, TranslateMessage, and DispatchMessage functions?

On the other hand, it's there after the while loop and DefWindowProc and WndProc.

I'm sorry if this question is dumb, but I really want to understand when to use the ret mnemonic, and when to not use it.

BogdanOntanu

RET (return) is used to finish / exit from a procedure or function.

Theoretically each procedure should have at least one return but it can have many if the procedure exits in multiple places.

There is no RET after GetMessage or TranslateMessage or DispatchMessage simply because in the logic of WinMain procedure there is no need for an exit from the procedure at that location.

There is an RET lower in the body of the procedure after the WHILE loop ends because that is the location where the programmer wanted the procedure to exit.

DO you know any other programming languages? Do you understand the concept or "returning" from a function?

The ASM RET mnemonic and instruction is pretty much the same as the "return" keyword of C programming language for example.

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

pk1983

Quote from: BogdanOntanu on May 27, 2012, 07:34:25 AM
RET (return) is used to finish / exit from a procedure or function.

Theoretically each procedure should have at least one return but it can have many if the procedure exits in multiple places.

There is no RET after GetMessage or TranslateMessage or DispatchMessage simply because in the logic of WinMain procedure there is no need for an exit from the procedure at that location.

There is an RET lower in the body of the procedure after the WHILE loop ends because that is the location where the programmer wanted the procedure to exit.

The ASM RET mnemonic and instruction is pretty much the same as the "return" keyword of C programming language for example.

Thank you for the explanation.

Quote from: BogdanOntanu on May 27, 2012, 07:34:25 AM
DO you know any other programming languages? Do you understand the concept or "returning" from a function?

I only know the basics of C (including arrays, functions and pointers), and I know what the return statement does in a C function.

MichaelW

I hope this makes sense, build as a console app.

;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================
    .data
    .code
;==============================================================================

;-----------------------------------------------------------------------------
; These options effectively turn off the automatically generated prologue and
; epilog code, so the only code in the procedure is the code that you see.
;-----------------------------------------------------------------------------

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

testproc proc arg1:DWORD, arg2:DWORD

    ;-----------------------------------------------------------------------
    ; ESP always contains the address of the last item to be pushed and the
    ; next in line to be popped. At this point the last item to be pushed
    ; (as an integral part of the CALL instruction) was the return address
    ; (IOW the address of the next instruction after the call instruction).
    ;-----------------------------------------------------------------------

    mov eax, [esp]                      ; get value at stack pointer

    printf("return address %Xh\n",eax)  ; display it

    ;------------------------------------------------------------------------
    ; Since the arguments are pushed onto the stack before the call, and the
    ; stack "grows" downwards (from higher addresses to lower addresses) as
    ; items are pushed, the arguments will be located on the stack above the
    ; return address.
    ;------------------------------------------------------------------------

    mov eax, [esp+4]
    printf("value of arg1 %Xh\n",eax)
    mov eax, [esp+8]
    printf("value of arg2 %Xh\n",eax)

    ;------------------------------------------------------------------------
    ; The RET instruction effectively pops the return address from the stack
    ; and uses it as a jump destination.
    ;
    ; The constant 8, which would normally be generated by the assembler but
    ; which must be added manually here, specifies the number of bytes to
    ; add to the stack pointer after the return, to effectively remove the
    ; arguments from the stack.
    ;------------------------------------------------------------------------

    ret 8

testproc endp

;---------------------------------------------------------------
; Turn the default prologue and epilog code generation back on.
;---------------------------------------------------------------

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

;==============================================================================
start:
;==============================================================================

    push 2
    push 1
    call testproc
  ra1:
    printf("return address %Xh\n\n",ra1)

    invoke testproc,1,2
  ra2:
    printf("return address %Xh\n\n",ra2)

    inkey
    exit
;==============================================================================
END start


return address 401044h
value of arg1 1h
value of arg2 2h
return address 401044h

return address 401060h
value of arg1 1h
value of arg2 2h
return address 401060h




Well Microsoft, here's another nice mess you've gotten us into.

RandomUsername

Rets are there becouse WndProc its a callback function (a function than windows call for you) so after calling DefWindowProc you pass the control to windows again same with the call at the end of WndProc when you finish evaluating msg and you must return.

pk1983

Thank you!

I wasn't thinking correctly about this. I understand it now.

hutch--

Lets try this out, for ever call EXECUTED you need to have a ret but with multiple exits in a procedure/function, only 1 ret is used. It is not the instruction count that matters, it is the instructions EXECUTED that do matter.

A RET can do extra things, if the function is of the STDCALL convention, the RET statement can have a trailing number that is used to balance the stack, something that must be done in any function call. Normally with a C calling convention the procedure only executes a bare RET and the code that called the function must balance the stack on return from the function.

Multiple exit conditions are common in software, multiple extry conditions are a bit more complex as there are a number of ways of doing it, you can use a C calling convention with a variable number of arguments and you can use in both C and STDCALL calls the address of a structure as is common in modern C++.

In assembler you can do any of these variations without any great effort, all you need to do is understand the basics of what you are doing and you can roll your own.

Vortex

Hi pk1983,

You can examine the code below with a debugger like Ollydbg. The pop and jmp instructions are simulating the job of RET.

.386
.model flat,stdcall
option casemap:none

include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\masm32.inc


includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\masm32.lib


.data

msg         db 'RET simulator',0

.code

start:

    call    testproc
    invoke  Beep,1000,1000
    invoke  ExitProcess,0

testproc PROC

    invoke  StdOut,ADDR msg
    pop     eax         ; get the return address from the stack
    jmp     eax         ; jump back to the main procedure
                        ; the execution will continue from
                        ; invoke Beep,1000,1000
   
testproc ENDP

END start

kroz

RET gets your comp back to executing the code after the CALL instruction. example:

call ASDF_P
xor eax, eax <<--------------------------------+
etc...                                                          |
etc...                                                          |
ASDF_P PROC                                            |
                                                                 |
mov eax, blahblah                                     |
xor eax, eax                                              |
ret ; this instruction brings you back here+

hope this helps :P i know the line's not straght :D

Vortex

Hi kroz,

Your explanation is OK. You can enclose the code portion between the [code ] tags and the lines will be straight.