Let's suppose you have this stack (image borrowed from wikipedia):

To call the DrawSquare function, you first have to push its parameters on the stack. Then, you
call DrawSquare
and what this does is essentially
push eip ; push the current instruction pointer on the stack
jmp DrawSquare
so you now have the return address on the stack, too.
Then, the function you just called sets up its own stack frame.
push ebp
saves the previous function's base pointer (it will become clearer why, later); then
mov ebp, esp
moves the base pointer to where the stack pointer currently is (the pushed base pointer, in this case), making the base pointer point at the previous base pointer.
This way, we can freely move our stack pointer and restore it when we're done. Why am I saying that? Well, because one very important thing in functions is local variables, and you will store them on the stack.
So you make room for your local variables (you could also push them but conventionally you do it this way), and since the stack grows downwards, you move the stack pointer downwards, by subtracting from it.
sub esp, 4 ; make room for 4 bytes
; or one double word variable (32 bit)
; or two one-word variables (2 x 16 bit)
; or 4 byte variables (4 x 8 bit)
Then you can access these local variables by subtracting from the base pointer (that's why we need it to stay still at the beginning of the function frame)
mov [ebp - 4], 0xAABBCCDD ; move some random value (32 bit) into the new variable
; subtract 4 from ebp because it's a 4-byte variable
You can also access the parameters by using the base pointer
mov eax, [ebp + 8] ; first 32 bit parameter
; add 8 to ebp because
; at [ebp] is the previous base pointer (32 bits)
; and at [ebp + 4] is the return address (32 bits)
; so 32 + 32 is 64, 8 bytes of offset to access the first parameter
Then we decide to call another function, DrawLine.
So we push its parameters on the stack, just like we did before; and call it.
push ebx
push eax
call DrawLine
The function initialises its stack frame just like before
push ebp ; DrawSquare's base pointer
mov ebp, esp
and when it's done, it can close its call frame just by resetting the stack pointer and the base pointer
mov esp, ebp ; moves the stack pointer to where the base pointer is.
; ebp still points to the old ebp
pop ebp ; pops the previous ebp value into ebp
; effectively restoring the previous functions' base pointer
Then the function will also use (if in stdcall) (with cdecl (which is another calling convention) the caller clears the parameters instead)
ret 8
to "clear" its parameters and restore the instruction pointer to where the call was made. Actually, the eip is restored before the parameters are cleared, since the parameters are below the eip on the stack; however we can't do that ourselves since after restoring the eip (returning) we can't do anything more in the funciton, and so with ret 8
we tell the processor to do
pop eip ; restore esp from the stack, where the return address lies
and
add esp, 8 ; move the stack pointer before the parameters, effectively "clearing" them
at the same time.
Then the DrawSquare function does the same thing when it's done.
^ This is how a conventional (stdcall) call stack frame works ^
In your case, _start is not even a function, it's the entry point of the program. Indeed it has no return address pushed onto the stack, and so the esp is actually pointing to argc.
The sum function has no local variables whatsoever, so the function frame would only slow down the program and use more space.
And since the stack frame is only useful when accessing parameters and/or local variables on the stack (both things can also be done by just using esp without the frame, but when adding local variables it's common to use the ebp for it doesn't move like esp does), it isn't needed here.
What that sum function does, is passing the parameters via registers, which is fine if your parameters are very few.