The accepted answer of this StackOverflow post gives the following solution:
get_eip: mov eax, [esp]
ret
But I don't understand why this works. Why is the saved EIP pointed to by ESP? Shouldn't ESP be pointing to SFP (the old EBP value) at the time we execute the mov instruction? The prologue of a subroutine call in x86 assembly looks like:
push ebp ; Save the old base pointer value
mov ebp, esp ; Set the new base pointer value
sub esp, ... ; Make room for local variable
So shouldn't the saved EIP sit one more word above the address where ESP is pointing to?