Can the program counter on Intel CPUs can be read directly (that is without 'tricks') in kernel mode or some other mode?
7 Answers
No, EIP / IP cannot be accessed directly, but in position-dependent code it's a link-time constant so you can use a nearby (or distant) symbol as an immediate.
mov eax, nearby_label ; in position-dependent code
nearby_label:
To get EIP or IP in position-independent 32-bit code:
call _here
_here: pop eax
; eax now holds the PC.
On CPUs newer than Pentium Pro (or PIII probably), call rel32
with rel32=0 is special-cased to not affect the return-address predictor stack. So this is efficient as well as compact on modern x86, and is what clang uses for 32-bit position-independent code.
On old 32-bit Pentium Pro CPUs, this would unbalance the call/return predictor stack, so prefer calling a function that does actually return, to avoid branch mispredicts on up to 15 or so future ret
instructions in your parent functions. (Unless you're not going to return, or so rarely that it doesn't matter.) The return-address predictors stack will recover, though.
get_retaddr_ppro:
mov eax, [esp]
ret ; keeps the return-address predictor stack balanced
; even on CPUs where call +0 isn't a no-op.
In x86-64 mode, RIP can be read directly using a RIP-relative lea
.
default rel ; NASM directive: use RIP-relative by default
lea rax, [_here] ; RIP + 0
_here:
MASM or GNU .intel_syntax
: lea rax, [rip]
AT&T syntax: lea 0(%rip), %rax
If you need the address of a specific instruction, usually something like this does the trick:
thisone:
mov (e)ax,thisone
(Note: On some assemblers this might do the wrong thing and read a word from [thisone], but there's usually some syntax for getting the assembler to do the right thing.)
If your code is statically loaded to a specific address, the assembler already knows (if you told it the right starting address) the absolute addresses of all instructions. Dynamically loaded code, say as a part of an application on any modern OS, will get the right address thanks to address relocation done by the dynamic linker (provided the assembler is smart enough to generate the relocation tables, which they usually are).
There is no instruction to directly read the instruction pointer (EIP) on x86. You can get the address of the current instruction being assembled with a little inline assembly:
// GCC inline assembler; for MSVC, syntax is different
uint32_t eip;
__asm__ __volatile__("movl $., %0", : "=r"(eip));
The .
assembler directive gets replaced with the address of the current instruction by the assembler. Note that if you wrap the above snippet in a function call, you'll just get the same address (within that function) every time. If you want a more usable C function, you can instead use some non-inline assembly:
// In a C header file:
uint32_t get_eip(void);
// In a separate assembly (.S) file:
.globl _get_eip
_get_eip:
mov 0(%esp), %eax
ret
This means each time you want to get the instruction pointer, it's slightly less efficient since you need an extra function call. Note that doing it this way does not blow the return address stack (RAS). The return address stack is a separate stack of return addresses used internally by the processor to facilitate branch target prediction for RET instructions.
Every time you have a CALL instruction, the current EIP gets pushed onto the RAS, and every time you have a RET instruction, the RAS is popped, and the top value is used as the branch target prediction for that instruction. If you mess up the RAS (such as by not matching each CALL with a RET, as in Cody's solution), you're going to get a whole bunch of unnecessary branch mispredictions, slowing your program down. This method does not blow the RAS, since it has a matched pair of CALL and RET instructions.
There is an architecture independent (but gcc dependent) way of accessing the address which is being executed by using labels as values:
http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
void foo()
{
void *current_address = $$current_address_label;
current_address_label:
....
}
There is a simple way to change the program counter (eip)
When you call a function with 'call' the eip is pushed in the stack then when you ret the eip is just poped from the stack . so , all what you have to do is to push the value you want and then ret . for example:
mov eax, 0x100
push eax`
ret
and it's done.
jmp
. My answer there explains why x86 machine code was designed so you can't encode amov
toeip
, the way you can on ARM where PC is one of the general-purpose integer registers. – Peter Cordes