How to print exact value of the program counter in C

后端 未结 3 1383
有刺的猬
有刺的猬 2020-12-10 06:29

I want to write a C program which would print the contents of the program counter PC. Can this be done from user space, or assembly, or some specific kernel rou

相关标签:
3条回答
  • 2020-12-10 07:04

    Well I think you can get the information by inserting assembly blocks inside your C code. This will totally depend on your compiler and the register set of your platform. I did it like this:

    int get_counter1()
    
    {
    
        __asm__ ("lea (%rip), %eax ") ;
    }
    
    int get_counter2()
    
    {
    
        int x = 0;
        __asm__ ("lea (%rip), %eax") ;
    }
    
    int main()
    
    {
    
        printf("%x\n",get_counter1());
        printf("%x\n",get_counter2());
        return 0;
    }
    

    4004ce

    4004e1

    0 讨论(0)
  • 2020-12-10 07:16

    You should be able to determine the PC by using the __current_pc() intrinsic in the ARM compiler toolchain (the ARM compiler supports many of the same extensions as GCC).* This is particular to ARM:

    int main () {
        printf("%#x\n", __current_pc());
        printf("%#x\n", __current_pc());
        printf("%#x\n", __current_pc());
        return 0;
    }
    

    * Thanks to FrankH. for pointing out the presence of __current_pc()

    In general, the PC gets saved as the return address in a function call. On non-ARM linux systems with GCC, you can call __builtin_return_address(0) to obtain the return address of the current function call context. Obtaining the program counter in this way incurs the penalty of adding a function call, but it avoids inline assembly, so this technique is portable to any system supported by GCC.

    void * get_pc () { return __builtin_return_address(0); }
    int main () {
        printf("%p\n", get_pc());
        printf("%p\n", get_pc());
        printf("%p\n", get_pc());
        return 0;
    }
    

    When I run the above program on my x86 system, it produces the output:

    0x8048432
    0x8048447
    0x804845c
    

    When disassembled in gdb:

    Dump of assembler code for function main:
       0x08048424 <+0>: push   %ebp
       0x08048425 <+1>: mov    %esp,%ebp
       0x08048427 <+3>: and    $0xfffffff0,%esp
       0x0804842a <+6>: sub    $0x10,%esp
       0x0804842d <+9>: call   0x804841c <get_pc>
       0x08048432 <+14>:    mov    %eax,0x4(%esp)
       0x08048436 <+18>:    movl   $0x8048510,(%esp)
       0x0804843d <+25>:    call   0x80482f0 <printf@plt>
       0x08048442 <+30>:    call   0x804841c <get_pc>
       0x08048447 <+35>:    mov    %eax,0x4(%esp)
       0x0804844b <+39>:    movl   $0x8048510,(%esp)
       0x08048452 <+46>:    call   0x80482f0 <printf@plt>
       0x08048457 <+51>:    call   0x804841c <get_pc>
       0x0804845c <+56>:    mov    %eax,0x4(%esp)
       0x08048460 <+60>:    movl   $0x8048510,(%esp)
       0x08048467 <+67>:    call   0x80482f0 <printf@plt>
       0x0804846c <+72>:    mov    $0x0,%eax
       0x08048471 <+77>:    leave  
       0x08048472 <+78>:    ret    
    End of assembler dump.
    
    0 讨论(0)
  • 2020-12-10 07:18

    On ARM, you can use:

    static __inline__ void * get_pc(void)  {
        void *pc;
        asm("mov %0, pc" : "=r"(pc));
        return pc;
    }
    

    Or this one should work as well:

    static __inline__ void * get_pc(void) {
        register void * pc __asm__("pc");
        __asm__("" : "=r"(pc));
        return pc;
    }
    

    The forced inlining is important here, because that ensures you retrieve PC as per the call site.

    Edit: just remembered, __current_pc() ARM intrinsic. GCC should have this as well.

    0 讨论(0)
提交回复
热议问题