The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: seymour_glass on March 30, 2006, 09:08:25 PM

Title: PROCEDURES
Post by: seymour_glass on March 30, 2006, 09:08:25 PM
Im just getting into writing procedures.  Anyone got any good resources for this?  As in parameters....pushing, popping (i understand them, but not like i think i should) , stack and index pointers?

Seymour
Title: Re: PROCEDURES
Post by: Ratch on March 30, 2006, 11:04:25 PM
seymour_glass,
     A lot of folks from the Ineffable All disagree with me, because I never use PROC's.  I think they are just a bunch of red tape that gets in-between the problem and the programmer.  Anyway, look at the references below.  Some will say that this method is too advanced for a beginner, and that is possibly true.  The choice is yours.  Tell me what you think. Ratch

http://www.masmforum.com/simple/index.php?topic=2371.0 see reply #4
http://www.masmforum.com/simple/index.php?topic=380.0  see replys #11,17
Title: Re: PROCEDURES
Post by: hutch-- on March 31, 2006, 12:22:56 AM
Seymour,

The techniques Ratch is talking about are probably a bit advanced for someone learning assembler. I would suggest that you start with normal stack frame procedures, once you have them going you can start on writing procedures with no stack frame and if you have some need later on, you can try out various techniques for short circuiting procedure CALL/RET branching.
Title: Re: PROCEDURES
Post by: Mark Jones on March 31, 2006, 12:42:23 AM
Hi Seymour, perhaps these posts will help you. It touches on both procedures and the stack.
http://www.masmforum.com/simple/index.php?topic=4276.msg32166#msg32166

Also, be sure to read \masm32\help\ASMINTRO.HLP. :U
Title: Re: PROCEDURES
Post by: seymour_glass on March 31, 2006, 03:48:36 AM
ok question....To  exchange two registers, one could.... 

push eax
push ebx
pop  eax
pop  ebx

Correct?

why then would:

push eax
mov eax, ebx
pop ebx

work?
Can you even pop something off that youu didnt push on?  I guess thats why this confuses me....plus my textbook sux....

_______

Also, can anyone briefly explain the PUBLIC and EXTRN directives? 

(sorry for these petty questions, ive got no other consolation for my problems.)

Seymour
Title: Re: PROCEDURES
Post by: hutch-- on March 31, 2006, 03:55:16 AM
seymour,

You have to realise that the stack is memory so when you push a register onto the stack, the value in the register is then stored in memory. The stack is a last on, first off layout and as long as you don't change the stack pointer (ESP) it will return the last item you pushed onto it.

The method you have shown to exchange register is perfectly valid as it uses the first on, last off technique to swap the register contents.


push eax
mov eax, ebx
pop ebx


When you use "push eax", the value in EAX is copied to the stack memory.

Moving EBX into EAX does not effect this and when you do the "pop EBX" you are copying the value on the stack into EBX.
Title: Re: PROCEDURES
Post by: seymour_glass on March 31, 2006, 04:11:46 AM
I see that now.  I just thought that it was a little more structured. Logically you cant take something off if you dont put it on...At least thats what i was thinking. However.....

push eax
pop  anyVar

is really popping eax into anyVar? Correct?  That may be worded wrong, i dont know, but the idea i think is right.
Title: Re: PROCEDURES
Post by: ChrisLeslie on March 31, 2006, 10:53:28 AM
QuoteA lot of folks from the Ineffable All disagree with me, because I never use PROC's.  I think they are just a bunch of red tape that gets in-between the problem and the programmer.
Ratch,
Any decent program, assembler or otherwise, has to have a structure whether one uses procs, classes, objects structs or whatever it takes. If you don't use PROC's I hope you use some sort of structural aids, or else how do you put an architectural shape to your program? I would hate to debug any such program if it is more than about 10 lines long!!

Thats my opinion - Chris
Title: Re: PROCEDURES
Post by: hutch-- on March 31, 2006, 12:23:04 PM
seymour,


push eax
pop  anyVar

is really popping eax into anyVar? Correct?  That may be worded wrong, i dont know, but the idea i think is right


Not exactly but its close. When you use PUSH EAX, it then becomes a value stored in stack memory, memory that is pointed to by the stack pointer ESP. This does not change the value that is still in EAX.

Here is a small test piece for you that shows you how ESP is used by the PUSH instruction.


    mov eax, 1234
    push eax

    mov edx, [esp]
    print str$(edx),13,10

    pop eax


After the PUSH EAX instruction, the value from EAX is now at the address pointed to by ESP so you have this notation [esp] .

The example just copies it back to the EDX register to display it and the value displayed is the same as the value at the memory address [esp]

The POP on exit is to ensure that stack is balanced.
Title: Re: PROCEDURES
Post by: Ratch on March 31, 2006, 01:23:36 PM
ChrisLeslie,

