Hi,
Actually right now i am a bit confused,
the documentation says that you can have nested procedures but when i compile the compiler says that i can not nest procedures ! whats this !?

Actually My main procedure is a thread procedure and i wanted to have local procs. Is this why the compiler wouldn't compile?

In cases such like the above, how would i declare a local procedure?
If i write the procedure in my main, and I call that procedure from my thread only, what would i be doing? I mean now, is this a local proc or global proc?

.code

ReceiveFileThread proc dwParam :DWORD
blah
blah
; My Main procedures code goes here

ret ;<<-- end of main

LocalProc proc
blah
blah

ret
localProc endp

ReceiveFileThread endp
Posted on 2002-02-15 07:10:45 by Ray
the only way ive been able to get a procedure to work inside another is to call/invoke it from inside the procedure while the other resides outside:

.code

ReceiveFileThread proc dwParam :DWORD
blah
blah
invoke LocalProc; My Main procedures code goes here

ret ;<<-- end of main
ReceiveFileThread endp

LocalProc proc
blah
blah

ret
localProc endp


since you want to nest your main procedure inside another im not sure how well that will turn out.
Posted on 2002-02-15 08:08:39 by smurf
Hiya Smurf,

actually thats what i am trying to do here,
but it doesnt allow me for some reason:
this is the error i get:

error A2144: cannot nest procedures

any ideas?
Posted on 2002-02-15 08:27:53 by Ray
Hi Ray

You can not declare a proc inside a proc like this:

MyProc1 proc

invoke MyProc2
ret

MyProc2 proc


ret

MyProc2 endp

MyProc1 endp

You can however hav a local sub inside a proc.

MyProc1 proc

call MySub
.
.
call MySub
ret

MySub:
.
.
retn <--- note: you must use retn if you have locals or args.

MyProc1 endp

KetilO
Posted on 2002-02-15 10:14:38 by KetilO
KetilO: is there any way to pass paramters to MySub?
Posted on 2002-02-15 10:38:50 by smurf
Hi,
the following was copied from "The Art of Asm"



11.2.2 Nested Procedures

MASM allows you to nest procedures. That is, one procedure definition may be totally enclosed inside another. The following is an example of such a pair of procedures:

OutsideProc proc near
jmp EndofOutside

InsideProc proc near
mov ax, 0
ret
InsideProc endp

EndofOutside: call InsideProc
mov bx, 0
ret
OutsideProc endp


and thats the question i was confused at the beginning..
now,
I must ask the same question as smurf :) how can i pass variables ?

thanks for your help
Posted on 2002-02-15 11:39:22 by Ray
Hi Smurf

The sub ha access to all the locals and registers, so you can pass as many parameters you wish, just not the usual way.

KetilO
Posted on 2002-02-15 11:40:56 by KetilO
Ray,
if your coding skills are up to speed (and i assume they are), there is absolutely no reason you should need to do what you are asking about.

The only place i have seen that kind of code used is in the ROMs of old pcs like the C64 and Apple II, but the difference was that the code was in non-relocatable memory, and the programmer would call/jmp to a literal memory address, not to a relocatable block of code that is identified with a label. That style of code was essential then, but not now.
Posted on 2002-02-15 16:55:27 by sluggy
I agree with Sluggy here, there is no direct advantage from coding this way. If you want a sub procedure, write it at the end of the existing one after the final RET by using a label, the code then a RET back to the calling position.


YourProc parameters etc ...

; assembler code

call sub_proc

; assembler code

ret ; the final RET in the proc

sub_proc:

; your sub code

ret ; return back to next instruction after CALL

YourProc endp


Regards,

hutch@movsd.com
Posted on 2002-02-15 17:34:43 by hutch--
thanks for clearing things up,
one last question
can someone explain the difference between a RET and RETN ?

KetilO mentioned it but i am not sure why.

:tongue:
Posted on 2002-02-16 13:25:17 by Ray
retn = pop only the IP register
retf = Far returns pop the IP followed by the CS
Posted on 2002-02-16 14:51:28 by smurf
Hi Ray

Masm is also kind enough to clean up the stack for you if it finds a ret instruction. You don't want to clean up the stack when returning from a local sub inside a proc.

KetilO
Posted on 2002-02-16 15:36:20 by KetilO
ret is a macro and chooses retn/retf depending on what is needed.
Also, it does stack frame cleanup. I believe that "retn" will always
choose retn with no stack frame cleanup, and retf will chose retf
with no stack frame cleanup. But search the forum for more clues :)
Posted on 2002-02-16 17:06:05 by f0dder
It also depends on the memory model, mostly flat and small, ret resolves to retn....I'm not sure about retf(usually far memory model) though, since I didn't experiment much in the 16 bit era.
Posted on 2002-02-16 17:09:03 by stryker
the choice of RETN or RETF depends what environment you are building in. 16 bit DOS used both depending on the memory model chosen, RETN means under the segment size in DOS coding, RETF was for cross segment returns being respectively < 64k or > 64k.

In 32 bit FLAT memory model, any address within the 4 gig range is RETN or NEAR return. In MASM id you use RET in 32 bit, it defaults to NEAR.

Regards,

hutch@movsd.com
Posted on 2002-02-16 17:36:48 by hutch--
In masm, "ret" is interpreted as a macro. It cleans up the stack frame,
and iirc it also chooses retn or retf depending on how the procedure
was defined. Furthermore, I think that manually typing retn or retf
will do that return without doing the stackframe cleanup?

Yes, I just assembled a small test piece and verified all this.
Posted on 2002-02-17 04:45:54 by f0dder
I wonder where this folk lore comes from,


EmptyProc proc

nop
nop
nop
nop

ret

EmptyProc endp

0040195F fn_0040195F:
0040195F 90 nop
00401960 90 nop
00401961 90 nop
00401962 90 nop
00401963 C3 ret


Intel manual for RET

Opcode Instruction Description
C3 RET Near return to calling procedure
CB RET Far return to calling procedure

Seems MASM does it right the first time.

Regards,

hutch@movsd.com
Posted on 2002-02-17 05:03:18 by hutch--


proc1 proc parm1:dword
ret
proc1 endp

proc2 proc parm1:dword
retn ; skips "leave"
proc2 endp

proc3 proc far, parm1:dword
ret ; does "leave" and "retf"
proc3 endp


... try assembling that and look at the output.
Posted on 2002-02-17 05:09:14 by f0dder
I just wonder how much use it is, RETN yields an unbalanced stack which would crash the app with recursive calling.


00401961 55 push ebp
00401962 8BEC mov ebp,esp
00401964 90 nop
00401965 90 nop
00401966 90 nop
00401967 90 nop
00401968 C3 ret

It is probably only useful in fully manually coded procedures.

Regards,

hutch@movsd.com
Posted on 2002-02-17 06:21:07 by hutch--
It would crash right at the ret for obvious reasons. But forcing masm
to do what YOU want to do can be useful. I believe there were some
old post where there was a really good reason to do the manual
ret thing - with a handcoded "db 0C3h" because whoever didn't
know about the "retn" trick.
Posted on 2002-02-17 06:26:16 by f0dder