News:

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

call & ret

Started by bawrobin, March 27, 2010, 06:51:46 PM

Previous topic - Next topic

bawrobin

Hello.
Please tell me why this code compiled succesfull but when I try to "run program" nothing is appear.

Here is code:
.686p

.model flat, stdcall

option casemap:none


includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\windows.inc


.data

MsgText     db 'Calculating results is %d',0
MsgTitle    db 'ebx and eax are equal',0
buffer      db 100 dup(?)

.code


start:

mov eax, 4
mov ebx, 8
call add_it

add_it:
push eax
add eax, ebx
mov ecx, eax    ;ecx - 12
pop eax         ;eax - 4
ret



    invoke  wsprintf,ADDR buffer,ADDR MsgText,eax,1
    invoke  MessageBox,0,ADDR buffer,ADDR MsgTitle,MB_ICONINFORMATION
    invoke  ExitProcess,0


end start


When I remove "ret" at the end of code segment - program runs successfull.

Thank you.

donkey

If you follow the execution path of your program it calls add_it  and returns to the instruction after the call instruction, which is the actual proc add_it, it executes that and encounters the RET at the end, since there is no return address on the stack it simply exits the program before it get to the MessageBox function. Move the add_it proc to after the ExitProcess call and everything should be fine.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Astro

Hi,

You trashed ebx which needs to be preserved according to register preservation convention for Windows. If you don't restore this value before returning any control back to Windows (e.g. you make a call such as wsprintf), bad things can happen.

The following is fixed code:

start:

mov eax, 4
mov ecx, 8
call AddIt

invoke  wsprintf,ADDR buffer,ADDR MsgText,eax,1
invoke  MessageBox,0,ADDR buffer,ADDR MsgTitle,MB_ICONINFORMATION
invoke  ExitProcess,0

ret

;=============================

AddIt proc

add eax,ecx ; adds eax and ecx together, and puts the result in eax
ret

AddIt endp

end start


Best regards,
Robin.

qWord

Quote from: Astro on March 28, 2010, 01:29:28 AMYou trashed ebx which needs to be preserved according to register preservation convention for Windows
no.
This only applies to callback functions like the window procedure.
FPU in a trice: SmplMath
It's that simple!

Astro

I was under the impression this was any API call, or prior to exiting?

EDIT: http://msdn.microsoft.com/en-us/library/cc267758.aspx

QuoteCalling Conventions

The x86 architecture has several different calling conventions. Fortunately, they all follow the same register preservation and function return rules:

    * Functions must preserve all registers, except for eax, ecx, and edx, which can be changed across a function call, and esp, which must be updated according to the calling convention.

Best regards,
Robin.

qWord

it is as said - believe it or test it  :U
FPU in a trice: SmplMath
It's that simple!

Astro

So:

xor ebx,ebx
xor esi,esi
xor edi,edi

call SomeWindowsAPIFunction


is safe?

Best regards,
Robin.

donkey

Quote from: Astro on March 28, 2010, 03:43:53 AM
So:

xor ebx,ebx
xor esi,esi
xor edi,edi

call SomeWindowsAPIFunction


is safe?

Best regards,
Robin.

As a rule of thumb yes, that is safe. It is only in callbacks that the register preservation rules are applicable. Since all Windows functions preserve the registers they generally have no need of the data they contain so it is considered undefined. As a matter of fact the registers are often used to preserve data across an API call without having to use memory locations, for this reason the callee (the API) is expected to preserve them for you. However, with callbacks your routine is called by the Windows routine and it expects you to preserve the registers and may use them to pass data across the call to your routine, in that case unexpected behavior could result if they are modified.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Astro

Hi,

OK!

I found one API call that was trashing ecx. I'll see if I can find which one it was.

Best regards,
Robin.

donkey

Quote from: Astro on March 28, 2010, 04:52:50 AM
Hi,

OK!

I found one API call that was trashing ecx. I'll see if I can find which one it was.

Best regards,
Robin.

You will probably find hundreds, for example the lstr functions or common dialogs, ECX is not guaranteed to be preserved, only EBX, EDI, ESI and EBP, the rest are volatile (ESP is restored according to the calling convention, for STDCALL it is restored, for cdecl it is not).
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

