I have pushed two DWORD values into a procedure and then inside the procedure pushed the EBX register onto the stack. I then pushed the EBP register and moved ESP to EBP to be able to access the parameters through EBP. when i disassembled the program i noticed that the first argument from left would have the offset +10h from EBP. I kind of do not know what happens really because in 16 bit tasm when we called a procedure, the parameters could had been pushed onto the stack and then a 16-bit offset of the next line adjacent to the invokation line like this

PARAM 1 (16 Bits)
PARAM 2 (16 Bits)
CALLER'S OFFSET (16 Bits)

then i could push BP and retrive the parameters like this

PARAM 1 (16 Bits)
PARAM 2 (16 Bits)
CALLER'S OFFSET (16 Bits)
BP

MOV BP , SP
MOV <...> , WORD PTR ; to access PARAM 2

but this seems pretty irrational right now to me that i have to access the arguments the way i do right now. i know that the parameters are passed from right to left but even in that case the stack should have the following state

PARAM 2 (32 Bits)
PARAM 1 (32 Bits)
CALLER  (32 Bits)
EBP        (32 Bits)

so to access PARAM 1, i should

MOV EBP , ESP
MOV <...> , DWORD PTR

But that is not it! can anybody help please?
Posted on 2006-06-27 04:57:36 by XCHG
XCHG,
      I always have advocated against using PROC's because they obfuscate what is going on, and besides use the EBP register in a register starved CPU.  I have a different system that uses STRUCTS to keep track of the stack, and does not use up a precious register that the program can use for other things besides stack maintenance.  Another benefit is that I can PUSH parameters to a subroutine many instructions before they are needed, when they happen to be available, instead of trying to corral and PUSH them at the time of the PROC call.  I have received some heat from the BoardMeister at the "other site" for flogging this method to nubes, so I am only going to tell you that it is available, and won't say anything else unless you ask.  If you must use PROC's, then it would be wise to use the Sg option for MASM so you can see what the PROC generates.  Ratch
Posted on 2006-06-27 07:52:46 by Ratch
If you are using the PROC directive, the EBP and ESP register setup code is already provided by it.

Your stack would look like this:

PARAM 2 (32 Bits)
PARAM 1 (32 Bits)
CALLER  (32 Bits)
EBP        (32 Bits) - from PROC directive
EBP        (32 Bits) - from your code

Posted on 2006-06-27 16:11:15 by tenkey

XCHG,
      I always have advocated against using PROC's because they obfuscate what is going on, and besides use the EBP register in a register starved CPU.  I have a different system that uses STRUCTS to keep track of the stack, and does not use up a precious register that the program can use for other things besides stack maintenance.  Another benefit is that I can PUSH parameters to a subroutine many instructions before they are needed, when they happen to be available, instead of trying to corral and PUSH them at the time of the PROC call.  I have received some heat from the BoardMeister at the "other site" for flogging this method to nubes, so I am only going to tell you that it is available, and won't say anything else unless you ask.  If you must use PROC's, then it would be wise to use the Sg option for MASM so you can see what the PROC generates.  Ratch


Yes, but when you make a big enough program, it gets to the point where you are doing the same calling convetion over and over... hence "proc" :)
Posted on 2006-06-27 18:22:49 by SpooK
Spook,

Yes, but when you make a big enough program, it gets to the point where you are doing the same calling convetion over and over... hence "proc"


?  ?  ? I am too dense to understand you mean.?  A subprogram is called by INVOKE, and defined by most MASM'ers, with the exception of myself, by PROCs.?  What does the program size have to do with whether PROCs are used or not??  Ratch
Posted on 2006-06-27 20:03:42 by Ratch
The same premise behind the use of Macros, to simplify the coding process.

As tenkey stated, using INVOKE against a defined "PROC", takes care of "saving" the stack for you. This doesn't mean that you save too much "typing" when using the standard Win32 type calls (stdcall), but it is indeed nice. As for introducing other conventions, like the C Calling Convention (cdecl), where the subroutine/function called is required to clean-up the stack, this makes things much cleaner and standardized. I don't even want to mention the PASCAL Calling Convention. Run-away stack never comin' back...

Instead of having to worry about if every Invoke/Proc pair is proper, the assembler (MASM in this case) checks it for you and fills in the blanks.

As for EBP, some people find it easier to use it "as it was intended"... especially when you bring constant use of "PUSH/POP" into the picture.

