2013-08-21 22 views
5

プログラムカウンタPCの内容を出力するCプログラムを作成したいと思います。これはユーザー空間、アセンブリ、またはいくつかの特定のカーネルルーチンが使用されることができますか?Cのプログラムカウンタの正確な値を出力する方法

+0

デバッガのコードがPCを制御/アクセスするので、インラインアセンブリを使用する方法があるはずです。 –

+0

@GrijeshChauhan:プログラムカウンターのGCC拡張があると思いますか? –

+1

はい私はあまりよく分かっていませんが、このノートを回避するには何らかの方法が必要だと感じています:コードに 'lable:'がある場合、 '&lable'を使ってそのアドレスを表示することができます)。非常に後方のコード(合法的)はこの種の命令を使用しますが、マルウェアコードで頻繁に使用します。 –

答えて

11

(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は、関数呼び出しのリターンアドレスとして保存されます。 ARM以外のシステムでGCCを使用している場合は、__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 <[email protected]> 
    0x08048442 <+30>: call 0x804841c <get_pc> 
    0x08048447 <+35>: mov %eax,0x4(%esp) 
    0x0804844b <+39>: movl $0x8048510,(%esp) 
    0x08048452 <+46>: call 0x80482f0 <[email protected]> 
    0x08048457 <+51>: call 0x804841c <get_pc> 
    0x0804845c <+56>: mov %eax,0x4(%esp) 
    0x08048460 <+60>: movl $0x8048510,(%esp) 
    0x08048467 <+67>: call 0x80482f0 <[email protected]> 
    0x0804846c <+72>: mov $0x0,%eax 
    0x08048471 <+77>: leave 
    0x08048472 <+78>: ret  
End of assembler dump. 
+1

リターンアドレスとPC( 'EIP' /' RIP')は同じものではありません。 –

+0

お詫び申し上げます。ARMでは、リターンアドレス( 'LR')と' PC'は同じものではありません。 –

+0

さらに、あなたの作品がなぜ機能するかは、あなたが関数call_(あなたの関数内で 'LR'を呼び出しサイトの' PC 'にする)を強制するためです。これは不必要に非効率的です。 –

2

あなたはCコードの中にアセンブリブロックを挿入することで情報を得ることができると思います。これは、あなたのコンパイラとあなたのプラットフォームのレジスタセットに完全に依存します。 私はこのようにそれをやった:あなたはARMコンパイラツールチェーンで__current_pc() intrinsicを使用してPCを決定することができるはず

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

5

をARMで、使用することができます

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

それともこの1つは同様に動作する必要があります。それはあなたが呼び出しサイトごとにPCを取得保証しているため

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

強制インライン化は、ここで重要なのです。

編集:ちょうど覚えている__current_pc() ARM intrinsic。 GCCもこれを持っているはずです。

関連する問題