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
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
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.
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
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
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.
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.
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
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.
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
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
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.
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
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
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
"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. :)
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