Moreover, as an OS Developer, I would like to touch on the fact that memory access across a limited memory space (like a stack/heap) is much more efficient than chasing around random variables. This is becoming less "relevant" as technology evolves, but not many people use ASM with that mindset.

I would suggest *your* method to the more established ASM programmers, but not so much the "new" crowd (beyond exposing them to that method). I like the idea of people knowing what is going on with the stack at all times, and exposing them to this method, as it could lead to more efficient programs/methods. As I said though, the "new" crowd should be exposed to the basics first, before exposing them to more advanced ideas/subjects that might possibly alienate them to HLLs and reinforce the time-old myth of "ASM is hard".
Posted on 2006-06-27 21:05:07 by SpooK
Oh, wow thanks for the replies. So far, this is what I have found about the procedures that are created with MASM.

When you call the procedure with parameters, MASM pushes the parameters from right to left onto the stack as per STDCALL calling convention. but on the entrance to the procedure MASM pushes the base pointer onto the stack and then moves the stack pointer to the base pointer. At the end of the procedure it uses the LEAVE instruction to first restore the stack pointer to its previous state and pop the base pointer from the stack. In the end it uses the RET 04h to pop 4 bytes off of the stack and return to the address indicated by those bytes. Thus, as a result to access the parameters I should not push and pop the base pointer again cause it is automatically done upon entrance to a procedure.

I never knew MASM was pushing the EBP until i disassembled my own program and saw what was going on.

I am thankful beyond words for all the help. Appreciations
Posted on 2006-06-27 22:49:00 by XCHG
You can use the masm directives PROLOGUE and EPILOGUE to prevent masm from screwing around with EBP. Just be aware that *YOU* are now responsible for cleaning up the Stack

PROLOGUE:NONE
EPILOGUE:NONE
myproc proc MyParam1
;blah
ret 4
myproc endp
PROLOGUE:DEFAULT
EPILOGUE:DEFAULT
Posted on 2006-06-28 01:06:08 by Homer
Homer,

You can use the masm directives PROLOGUE and EPILOGUE to prevent masm from screwing around with EBP. ...


    If you castrate a PROC like that, why bother making a PROC in the first place?  Ratch
Posted on 2006-06-28 18:47:20 by Ratch
Because you still have named access to your arguments without all the typing of creating a structure which represents the stack frame:

OPTION	PROLOGUE:NONE
OPTION EPILOGUE:NONE
ErrorMessage PROC lpszMessage:DWORD
enter 0, 0
INVOKE MessageBox, NULL, lpszMessage, NULL, MB_OK + MB_ICONERROR
leave
ret 4
ErrorMessage ENDP
OPTION PROLOGUE:DEFAULT
OPTION EPILOGUE:DEFAULT
Posted on 2006-06-28 19:30:48 by Synfire
Synfire,

Because you still have named access to your arguments without all the typing of creating a structure which represents the stack frame:


      Well, you still have to name the parameters and local variables in the PROC definition.  Maybe it's a little more typing for the STRUCT, but not much more.  Ratch
Posted on 2006-06-28 20:44:38 by Ratch
At that rate, I would recommend a trial run of RosASM... no macros, or any other High Level constructs for that matter, to get in the way of your ASM experience. Who knows, you might like it :)
Posted on 2006-06-28 20:49:24 by SpooK
Spook,
At that rate, I would recommend a trial run of RosASM... no macros, or any other High Level constructs for that matter, to get in the way of your ASM experience. Who knows, you might like it


    I like the MACROs and HLL of MASM, even though I can suggest a lot of implementation improvements.  It's the PROCs that I believe are another layer of software that get in-between the programmer and the problem.  Ratch
Posted on 2006-06-28 21:33:15 by Ratch
I am not talking about the Win32API but when I create a procedure which has lets say, 10 arguments, i'd rather push the arguments and clean them up from the stack manually. Because this way you will *actually* know what is going on inside the procedure.

Oh and by the way, i loved the PROLOGUE and EPILOGUE options.
Posted on 2006-06-28 22:24:29 by XCHG

I am not talking about the Win32API but when I create a procedure which has lets say, 10 arguments, i'd rather push the arguments and clean them up from the stack manually. Because this way you will *actually* know what is going on inside the procedure.

Oh and by the way, i loved the PROLOGUE and EPILOGUE options.


This is a good advantage when you have the source code (i.e. not the API, but own function).
Posted on 2006-06-28 23:01:11 by SpooK
XCHG,