Quote
Ratch,
Any decent program, assembler or otherwise, has to have a structure whether one uses procs, classes, objects structs or whatever it takes. If you don't use PROC's I hope you use some sort of structural aids, or else how do you put an architectural shape to your program? I would hate to debug any such program if it is more than about 10 lines long!!

Thats my opinion - Chris

     If you read the references I gave in my post, you would see that I do indeed implement a structure with respect to the stack.   I use the MASM directive STRUCT (as in structure) to do this.   Ratch

Title: Re: PROCEDURES
Post by: Mark Jones on March 31, 2006, 06:22:12 PM
Quote from: seymour_glass on March 31, 2006, 04:11:46 AM
push eax
pop  anyVar

is really popping eax into anyVar? Correct?

Here's the low-down on the stack. The "stack" is a segment of memory, pointed to by ESP, which works "backwards" from conventional thought and in a "circular" or First-In-Last-Out (FILO) arrangement. Think of the stack as literally a stack of coins - each time you push a value on, you're adding a coin to the stack. Pop takes a coin off the top. You can't pop off anything in the middle. You can however, access any value on the stack by referencing ESP plus an offset. So, say you pushed a 1, then a 2, then a 3 DWORD to the stack. The 3 is on top, so the 3 gets popped off first, then the 2, and 1. If all three are pushed on, you can get the value of 2 and 1 by referencing ESP+4 and ESP+8. Here is how the stack addressing works in "backwards" logic - each newly pushed value DECREMENTS ESP by 4 (or 2 if a WORD was pushed.) So, as the stack grows, ESP gets smaller, and as items are popped off, ESP gets larger. That's how it works "in reverse logic."

Now the things being pushed and popped can be a literal value (PUSH 1024h), a register (PUSH EAX), or a memory operand (PUSH MyVar, PUSH OFFSET szHello, PUSH DWORD PTR lpFrellit!, PUSH [EDX+ESI], etc.) Here are some questions for you to answer. Try coding a small application to test these, it will really help you learn this. A quick way to see what happens would be to load the program into a debugger like OllyDbg and press F8 to step through each instruction.

1. If EAX contains 87654321h and you PUSH EAX then POP ECX, what does ECX equal?
2. You have an integer variable "iVar" and you PUSH iVar and POP EAX. What does EAX equal?
3. You PUSH 12345678h then POP iVar. What does iVar equal?
4. If you PUSH OFFSET iVar and POP EAX, does EAX == iVAR?
5. You PUSH iVar and PUSH EAX then MOV EAX,ESP. Does EAX == iVar?
6. You PUSH iVar and PUSH EAX then MOV EAX,[ESP+4]. Does EAX == iVar?

Good luck, have fun! :toothy
Title: Re: PROCEDURES
Post by: seymour_glass on March 31, 2006, 07:27:10 PM
Thanks alot guys.  I got it a lil better.  As far as learning about the parameters and all that I will just have to jump into it.  Im trying to figure it out before even trying it in code, which probably isn't the best way to learn.  Im just afraid that if I start messing around with [ebx+4], im gonna get myself lost quickly.

That ASMINTRO is an excelllent resource, much better than my text...

And Mark, I havent tried those examples you gave me. I will, however, when i get back to my pc.  Although i believe that i can probably answer them without actually following it in debug,  i think that watching it will probably make a helluva difference in me grasping it.

Seymour.
Title: Re: PROCEDURES
Post by: ChrisLeslie on March 31, 2006, 09:40:06 PM
Ratch,

QuoteIf you read the references I gave in my post, you would see that I do indeed implement a structure with respect to the stack.   I use the MASM directive STRUCT (as in structure) to do this.   Ratch

Oh!  :red  -  I don't want to rekindle any old flames.
I do admire your approach using STRUCTs, and that approach had crossed my mind before but I had not pursued it. But I do also appreciate good overall program design that allows easy readability and maintenance of a program that is required to grow and improve. I'm sure you also achieve such design with your methods.

Regards

Chris
Title: Re: PROCEDURES
Post by: seymour_glass on April 01, 2006, 04:03:20 AM

Quote

5. You PUSH iVar and PUSH EAX then MOV EAX,ESP. Does EAX == iVar?
6. You PUSH iVar and PUSH EAX then MOV EAX,[ESP+4]. Does EAX == iVar?

Quote

Is it assumed that i am popping the values off? If not popped must i ret, 8? Or does this work?  I would think it would leave the stack unbalanced, which may not matter if im not returning from a call, and simply exiting...?  I dont know...?

Seymour
Title: Re: PROCEDURES
Post by: Ratch on April 01, 2006, 02:51:53 PM
seymour_glass,

     I don't know if you read carefully the pertient documentation relating the the stack and the relevant instructions, so lets review.

