views:

1214

answers:

4

Can the program counter on Intel CPU's can be read directly (that is without 'tricks') in kernel mode or some other mode?

Thanks :-).

+7  A: 

No, (E/R)IP cannot be accessed directly. To get it:

call _here
_here: pop eax
; eax now holds the PC.
Cody Brocious
Ah, I love that trick. In ARM, there are pipelining issues when reading the PC. Is this issue present with Intel CPU's as well?
strager
No, it is not present on x86. (Btw - the ARM pipelining issue is crazy)
Nils Pipenbrinck
In x86, you have the cost of a branch, which is far worse for the pipeline than just reading the PC. PIC on ARM is far cheaper than x86, even with the pipeline oddities.
Cody Brocious
This code actually screws up the return value branch prediction and slows you down quite a lot. I'll try to find a reference for this...
Adam Rosenfield
Still trying to find a reference, but the keyword is "return address stack", which is a stack of return addresses the processor uses to predict the branch targets of RET instructions. Since CALL pushes EIP onto the RAS, you're screwing up the RAS.
Adam Rosenfield
You could fix that issue by pushing a label on the stack after you pop the eip, and then doing a ret (which would jump to the label you pushed).
SoapBox
Don't know why this is the accepted answer over TrayMan's answer. TrayMan's version has no unexpected side effects and is shorter.
Skizz
http://www.ptlsim.org/Documentation/html/node31.html has a good description on "return address stack"
mfazekas
+6  A: 

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).

TrayMan
Thanks for the info, good idea indeed. :)
Liran Orevi
+2  A: 

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.

Adam Rosenfield
Thanks, you guys rock :)
Liran Orevi
Many thanks for the info, I didn't know there were two stacks.. :)
Liran Orevi
The RAS is an internal stack used by the processor; it's not accessible to code in any way. It's only used for branch target prediction. Without it, code would still function correctly, just more slowly.
Adam Rosenfield
Thanks you so much.Does RAS mess up if you manually set the ESP after Push?
Liran Orevi
+2  A: 

on x86-64 you can do eg, :

lea rax,[rip] (48 8d 05 00 00 00 00)
matja
Thanks! What's the meaning of the numbers?
Liran Orevi
thats the instruction encoding - theres an implicit 32-bit offset which is 0, i'm not sure if there is a shorter encoding
matja