Comment imprimer la valeur exacte du compteur de programme en C

Je veux écrire un programme C qui imprime le contenu du compteur PC du programme. Est-ce que cela peut être fait à partir de l’espace utilisateur, de l’assembly ou de certaines routines spécifiques du kernel?

Vous devriez être capable de déterminer le PC en utilisant l’ __current_pc() insortingnsèque __current_pc() dans la chaîne d’outils du compilateur ARM (le compilateur ARM prend en charge plusieurs des mêmes extensions que GCC). * Ceci est particulier à ARM:

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

* Merci à FrankH. pour signaler la présence de __current_pc()

En général, le PC est enregistré comme adresse de retour dans un appel de fonction. Sur les systèmes Linux non-ARM avec GCC, vous pouvez appeler __builtin_return_address(0) pour obtenir l’adresse de retour du contexte d’appel de fonction en cours. L’obtention du compteur de programme de cette manière entraîne la pénalité de l’ajout d’un appel de fonction, mais évite l’assemblage en ligne. Cette technique est donc portable pour tout système pris en charge par 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; } 

Lorsque je lance le programme ci-dessus sur mon système x86 , il produit le résultat:

 0x8048432 0x8048447 0x804845c 

Lorsque démonté en 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  0x08048432 <+14>: mov %eax,0x4(%esp) 0x08048436 <+18>: movl $0x8048510,(%esp) 0x0804843d <+25>: call 0x80482f0  0x08048442 <+30>: call 0x804841c  0x08048447 <+35>: mov %eax,0x4(%esp) 0x0804844b <+39>: movl $0x8048510,(%esp) 0x08048452 <+46>: call 0x80482f0  0x08048457 <+51>: call 0x804841c  0x0804845c <+56>: mov %eax,0x4(%esp) 0x08048460 <+60>: movl $0x8048510,(%esp) 0x08048467 <+67>: call 0x80482f0  0x0804846c <+72>: mov $0x0,%eax 0x08048471 <+77>: leave 0x08048472 <+78>: ret End of assembler dump. 

Sur ARM, vous pouvez utiliser:

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

Ou celui-ci devrait aussi bien fonctionner:

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

L’incrustation forcée est importante ici, car cela vous permet de récupérer le PC fonction du site d’appel.

Edit: vient de se souvenir, __current_pc() ARM insortingnsèque . GCC devrait avoir cela aussi.

Eh bien, je pense que vous pouvez obtenir les informations en insérant des blocs d’assemblage dans votre code C. Cela dépendra totalement de votre compilateur et de l’ensemble de registres de votre plate-forme. Je l’ai fait comme ça:

 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