enter also needs a number which is the amount of space to allocate, which is the key to your question: these instructions are made to set up space for your function's local variables.
Local variables are referred to through the EBP register. Let me show you an example:
import core.stdc.stdio;
void main() {
int a = 8;
a += 8;
printf("%d\n", 8);
}
(This is D code but that's not really relevant)
Disassembly of section .text._Dmain:
00000000 <_Dmain>:
0: 55 push ebp
1: 8b ec mov ebp,esp
3: 83 ec 04 sub esp,0x4
6: b8 08 00 00 00 mov eax,0x8
b: 89 45 fc mov DWORD PTR [ebp-0x4],eax
e: 01 45 fc add DWORD PTR [ebp-0x4],eax
11: 50 push eax
12: b9 00 00 00 00 mov ecx,"%d\n"
17: 51 push ecx
18: e8 fc ff ff ff call printf
1d: 31 c0 xor eax,eax
1f: 83 c4 08 add esp,0x8
22: c9 leave
23: c3 ret
Let's break this up into each part:
0: 55 push ebp
1: 8b ec mov ebp,esp
3: 83 ec 04 sub esp,0x4
This is the function prolog, setting up ebp. The sub esp, 0x4 pushed the stack 4 bytes away - this makes room for our local int a variable, which is 4 bytes long.
The enter instruction is rarely used, but I believe enter 4,0 does this same thing - enter a function with 4 bytes of local variable space. edit: The other 0 is the nesting level, I've never seen it used... enter is generally slower than just doing the steps yourself as the compiler does here. /edit
6: b8 08 00 00 00 mov eax,0x8
b: 89 45 fc mov DWORD PTR [ebp-0x4],eax
This is the a=8 line - the second line stores the value in the local variable's memory.
e: 01 45 fc add DWORD PTR [ebp-0x4],eax
Then, we add to it in a+=8 (the compiler reused eax here since it recognized that the
number is the same...)
After that, it calls printf by pushing its arguments to the stack, then zeroes out the eax register (xor eax, eax), which is how D returns 0 from a function.
11: 50 push eax
12: b9 00 00 00 00 mov ecx,"%d\n"
17: 51 push ecx
18: e8 fc ff ff ff call printf
1d: 31 c0 xor eax,eax
1f: 83 c4 08 add esp,0x8
Note that the add esp, 0x8 here is part of the call to printf: the caller is responsible for cleaning up the arguments after calling the function. This is needed because only the caller knows how many args it actually sent - this is what enables printf's variable arguments.
Anyway, finally, we clean up our local variables and return from the function:
22: c9 leave
23: c3 ret
edit: leave btw expands to mov esp, ebp; pop ebp; - it is exactly the opposite of the setup instructions, and like Aki Suihkonen said in the other answer, a nice thing here is the stack is restored to how it was at function entrance, no matter what happened inside the function (well, unless the function totally destroyed the stack's contents, in which case your program will most likely soon crash). /edit
So, bottom line, the ebp stuff is all about your local variables. It uses esp to get started so it has a nice memory space that won't step on other functions (it is on the call stack), but moves it to ebp so your locals remain at a consistent offset throughout the function - the variable a is ALWAYS [EBP-4] in this function, even as the stack is manipulated.
It is easiest to see in action by disassembling a function you write in C or something, like we did here. The linux command objdump -d -M intel somefile.o is what I used (then I manually fixed up some minor things to make it more readable. If you disassemble a .o file not all library calls are resolved yet so it can look kinda weird, but that doesn't affect the local variable stuff!)