News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

PUSH & POP question

Started by Lonewolff, May 01, 2018, 11:01:40 AM

Previous topic - Next topic

Lonewolff

Hi guys,

Do you have to 'pop' every time you 'push' something on the stack?

Do 'call' and 'invoke' automatically do this for us?

Thanks in advance  :biggrin:

hutch--

Except in rare instances, yes. The stack for PUSH / POP work on a last on, first off basis so the POPs must be in reverse order to the PUSHs.

When a CALL is made, you need to have pushed the arguments onto the stack first. When you use the built in MACRO "invoke" it automates the push / call process. Note that any procedure you call that you wrote yourself must balance the stack on exit. This is done with the number after the RET (ret 16) and it must match the number of arguments x 4.

jj2007

YES and YES.

Quote from: hutch-- on May 01, 2018, 11:16:15 AMNote that any procedure you call that you wrote yourself must balance the stack on exit.
"Balanced" means normally that #push = #pop, but there are situations where you may want to use push push call instead of invoke, see screenshot below. I have recently started to use uppercase PUSH for these cases, so that searching for push+pop yields lowercase #push = #pop if the stack is balanced.

Note also that a program does not necessarily crash if the stack is not balanced; most procs have a stack frame, and if that gets released at the end, the stack is balanced. Great, but you have a bug...

Lonewolff

Thanks guys.

So this would need four more pop's before pop'ping ESI?


; Display 'MessageBox'
push esi ; preserve esi

mov eax, 10h ; Error icon
push eax

lea esi, _EE ; Error title
mov ecx, esi
push ecx

lea esi, _E0 ; Error reason
mov ecx, esi
push ecx

xor eax, eax ; Window handle
push eax
call MessageBoxA

pop esi ; restore esi


Doing it all long handed for learning purposes (ie. not using 'offset' or 'invoke').

(Or a ret 16 if it was in a proc?)

hutch--

For the 1st and 4th argument, you can directly do a "push 0" in MASM.

jj2007

Quote from: Ascended on May 01, 2018, 11:19:17 AM
So this would need four more pop's before pop'ping ESI?
Nope. You used 4*push instead of invoke. Your stack is balanced.

If you want to dig deeper, here is a snippet (see above, "a program does not necessarily crash if the stack is not balanced"):include \masm32\include\masm32rt.inc ; console build!

.code
SayHi proc uses esi edi ebx pMessage
Local hWnd ; force a stack frame...
  and hWnd, 0 ; set window handle to zero
  push MB_OK
  push chr$("Hi")
  push pMessage ; chr$("Hello World")
  push hWnd
  call MessageBox ; invoke MessageBox, 0, str$(eax), chr$("Title"), MB_OK
  pop edx ; a desperate attempt to balance the stack
  pop edx
  pop edx
  pop edx
  ; int 3 ; uncomment to see what happens here
  ret
SayHi endp
 
start:
  mov ebx, 123
  mov esi, 456
  mov edi, 789
  print str$(ebx), 9, "ebx before", 13, 10
  print str$(esi), 9, "esi", 13, 10
  print str$(edi), 9, "edi", 13, 10
  invoke SayHi, chr$("Hello World")
  print str$(ebx), 9, "ebx after", 13, 10
  print str$(esi), 9, "esi", 13, 10
  inkey str$(edi), 9, "edi", 13, 10
  exit

end start

Lonewolff

Thanks guys. Got it  :t

And Hutch, the fourth arg is a 10H, but I get what you are saying.

Thanks again  8)

Lonewolff

Also, was I right in assuming that this is the equivalent of 'offset'?


push esi
lea esi, xxx
mov ecx, esi
pop esi


[edit]
Actually OllyDbg says that it is simply 'push offset address'

I though 'offset' must have been another macro, but it is an actual keyword. There ya go  :biggrin:

jj2007

lea esi, somevar is the same as mov esi, offset somevar if somevar is a global variable.

This is unnecessarily complicated:
lea esi, _EE ; Error title
mov ecx, esi
push ecx

lea esi, _E0 ; Error reason
mov ecx, esi
push ecx


Better:
mov esi, offset _EE ; Error title
push esi

mov esi, offset _E0 ; Error reason
push esi


Even better (shorter, and doesn't need esi):
push offset _EE ; Error title
push offset _E0 ; Error reason


Even better (for readability):
push chr$("There was an error:")
push chr$("But I don't know the reason")


And once you have understood how it works under the hood. you can become professional and lazy:
MsgBox 0, "But I don't know the reason", "There was an error:", MB_YESNOCANCEL or MB_ICONWHATEVER

hutch--

Its unfortunate that ML64 has gone the way of NASM in not using OFFSET which is a specific technical term for a distance from a location which is used to locate either data or code within an assembler binary. In 32 bit MASM (ML.EXE) it is the preferred technique for addresses. LEA will do it but you are determining the address dynamically where OFFSET puts the value in at assembly time as an immediate.

Lonewolff

Quote from: hutch-- on May 01, 2018, 12:51:06 PM
Its unfortunate that ML64 has gone the way of NASM in not using OFFSET which is a specific technical term for a distance from a location which is used to locate either data or code within an assembler binary. In 32 bit MASM (ML.EXE) it is the preferred technique for addresses. LEA will do it but you are determining the address dynamically where OFFSET puts the value in at assembly time as an immediate.

Oh, so in ML64 you have to use LEA then?

hutch--

In most instances, yes. I don't like it but that is how it works.

Lonewolff

Bummer, good snippet to know though  :t

jj2007

Quote from: hutch-- on May 01, 2018, 12:51:06 PM
Its unfortunate that ML64 has gone the way of NASM in not using OFFSET

Are you sure?

  mov rsi, offset txMessage
  lea rdi, txMessage


0000000140001018   | 48 BE 02 10 00 40 01 00 00 00    | movabs rsi,140001002                    | 140001002:"Hello World"
0000000140001022   | 48 8D 3D D9 FF FF FF             | lea rdi,qword ptr ds:[140001002]        | 140001002:"Hello World"

hutch--

There are some places where you can use it and some places where it fails. I try for consistency and LEA is consistent across all of the uses I have found.