When the function is called, the stack looks like:
+-------------+
| Parameter 2 |
+-------------+
| Parameter 1 |
+-------------+
| Return Addr | <-- esp
+-------------+
then after the “stack frame” is set up:
+-------------+
| Parameter 2 | <-- [ebp + 12]
+-------------+
| Parameter 1 | <-- [ebp + 8]
+-------------+
| Return Addr |
+-------------+
| saved ebp | <-- ebp
+-------------+ <-- esp
Now the context is saved:
+-------------+
| Parameter 2 | <-- [ebp + 12]
+-------------+
| Parameter 1 | <-- [ebp + 8]
+-------------+
| Return Addr |
+-------------+
| saved ebp | <-- ebp
+-------------+
| saved eax |
+-------------+
| saved ebx |
+-------------+
| saved ecx |
+-------------+
| saved edx | <-- esp
+-------------+
Don’t forget that on many systems the stack grows downward (and that is definitely true of the x86 family), so the top of the stack will have the lowest memory address.