I found some strange problem when I was writing some code which uses callback function:

someprocedure proc

.while ...

.if ...

;notice the code bellow -

push ...
push ...
call getCellProc

;

.endif


.endw...


someprocedure endp


I getCellProc I intensively use registers, not worying about anything, but :)!!!!!

when I use ebx register, it starts to act strangely! And when I change ebx to lets say edx, everything is ok :)

example

;This hangs and use 100% of procesor ( dead loop )

getCellProc proc

mov ebx, 01h
mov eax, ebx
ret

getCellProc enp

;This works normaly

getCellProc proc

mov edx, 01h
mov eax, edx
ret

getCellProc enp

Are there any limitations of using registers in using high level syntax functions under masm?

Regards, Ulterior
Posted on 2004-03-16 01:26:54 by Ulterior
Thats because callback procedures expect ebx esi and edi to be unchanged. If you use any of these restore them before the callback returns.
Posted on 2004-03-16 01:39:00 by ENF
ebp and the direction-flag must remain unchanged, too. Basically windows assumes you're following the MS C-compiler standard with regards to register usage and preservation.
Posted on 2004-03-16 04:45:17 by f0dder
But I am not using ebp register :(

.elseif cellNum == 2

invoke Get_IB71_FldInt, pRec, FLD_SCHEDULE_TASKID
mov tempInt, eax

.if ebx == 0 -->with this line application crashes

.if tempInt == 0
lea eax, schedule_task_0
.elseif tempInt == 1
lea eax, schedule_task_1
.elseif tempInt == 2
lea eax, schedule_task_2
.elseif tempInt == 3
lea eax, schedule_task_3
.elseif tempInt == 4
lea eax, schedule_task_4
.elseif tempInt == 5
lea eax, schedule_task_5
.endif
.endif

mov ret_str, eax

.elseif cellNum == 3

Please look at the code above and tell me what's wrong with using ebx register??
When I comment this .if statement - everything's ok...
Posted on 2004-03-16 05:46:38 by Ulterior
It doesn't matter if you are using HLL syntax or not.

If you are using EBX in a callback (for example, a wndproc or a dlgproc), then you must preserve the register. This means that you save the register value before using the register, and restore the value when you are done.

You must also do this for ESI and EDI, if you use them. If you do not use these registers, you will not need to preserve them.

*** Solution 1

The easiest way to do this is with the USES clause in the PROC directive.

WndProc PROC USES EBX hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

This creates at the beginning of the PROC:

PUSH EBX

And it generates before every RET:

POP EBX

*** Solution 2

You can also manually put the PUSH and POP around the code that uses EBX.

PUSH EBX ; save value in EBX
;... insert code that uses EBX here
POP EBX ; restore value that was in EBX
Posted on 2004-03-16 14:58:34 by tenkey
Ulterior

The use of that .if ebx == 0 line cannot be the cause of a crash by itself due to such usage of the EBX register. Its value is not changed.

However, IF the EBX register happens to be equal to something else than 0, you would then skip all the instructions loading the EAX register with some value which must be used later to perform some function. And the probability that EBX is NOT equal to 0 is extremely high unless you had changed it yourself.

Just to prove it to yourself, change that line to:

.if ebx != 0

Raymond
Posted on 2004-03-16 23:11:20 by Raymond