一尘不染

如何在C中打印程序计数器的确切值

linux

我想写一个C程序,它将打印程序计数器的内容PC。可以从用户空间,程序集或使用某些特定的内核例程来完成此操作吗?


阅读 329

收藏
2020-06-03

共1个答案

一尘不染

您应该能够使用ARM编译器工具链中的__current_pc()内在函数来确定PC
(ARM编译器支持许多与GCC相同的扩展)。*这是ARM特有的:

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

*感谢FrankH。指出存在__current_pc()

通常,PC在函数调用中被保存为返回地址。在具有GCC的非ARM linux系统上,您可以调用__builtin_return_address(0)以获取当前函数调用上下文的返回地址。以这种方式获得程序计数器会增加添加函数调用的代价,但是避免了内联汇编,因此该技术可移植到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;
}

当我在x86系统上运行上述程序时,它将产生输出:

0x8048432
0x8048447
0x804845c

在拆卸时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.
2020-06-03