I'm preparing for my ASM exam and I'm having trouble understanding the concept of passing parameters via the stack. Usually we must use local variables when writing recursive procedures. Here's a little code snippet that I'm unable to test atm:

procedure1:

PUSH EBP
MOV EBP, ESP
PUSH EAX
PUSH EBX
MOV EAX, [EBP+8] ;EAX receives the 1st parameter  ex EAX = 10
MOV EBX, [EBP+12];EBX receives the 2nd parameter  ex EBX = 20
ADD EAX,10
ADD EBX,10
SUB ESP,8        ;Creating space for 2 local variables 4 bytes each
MOV [EBP-4], EAX
MOV [EBP-8], EBX 
CALL procedure2
;POPS, MOV, RET

procedure2:
PUSH EBP
MOV EBP, ESP
PUSH EAX
PUSH EBX
MOV EAX, [EBP+8] ;EAX should receive the 1st local parameter  ex EAX = 20
MOV EBX, [EBP+12];EBX should receive the 2nd local parameter  ex EBX = 30
;POP, MOV, RET

What I want to be able to do is create local variables that can be accessed via the stack by another procedure. I'm not sure whether the "local" variables would be placed at EBP+8 and EBP+12. Also whenever I ADD or SUB ESP does it automatically adjust (sorry for this one but I want to be sure).

Also can someone tell me whether pushing the registries first and doing SUB ESP, X is different from doing SUB ESP, X and then saving the REGs?

P.S I'm using NASM

Hi Swiftle,

I am not sure if I got you right. And I haven't tried out what I am telling you. So please verify the stuff I'm just writing down.

When you call a procedure, CALL simply pushes the address of the very next instruction onto the stack. Now the trouble actually begins. Because you have to distinguish between quite a few possibilities:
1) the address might be eight byte long running a 64-Bit programme. I just take, that this not the kind stuff you want to do. So we forget this one.
2) if you're calling a far label (which is simply a procedure that is out of you current segmentation - so further than 65.536 Bytes of your CS) then you definitely have 32-Bit (four bytes) pushed on the stack.
3) if you're calling a procedure within your current segment (which is very likely your case) than you just have 2 bytes pushed on the stack.

You can actually simplify things. Let's take you're writing a 32-Bit programme for the sake of ease. I you're putting a "FAR" right after "CALL", you can make sure that always 4 Bytes are pushed on the stack (please verify that!).

Now that you've found out how many bytes are needed for "RET", you know how to access the provided arguments. The arguments start at "[ESP-usedBytes]". So having provided a "FAR", the arguments always start at "[ESP-4]".

So, to put all stuff into code:

PUSH DWORD 10   ;one argument
PUSH DWORD 20   ;another argument
CALL FAR procedure   ;which will add 4 Bytes to the stack...

procedure:
MOV EAX,[ESP-4]   ;this should be '20' if I'm right
MOV EBX,[ESP-8]   ;this should be '10' if I'm right
RET

Of course you can do that recursively if you want.

You've put some value after the stack-base-pointer: [EBP+8]. I can't recommend this. Because: EBP points to the beginning of the stack and you can never know what kind of data is stored there. So you better always push new value on the stack and than use the stack-pointer (ESP) which points at the end of the stack. Working with EBP always makes trouble. For instance: On Linux you have to push all registers manually onto the stack at the beginning of your programme. So working with EBP makes the world totally different.

Personally I never ever change the value of ESP or EBP, just because that can quickly become a real pain. And I strongly advice you not to do so as well. Just remember where you put your stuff and access that stuff with a simple calculation (eg "[ESP-EBX]") that subtracting ESP and than adding value to it again. You just mess up your code so easily.

Your last question was about changing the values and pushing them onto the stack.
Of course there's little different. Not for the processor - it would do both. But if you change the value of your register and then put it on the stack, the stuff is packed somewhere in your memory and may even cause your computer to crash. The processor always places your data directly where "ESP" is pointing to right at that moment. If you change the value of ESP, the processor puts the data somewhere else.

Doing it the other way round, so pushing the stack-pointer onto the stack and then changing it, let the processor put the value at the end of the stack and then mess up the pointer. By then you haven't crashed your programme yet, but a soon as you push something else onto the stack you have a problem.

I hope this helps a little bit. If you're still confused feel free to ask again.

Greeting Simon

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.