1) The stack is a logical segment of memory whose architecture and instruction set are optimized for 'last in first out' (LIFO) operations.  It has its own dedicated pointer register (ESP) and a stack frame register (EBP).

2) The stack grows towardS DECREASING memory addresses and shrinks towards INCREASING memory address.  That means that a PUSH will decrease the ESP value and a POP will increase the ESP value.

3) The ESP value will be at the stack memory address of the last PUSH'ed value, or the next value to be POP'ed.  In other words, a PUSH EAX is equavalent to the instruction sequence:

SUB ESP,4
MOV [ESP],EAX

Similarly, a POP  EAX is equivalent to:

MOV EAX,[ESP]
ADD ESP,4

A RET is equivalent to:

JMP [ESP]
ADD ESP,4

And a RET 8 is equivalent to:

JMP [ESP]
ADD ESP,(4+8)

Quote. You PUSH iVar and PUSH EAX then MOV EAX,ESP. Does EAX == iVar?

     No, EAX will be the stack address of the last item PUSH'ed, namely EAX.  If you wanted to load the last item you PUSH'ed, you should have coded something like MOV ECX,[ESP].  If you wanted the first item you PUSH'ed (ivar), then code MOV ECX,[ESP+4] .

QuoteYou PUSH iVar and PUSH EAX then MOV EAX,[ESP+4]. Does EAX == iVar?

     Yes, that is correct.

QuoteIs it assumed that i am popping the values off? If not popped must i ret, 8? Or does this work?  I would think it would leave the stack unbalanced, which may not matter if im not returning from a call, and simply exiting...?  I dont know...?

     You are NOT POP'ing values off with the above code sequences.  You are copying a stack address, and then the contents of a stack address into EAX.  If you code a RET, you will cause a JMP.  Is that what you want?  Since you coded two PUSH'es without any POP's,  you will need to code ADD ESP,8 to balance the stack.  Ratch


Title: Re: PROCEDURES
Post by: Mark Jones on April 01, 2006, 06:00:31 PM
"Stack Balance" issues arise when the stack becomes mis-aligned. Take this code for example:


one:
    push 1000
    push 100
    call Beep

two:
;    push 1000   we forgot to include this
    push 100
    call Beep


The first code runs normally. This is actually what "invoke Beep,100,1000" gets converted to by ML.EXE. Inside the Beep procedure it POPs two values off the stack to use as its frequency and duration parameters. (This is how parameter passing works in MASM.) In the second example, we forgot to push a parameter, but Beep still POPs two off the stack, unbalancing it. So Beep just popped off some other value, which will probably cause a crash (or a very unusual tone!) But if this particular function does not crash the app, the stack is no longer correct (it is missing a value) so something else will probably crash. Since the stack is a Last-In-First-Out buffer, unbalancing it is usually catastrophic because nothing else lines up. So you only want to POP things off the stack if you're sure you PUSHed them on. :bg

Procedures are a little more complicated. In this procedure here,


MyProc PROC szText:DWORD
    invoke MessageBox,0,szText,0,MB_OK
    push eax
    ret
MyProc ENDP


Say we call this from somewhere else in our code. What happens when a procedure is called, is the EIP (the address where program execution originates from) is pushed to the stack, then execution branches to the procedure. The RET instruction POPs the topmost value off the stack as EIP and resumes program execution there. This works great for normal procedures but can you guess what will happen to the one above? Right, program execution will branch to whatever value was in EAX! This will probably result in the dreaded "Page Fault" error.

To further complicate things, it has been my experience (and I have not fully tested this) but PUSHing extraneous values to the stack without imbalancing it is not a problem. i.e.,


    push eax
    push 1234
    push HiMom!
    invoke ExitProcess,0


Those three PUSHes are simply not used for anything. Apparently Windows discards an application's stack when it exits, so those values are not stuck in memory anywhere. This isn't good coding practice, but it doesn't seem to hurt anything either. :)
Title: Re: PROCEDURES
Post by: tenkey on April 02, 2006, 09:17:21 AM
By default, the PROC protects you from excessive PUSHing. The RET instruction, when it appears between PROC and ENDP is expanded to a stack balancing code sequence. The stack balancing act is equivalent to the following...

; set ESP to beginning of stack frame
; by definition, this deallocates all local variables,
;   and any unpopped stack data
        mov esp,ebp

; recover pushed EBP to satisfy register preservation rules
; this would normally be a pointer to the previous stack frame,
;   but in reality, it doesn't matter what it is, as long as it's restored
        pop ebp

; the stack is now properly pointing to the return address
; nn is always 0 for C or CDECL type PROC
; the RET nn will pop nn bytes of "arguments" AFTER the return address
;   has been removed from the stack
        ret nn