Currently when I write a new routine, I always wrap it up in a proc. But sometime the proc is so small and passes no parameters, that I seems it doesn't need the functionality of the call instruction.

Because there are no parameters to pass, a jmp would work fine.
I dont have masm here to try, and I'll be out of town for a few days, so... I guess I can jump to a label (duh). Can a label be declared public and extern?

I seem to be looking for a way to access code not defined in a proc across multiple source files. I've also got the feeling someone is going to say 'macro' here.
:stupid: :stupid: :stupid: :stupid: :stupid: :stupid:
Posted on 2001-08-30 17:37:03 by ThoughtCriminal
You can use call on a normal label too. But if your going to do that, you might as well use a proc so you can have locals.
Posted on 2001-08-30 19:09:36 by ChimpFace9000
If it's a short piece of code you wouldn't mind inlined... I'd go for a
macro, since you get rid of any call/ret overhead.
Posted on 2001-08-30 19:45:52 by f0dder
Hi.

If I understand you correctly, CofeeDrinker, I did that once in a similar way.

In my 6510 CPU emulator (started but never finished) I would configure it with a return address and call it using a jump and return from it using a jmp to the preconfigured return address. I don't know how much performance I would get that way, but most probably won't be much.

By the way, the "call" instruction knows nothing about parameters! That would a "invoke"s job.

In short, yes, you can call and/or jump to any label, the proc syntax is for your convenience, like to use locals or pass parameters and have the assembler automatically do the house keeping for you. But I would stick with the call/ret combo (or invoke/ret)

CarlosM7
Posted on 2001-08-30 21:15:01 by CarlosM7
CoffeeDrinker,

As you would be familiar, the CALL/RET syntax is built into the hardware so its overhead is not really a problem. Its worth disassembling a bare proc to see what you get.

EmptyProc proc
; code here
ret
EmptyProc endp

Then code a simple direct call.

label:
; code here
ret

and have a look at the difference. You will see that its no big deal.

The problem with using a jump is that you don't automatically get a return address as you do with CALL/RET so the gain you have with a single jump is lost working out where to jump to next.

Regards,

hutch@pbq.com.au
Posted on 2001-08-30 21:37:28 by hutch--
:grin: Back from vacation.

I see. You make the best point hutch:

The problem with using a jump is that you don't automatically get a return address as you do with CALL/RET so the gain you have with a single jump is lost working out where to jump to next. [\QUOTE]

If I made a jmp/call to a label, I can't just ret back to where I was. I would need another unique label to jmp/(ret?) back to.

jmp code
done:

-----

code:
xor eax,eax
jmp done

That would kinda mess-up readability, and tax my ability to think up label names.
Posted on 2001-09-04 14:53:04 by ThoughtCriminal
Tail-call optimization was popular when parameters were passed in registers instead of on the stack.

Example:
RoutineA:   ; register-only parameters

; PROC not used, so there is no prolog/epilog code being generated
; ... your main code
invoke RoutineB ; register-only parameters
ret ; invoke/call immediately followed by "ret"
"Tail-call" optimization replaces invoke-ret pair with simple jmp:
RoutineA:   ; register-only parameters

; PROC not used, so there is no prolog/epilog code being generated
; ... your main code
jmp RoutineB ; register-only parameters
======

The following is an extreme use of tail-call optimization. It implements the following C code:
LRESULT CALLBACK WndProc(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)

{
switch (iMsg)
{
case WM_DESTROY: return OnDestroy(hWnd, iMsg, wParam, lParam);
// ... other cases coded like WM_DESTROY/OnDestroy ...
default: return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
}

// Example case
LRESULT OnDestroy(HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)
{
PostQuitMessage(0);
return 0;
}
The optimization relies on every call (to a message handler) having the same parameters and return value as WndProc.
WndProc:   ; avoid PROC prolog

; the following dispatch code avoids using EBX, ESI, and EDI
; it also avoids altering EBP
mov eax,[esp+8] ; get second arg, the message code
cmp eax,WM_DESTROY
je OnDestroy
; ... several CMP/JE pairs
jmp DefWindowProc ; other messages get default handling
; End of dispatch code

; Example case
; use standard calling convention
OnDestroy proc STDCALL hWnd:HWND, iMsg:DWORD, wParam:DWORD, lParam:DWORD
invoke PostQuitMessage, 0
xor eax,eax
ret
endp
Posted on 2001-09-04 18:51:28 by tank