如何在C中打印程序计数器的确切值 [英] How to print exact value of the program counter in C

查看:26
本文介绍了如何在C中打印程序计数器的确切值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个 C 程序来打印程序计数器 PC 的内容.这可以从用户空间、汇编或使用某些特定的内核例程来完成吗?

解决方案

您应该能够通过使用 __current_pc() 内在的 ARM 编译器工具链(ARM 编译器支持许多与 GCC 相同的扩展).* 这是 ARM 特有的:

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

<块引用>

* 感谢 FrankH.用于指出 __current_pc()

的存在

一般来说,PC 被保存为函数调用中的返回地址.在带有 GCC 的非 ARM 系统上,您可以调用 __builtin_return_address(0) 获取当前函数调用上下文的返回地址.以这种方式获取程序计数器会产生添加函数调用的惩罚,但它避免了内联汇编,因此该技术可移植到任何 GCC 支持的系统.

__attribute__ ((__noinline__))void * get_pc () { return __builtin_return_address(0);}int主(){printf("%p\n", get_pc());printf("%p\n", get_pc());printf("%p\n", get_pc());返回0;}

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

0x80484320x80484470x804845c

gdb中反汇编时:

转储函数 main 的汇编代码:0x08048424 <+0>:推%ebp0x08048425 <+1>: mov %esp,%ebp0x08048427 <+3>: 和 $0xfffffff0,%esp0x0804842a <+6>: sub $0x10,%esp0x0804842d <+9>:调用 0x804841c <get_pc>0x08048432 <+14>: mov %eax,0x4(%esp)0x08048436 <+18>: movl $0x8048510,(%esp)0x0804843d <+25>:调用 0x80482f0 <printf@plt>0x08048442 <+30>:调用 0x804841c <get_pc>0x08048447 <+35>: mov %eax,0x4(%esp)0x0804844b <+39>: movl $0x8048510,(%esp)0x08048452 <+46>:调用 0x80482f0 <printf@plt>0x08048457 <+51>:调用 0x804841c <get_pc>0x0804845c <+56>: mov %eax,0x4(%esp)0x08048460 <+60>: movl $0x8048510,(%esp)0x08048467 <+67>:调用 0x80482f0 <printf@plt>0x0804846c <+72>: mov $0x0,%eax0x08048471 <+77>:离开0x08048472 <+78>:返回汇编程序转储结束.

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 routines are used?

解决方案

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

__attribute__ ((__noinline__))
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.

这篇关于如何在C中打印程序计数器的确切值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