Understanding how EIP (RIP) register works?
Let's begin with a concrete, x86-specific example.
00000000000020b0 <foo>:
20b0: 89 d1 movl %edx, %ecx
20b2: 89 f8 movl %edi, %eax
20b4: 0f af c6 imull %esi, %eax
20b7: 31 d2 xorl %edx, %edx
20b9: f7 f1 divl %ecx
20bb: c3 ret
For the sake of simplicity and of this example, think of memory as a gigantic "array" of bytes, and think of memory addresses as indexes into such an "array"0. When something lies at a given memory address, that essentially means that its first byte lies at that address, its second byte (if it's more than just a byte big) lies at the next address, and so on. For example, foo
starts at address 0x20B0
1 and spans 12 bytes. This means that each address from 0x20B0
to 0x20BB
(inclusive) points to a byte in the function.
The program counter in x86, called RIP
(EIP
if 32-bit), points to the next instruction2. For example, if the current instruction being executed is the one at 0x20B2
, RIP
would contain the value 0x20B4
. Because of the CISC nature of x86, instruction sizes differ, so RIP
does not necessarily increase by a fixed amount each time.
00000000000020b0 <foo>:
20b0: 89 d1 movl %edx, %ecx
EX->20b2: 89 f8 movl %edi, %eax
PC->20b4: 0f af c6 imull %esi, %eax
20b7: 31 d2 xorl %edx, %edx
20b9: f7 f1 divl %ecx
20bb: c3 ret
In the next "iteration", EX (not a real register, just a way to mark what's being executed) will point to the imull
instruction, and PC (RIP
) will point to the xorl
instruction, and so on until the ret
instruction, at which point the return address, which is stored on the stack, will be loaded into RIP
so that execution may continue at the caller of foo
.
0 As mentioned by Peter Cordes, there are some architectures out there where this does not apply. For the sake of the question, this answer is specific to x86.
1 That's not actually the address at which this function would be found at runtime, but pretend it is for the sake of example.
2 There are some architectures where the program counter points to the current instruction (AArch64 does this), or even to two instructions ahead (AArch32 does this).