I am not talking about the Win32API but when I create a procedure which has lets say, 10 arguments, i'd rather push the arguments and clean them up from the stack manually. Because this way you will *actually* know what is going on inside the procedure.


    If we are talking about PROCs, they don't PUSH arguments/parameters.  That is done by directive INVOKE directive or a PUSH and CALL sequence.  PROCS implement a hidden virtual STRUCT that keeps track of the arguments and local variables on the stack.  You are wise for wanting to at control at least part of the stack operations yourself.  The ultimate nirvana is to dispense with PROCs completely.  Ratch
Posted on 2006-06-28 23:04:54 by Ratch
This case is a sacrafice between readability, and reusable code, and OOP, and stuff liek that, VS speed, procedural writing, and hard to understand code due to (possible) optimization on your part. That's always the tradeoff when coding. I find that procedural coding will most likely always be faster, but OOP is much more understandable.
Posted on 2006-06-29 00:15:06 by Bobbias
Well i totally understand you Ratch but in some special occasions you may need not to remove the pushed parameters from the stack.

Imagine there is a procedure that converts the integral value of the EAX register to its equivalent null-terminating string. The string's offset should be pushed onto the stack before calling the procedure. now let's say the procedure has done it's job and has left the string's offset to be removed from the stack by the programmer. as long as the offset is there, you could call other procedures and functions that could use the offset of the string without any further pushes or pops. In the end you can pop the offset off of the stack. that will save you 1 push and a pop for each of the calls.

I am not saying that using the procedure is good or bad. in fact you can write thousands of lines of code without using a single procedure and have a very structured code which can be easy to maintain or in contrast have a procedural code which is not even readable or vice versa. When i first disassembled my program which was coded in MASM i couldn't even believe that was my program because MASM had added some extra lines of codes to the program which i had no clue where they had came from and seemed totally counterintuitive to me. I believe the use of procedures the way *you* code them can sometimes save you a lot of time.
Posted on 2006-06-29 13:49:42 by XCHG
XCHG,

Well i totally understand you Ratch but in some special occasions you may need not to remove the pushed parameters from the stack.


    Static variables that are left on the stack between subroutine calls should first be put on the stack in a separate operation, followed by an INVOKE to the subroutine.  Afterwords they can be removed in a separate operation.

    Another example is a search for a character within a string.  The index can be returned on the stack and used again for searching the next character starting from the value of that index.

I am not saying that using the procedure is good or bad.


    I think they are a nuisance.  They obfuscate the code for beginners, and the intermediate and advanced users don't need them.

I believe the use of procedures the way *you* code them can sometimes save you a lot of time.


    I don't code procedures.  I code subroutines.  I am a PROCless programmer, because I do not use the PROC directive.  Ratch



   
Posted on 2006-06-29 16:31:53 by Ratch
Ratch,

I personally don't see how PROC's are a nuisance.

They obfuscate the code for beginners,


If you really believed that, then why use INVOKE, or macros at all. When I use MASM (which I must add is very rare) I take full advantage of features such as PROC, INVOKE, .IF, etc. This increases readability and is really, IMHO, the only reason to use MASM. If you have such a dislike for such features why not use an assembler like NASM or FASM.

and the intermediate and advanced users don't need them.


No, intermediate and advanced users don't need them, but they use them to speed up development times and cut down on the amount of stack managment that is required. Truth is, the majority of my real world code looks more like this:


WndProc: ; Message Handler
hWnd EQU 0x08
uMsg EQU 0x0C
wParam EQU 0x10
lParam EQU 0x14
push EBP
mov EBP, ESP
mov EAX,
cmp EAX, WM_USER
jg .DEFAULT
cmp EAX, 0
je .DEFAULT
cmp EAX, WM_CREATE
jne .WM_COMMAND
; Initialize Windows
jmp .DEFAULT
.WM_COMMAND:
;...(stripped down for size)...
.DEFAULT:
push dword
push dword
push dword
push dword
call
.EXIT:
mov ESP, EBP
pop EBP
retn
; EndOf WndProc


But if I posted something that contained code like that to a novice assembly programmer, they would most likely end up with more questions than answers. I've always been a strong supporter that novices should not use ANY of the extended features of an assembler (such as PROC and INVOKE) until they are able to develop without them. Such features are an asset, not a  nuisance, and should be used as such. Only when the person doesn't need them should they use them to increase development time. I'm a hobbiest programmer, so development speeds don't matter to me, therefore I'm comfortable using a syntax like shown above, but when time constraints are set a user should use whatever features are available to them.

Regards,
Bryant Keller
Posted on 2006-06-29 19:15:48 by Synfire