dedndave

if you are writing a function that may be used anywhere, it is good to follow the conventions
that way, if the programmer using your function wants to use it in a callback, he can
if you are writing a procedure for a specific program, then you may be able to ignore the convention

jj2007

Quote from: donkey on March 28, 2010, 04:12:05 AM
As a rule of thumb yes, that is safe. It is only in callbacks that the register preservation rules are applicable.

Adding to what Edgar wrote: As a rule of thumb, a console program is safe because it doesn't have callbacks. Try this:
include \masm32\include\masm32rt.inc

MyTest PROTO: DWORD, :DWORD

.code
AppName db "Masm32 is great!", 0
Hello db "A message:", 0

start:
  dec esi
  dec edi
  dec ebx
invoke MyTest, offset AppName, addr Hello
  dec esi
  dec edi
  dec ebx
invoke MyTest, str$(esi), chr$("ebx:")
invoke MyTest, str$(edi), chr$("ebx:")
invoke MyTest, str$(ebx), chr$("ebx:")
exit

MyTest proc arg1:DWORD, arg2:DWORD
  dec esi
  dec edi
  dec ebx
  MsgBox 0, arg1, arg2, MB_OK
  dec esi
  dec edi
  dec ebx
  ret
MyTest endp


In contrast, you must be very careful with a Windows application because everything beyond a certain point is "inside" a callback:
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke GetCommandLine
invoke WinMain, hInstance, NULL, eax, SW_SHOWDEFAULT
invoke ExitProcess, eax

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
...
mov wc.lpfnWndProc, offset WndProc
...
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
********** vvvvv CALLBACK ZONE, watch your step vvvvv **************


Any handler, be it for WM_PAINT, a pushbutton etc., starts from inside this callback procedure and is therefore "callback zone" in the sense that you must preserve esi, edi, ebx.

MichaelW

Console apps can have a callback, see  SetConsoleCtrlHandler. In my tests under Windows 2000, while clearing EBX, ESI, and EDI in the handler had no apparent effect, setting them to the value -1 triggered an access violation.
eschew obfuscation

jj2007

Quote from: MichaelW on March 28, 2010, 08:21:57 AM
Console apps can have a callback, see  SetConsoleCtrlHandler. In my tests under Windows 2000, while clearing EBX, ESI, and EDI in the handler had no apparent effect, setting them to the value -1 triggered an access violation.


Now I must admit I am confused:
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL rc:RECT
  or esi, -1 ; let's try to crash Windows
  or edi, -1
  or ebx, -1
SWITCH uMsg
...

No effect! What's wrong?

MichaelW

I've had mixed results modifying these registers in a window procedure:
No apparent effect
A malfunction of one or more controls
An inability to close the window normally
An exception followed by a termination of my test app

Under Windows 2000 your SkelWindow app appears to hang, without displaying a window. If I comment the code that is modifying the registers then the window displays and appears to operate normally. There is no apparent problem with only EBX modified. With only ESI modified it looks like the TranslateMessageEx function triggers an access violation:

function: TranslateMessageEx
        77e14619 64a118000000     mov     eax,fs:[00000018]      fs:00000018=????????
        77e1461f 39903c070000     cmp     [eax+0x73c],edx        ds:0000074b=????????
        77e14625 7413             jz      TranslateAcceleratorW+0x131 (77e1aa3a)
        77e14627 64a118000000     mov     eax,fs:[00000018]      fs:00000018=????????
        77e1462d 053c070000       add     eax,0x73c
        77e14632 8b08             mov     ecx,[eax]              ds:0000000f=????????
        77e14634 890e             mov     [esi],ecx              ds:ffffffff=????????
        77e14636 8910             mov     [eax],edx              ds:0000000f=????????
        77e14638 eb96             jmp     GetSubMenu+0xd (77e1d1d0)
        77e1463a 8b45dc           mov     eax,[ebp+0xdc]         ss:00ba9e2a=????????
FAULT ->77e1463d 8906             mov     [esi],eax              ds:ffffffff=????????


With only EDI modified no window is displayed.

eschew obfuscation