I'm studying x86 architecture and assembly in order to have the bases for studying reversing and exploit development. I'm following a course on opensecuritytraining.info.

I see a Hello World example:

push ebp
mov ebp, esp
push offset aHelloWorld; "Hello world\n"
call ds:__imp__printf
add esp, 4
mov eax, 1234h
pop ebp

This code was generated by Windows Visual C++ 2005 with buffer overflow protection turned off and disassembled with IDA Pro 4.9 Free Version.

I'm trying to understand what each line does.

the first line is push ebp.

I know ebp stands for base pointer. What is its function?

I see that in the second line the value in esp is moved into ebp and searching online I see that there first 2 instructions are very common at the beginning of an assembly program.

Though are ebp and esp empty at the beginning? I'm new to assembly. Is ebp used for stack frames, so when we have a function in our code and is it optional for a simple program?

Then push offset aHelloWorld; "Hello world\n"

The part after ; is a comment so it doesn't get executed right? The first part instead adds the address containing the string Hello World to the stack, right? But where is the string declared? I'm not sure I understand.

Then call ds:__imp__printf

it seems it's a call to a function, anyway printf is a builtin function right? And does ds stand for data segment register? Is it used because we are trying to access a memory operand that isn't on the stack?

then add esp, 4

do we add 4 bytes to esp? Why?

then move eax, 1234h what is 1234h here?

then pop ebx..it was pushed at the beginning. is it necessary to pop it at the end?

then retn ( i knew about ret for returning a value after calling a function). I read that the n in retn refers to the number of pushed arguments by the caller. It isn't very clear for me. Can you help me to understand?

1 Answer 1


first up: I would recommend you to try and write some simple assembly programs or use an intermediate representation like REIL to get a hang of it (REIL has only ~17 instructions).

push ebp
mov ebp, esp

The first two lines build the stack frame. As you correctly mentioned, ebp describes the current stack frame. So when this function is called from another function, is saves the previous base pointer on the stack to be able to restore it when the function returns. When the value is saved, the function assignes the current location on the stack to be the new base pointer for this fuction.

This assignments are called function prolog and are common among different disassembleres. Mainly the ebp is used to reference function arguments, while the esp can be modified freely (by pushing variables on the stack, etc.)

push offset aHelloWorld; "Hello world\n" 

This function pushes the address of the String "Hello world\n" on the stack. The comment at the end is just for convenience matters. Please note pushing something on the stack modifies esp by the (byte-size) of the given value. In this case 4 for x32 and 8 for x64 references (esp=esp-4).

call ds:__imp__printf

This call does not directly jump to the function, because the function is loaded dynamically and the code does not know where the function is located in the address space. So it calls a reference to the location, which is the "jump table" or in this case rather "import table". When a binary is loaded, the systems loader ensures that it loads the dependencies and leaves the correct addresses for the program to use there. (imp stands for "import").

add esp, 4

Based on the calling convention (how are arguments passed? who cleans them from the stack?) printf does not clean up its stack before returning. So the calling function must do it itself. It adds 4 to the stack pointer to revert the changes from the push instruction (which subtracted 4 from esp implicitly).

mov eax, 1234h

Nothing special here. The value 0x1234 is moved to the register eax (apparently for no reason). I assume this is the return value of the program (unix convention is to return 0 in eax if there was no failure).

pop ebp

This instruction reads the former value of ebp from the stack and stores it in ebp again. Please note you must keep track of the order in which things were pushed on the stack (Last-In-First-Out). Note that this instruction also adds 4 to the esp implicitly.


Resume execution at the location at the current esp. When a function is called, the calling fucntion pushes the address to return to on the stack. Also, this function adds 4 to esp to 'remove' the address from the stack.

  • I think your answer is very clear, though I should learn more about computer architecture and assembly in order to understand better. I just started. Thank you for your help.
    – Fabio
    Commented Sep 8, 2016 at 10:31
  • 1
    No problem. Although there are many corner cases and special instructions, relatively few are common. I'd advise learning by doing using IDA or x64dbg ;) Questions are always welcome
    – Nordwald
    Commented Sep 8, 2016 at 11:08
  • This is more than a hello world
    – realtebo
    Commented Jul 6, 2018 at 20:17
  • When you said that "pushing something on the stack modifies esp by the (byte-size) of the given value. In this case 4 for x32 and 8 for x64 references (esp=esp-4)", what is this exactly 4? The given value isn't that storage bytes consumed by that string? Shouldn't it be longer?
    – Arise
    Commented Jan 10, 2021 at 18:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.