Assuming that segment descriptor for code, data, stack are stored in cs, ds and respectively ss registers.
Instruction pointer
- value is in EIP register (RIP for 64 bits)
- processor will execute an instruction stored in the address specified by the EIP
- jump loc1 will change EIP to loc1
Stack pointer ESP
Point to top address of the stack
- value is in ESP register (RSP for 64 bits)
- push/pop instruction will store/get a value from an address specified by ESP and decrease/increase ESP by a corresponding size
- stack grows from higher to lower memory address
- Kernel can directly modify ESP during context switch
call loc1 will push memory location after the instruction (EIP content) into current stack (memory location specified by ESP register) and jump to loc1.
ret will change EIP to a value in an address specified by ESP and increase ESP by a corresponding size
Stack base pointer EBP
holds address of current stack frame, a range of stack holding passed parameters, return address and local parameters
- value is in EBP register (RBP for 64 bits)
- EBP contains address in stack where return address is stored.
x86 Function Call
ESP and EBP: The Stack Pointer and the Base Pointer
When a block of code calls a function, it pushes the parameters and the return address on the stack. Once inside, function sets the base pointer equal to the stack pointer and then places its own internal variables on the stack. From that point on, the function refers to its parameters and variables relative to the base pointer rather than the stack pointer.
Why not the stack pointer? For some reason, the stack pointer lousy addressing modes. In 16-bit mode, it cannot be a square-bracket memory offset at all. In 32-bit mode, it can be appear in square brackets only by adding an expensive SIB byte to the opcode.
In your code, there is never a reason to use the stack pointer for anything other than the stack.
The base pointer, however, is up for grabs. If your routines pass parameters by register instead of by stack (they should), there is no reason to copy the stack pointer into the base pointer. The base pointer becomes a free register for whatever you need.
AT&T assembly syntax
example assembly code generated by hotspot jvm
# {method} 'setA' '(I)V' in 'TestVolatile'
# this: ecx = 'TestVolatile'
# parm0: edx = int
# [sp+0x10] (sp of caller)
0xb4f48980: cmp 0x4(%ecx),%eax ;...3b4104
0xb4f48983: jne 0xb4f2cea0 ;...0f851745 feff
; {runtime_call}
0xb4f48989: xchg %ax,%ax ;...666690
[Verified Entry Point]
0xb4f4898c: push %ebp ;...55
0xb4f4898d: sub $0x8,%esp ;...81ec0800 0000
0xb4f48993: mov %edx,0x8(%ecx) ;...895108
0xb4f48996: lock addl $0x0,(%esp) ;...f0830424 00
;*synchronization entry
; - TestVolatile::setA@-1 (line 14)
0xb4f4899b: add $0x8,%esp ;...83c408
0xb4f4899e: pop %ebp ;...5d
0xb4f4899f: test %eax,0xb7f62000 ;...85050020 f6b7
; {poll_return}
0xb4f489a5: ret ;...c3
- register: %ax, %eax
- constant: $0x18, $0x4
- access memory location, its address is in register: (%ecx)
- access memory location, its address is in register + offset: 0x4(%ecx)
- move data from source (left operand) to destination (right operand): mov %edx,0x8(%ecx)
References