1

I am having slight confusion about the usage of ebp and esp in relation to setting up a stack frame in x86 assembly language. In this following code:

section '.code' code readable executable        ; define the code section of the file
main:                ;main label is where execution begins
push ebp
mov ebp,esp          ;set up the base ptr
sub ebp,4            ;subtract 4 from ebp
mov dword [esp],msg
call [printf]
mov dword [esp],p   ; pass pause>nul cmd to system to hold the box open
call [system]
mov dword [esp],0              ;pass NULL to exit
call [exit]   

The programmer has subtracted 4 from ebp but I'm not sure why. Typically, I see a subtract from ESP here instead of EBP. What is the purpose of subtracting from EBP here?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
the_endian
  • 2,259
  • 1
  • 24
  • 49
  • Is there more to this code? Or is this the entire snippet? In terms of what is happening specifically here ... they're using the stack pointer to pass arguments to the functions they call (instead of `push`'ing them onto the stack they're just moving data directly to the stack). – Simon Whitehead Feb 22 '18 at 05:16
  • @SimonWhitehead No sir this is the entire program sans the .data and .idata sections wich declare the vars and imports used – the_endian Feb 22 '18 at 05:25
  • I think I get what you're saying... So basically, they are putting the MEMORY ADDRESS of msg (hence 4 bytes for a ptr) into the 4 bytes that are subtracted from ebp?? – the_endian Feb 22 '18 at 05:30
  • SO alternative would be `sub esp, 4`, followed by `push msg` instead? – the_endian Feb 22 '18 at 05:32
  • 1
    I don't think it serves any actual purpose. This snippet is quite strange. – Simon Whitehead Feb 22 '18 at 06:13

2 Answers2

5

This is definitely a bug:

push ebp              ; 1
mov ebp,esp           ; 2
sub ebp,4             ; 3
mov dword [esp],msg   ; 4

Because instructions 2 and 3 only modify the ebp register (but not esp) instruction 4 will overwrite the value pushed in instruction 1.

I doubt that the programmer intended that.

Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38
  • Furthermore, the programmer never uses the `ebp` register. If they really wanted to set `ebp` that way, it would have been written as `lea ebp, [esp-4]`. – Raymond Chen Feb 22 '18 at 06:13
  • @Martin I see, this is because the push ebp is placing the address of the base ptr into the stack pointer, but we then place the address of the msg inside of that same position of the stack pointer since we never moved the stack pointer after the push? – the_endian Feb 22 '18 at 06:31
  • @the_endian yes, `push x` is almost the same thing as "`sub esp,sizeof x` `mov [esp],x`" (it's a bit more complicated, but in simplified sense...) ... and another `mov [esp],msg` will overwrite the value of last `push`. So that snipped could have just do `push msg` (maybe `push offset msg`, depending on assembler used) instead of those 4 instructions (and keep `ebp` to original value). – Ped7g Feb 22 '18 at 06:55
  • if "the programmer intended" was to `push msg`, his 4 instructions are (a very strange, but working) way to implement that. He doesn't clean up the stack, so the space is reused also for the 'system' and 'exit' calls. Looks VERY weired, and clobbering ebp isn't needed at all, but looks more a strange hack to me than like a bug. but 2) and 3) are definitely unneeded – Tommylee2k Feb 22 '18 at 08:01
2

Your code seem to be from a FASM tutorial where the full code looked like:

format PE console
entry main

include 'macro/import32.inc'

section '.data' data readable writeable
msg db "hello world!",0
p db "pause>nul",0

section '.code' code readable executable
main:
push ebp
mov ebp,esp
sub ebp,4
mov dword [esp],msg
call [printf]
mov dword [esp],p
call [system]
mov dword [esp],0
call [exit]

section '.idata' import data readable
library msvcrt,'msvcrt.dll'
import msvcrt,\
printf,'printf',\
system,'system',\
exit,'exit'

In the description of the code the author wrote this:

Starting with our entrypoint label main, I set up a stack frame and allocate 4 bytes on the stack by subtracting 4 from the value of esp. Now in that 4 byte range I place the address of msg in there and call printf,

This leads me to believe that the actual instruction the author intended was:

sub esp, 4

The code effectively has a typo. The description is correct, the code is wrong.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • both "mov ebp, esp" and "sub ebp,4" is irrelevant, for ebp isn't needed anymore after that. the "reserve 4 bytes on the stack" (to be able to give the parameters to the functions called) was already done (by pushing ebp - which is never poped btw); afterwards the parameter for each of the 3 calls is re-using exatly this space on the stack 3 times, instead of (repeatedly) pushing the values for the calls, and cleaning up the stack after the calls. the stack frame set up is never used, and the allocation is (eventually) done by pushing ebp, so it's working. even if it was not intended that way – Tommylee2k Feb 22 '18 at 13:08
  • @Tommylee2k : You are misreading the code. `sub esp, 4` (assume we fix the bug) is not irrelevant. The author is using EBP as a typical stack frame. Rather than `push msg` he is using the allocated space on the stack when he does `mov dword [esp],msg`. The author in the tutorial actually explains this when he shows the alternative version where he does the `push msg` method instead. – Michael Petch Feb 22 '18 at 13:10
  • not yours. his (the code's author). his stack frame is never used, so both, storing esp in ebp, and subtracting -4 from it, was irrelevant. still "sub eSp,4" isn't needed here. the room needed for the call's parameter is already there ( by pushing ebp ). In HIS code, there is no "add esp,4", but he had pushed ebp, which is overridden with the parameters for the calls. one could say "works by accident" – Tommylee2k Feb 22 '18 at 13:13
  • @Tommylee2k : His stack frame is never used correct because he short circuited it because he called the `exit` function in the _C_ runtime. However he probably typically has a full stack frame. He probably should have put the stack prologue at the end for completeness. Sure the author isn't using it, but it was just an example. The version of the code with `sub esp, 4`is not buggy, it just happens to have a prologue (stackframe) that isn't needed. – Michael Petch Feb 22 '18 at 13:17
  • exactly. functionally his code is working (with a lot of luck even), but he (obviously) messed it up completely – Tommylee2k Feb 22 '18 at 13:19
  • One reason you may wish to put the stack frame in there (despite it not being used by the function itself) is to allow the debugger to form a proper backtrace in the absence of any debug meta data. – Michael Petch Feb 22 '18 at 13:35