Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading program counter directly

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

like image 705
Liran Orevi Avatar asked Mar 01 '09 15:03

Liran Orevi


People also ask

How do you read a program counter?

A program counter is a register in a computer processor that contains the address (location) of the instruction being executed at the current time. As each instruction gets fetched, the program counter increases its stored value by 1.

Can we access the program counter?

Program counter cannot be directly read as like other I/O registers in AVR devices. The only way to read out the PC is by issuing a 'RCALL' or 'CALL' instruction (depending on the device that support this instruction.

What is the difference between program counter and instruction register?

The program counter (PC) holds the address of the next instruction to be executed, while the instruction register (IR) holds the encoded instruction. Upon fetching the instruction, the program counter is incremented by one "address value" (to the location of the next instruction).

What does the program counter do when I step through my program?

The processor checks the program counter to see which instruction to run next. The program counter gives an address value in the memory of where the next instruction is. The processor fetches the instruction value from this memory location. Once the instruction has been fetched, it needs to be decoded and executed.


1 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

like image 178
Serafina Brocious Avatar answered Sep 21 '22 13:09

Serafina Brocious