PCをゲットしよう in x86 Linux

x86の命令ではPCを直接取得する命令はない。多分。でもcallを使うとメモリ上にPCは退避される。だったらそれを横から掠めてやれば、いつだってPCを見放題だね。


前回書いたように、Linuxでは関数の中のローカル変数一個めの位置から幾つか先に行ったところにPCはある。
前回だと4*4byteのところにあったけど、最適化の施され方如何によってはまるきり見当違いなことをしてしまう可能性もある。


そういう理由で、この類のコードは却下。

#include <stdio.h>                                                                                                                             

int getpc(void)                                                                                                                                
{                                                                                                                                              
  int x;                                                                                                                                    
  return *((&x) + 4);                                                                                                                        
}                                                                                                                                             
                                                                                                                                               
int main(void)                                                                                                                                 
{                                                                                                                                              
  int addr;                                                                                                                                    
  addr = getpc();                                                                                                                              
                                                                                                                                               
  printf("main addr : %x\npc addr   : %x\n", (int)main, addr);                                                                                 
}                                                                                                                                              
                                                


ならどうするか。
ここでインラインアセンブラですよ。うふふ。
関数の呼出元でcallしてくれてるので、その時点のespの指すアドレスにPCが格納されるはずなのです。

#include <stdio.h>                                                                                                                             

__asm__("getpc:\n\t"                                                                                                                           
        "mov (%esp), %eax\n\t"                                                                                                                 
        "ret"                                                                                                                                  
        );                                                                                                                                     
                                                                                                                                               
int main(void)                                                                                                                                 
{                                                                                                                                              
  int addr;                                                                                                                                    
  addr = getpc();                                                                                                                              
                                                                                                                                               
  printf("main addr : %x\npc addr   : %x\n", (int)main, addr);                                                                                 
}

これだけで良い。GOOD!


にしても %esp と (%esp) とが違うとは…!
%esp だと %esp の内容で、(%esp) だと %esp の指しているところの内容になる模様。
ポインタと比較してみると、int * hogefugaに対して

アセンブリ言語だとこうだけど これってポインタのこれに似てる。 つまり、これは
%esp hogefuga シンボルの値
(%esp) *hogefuga シンボルの値の指す場所の値

みたいな具合か。


ちゃんと資料や本を読まないと、こゆところでつまづくんだにゃー。


参考URL
gccのx86インラインアセンブリに関して
http://www.pdfdownload.org/pdf2html/pdf2html.php?url=http%3A%2F%2Fwww.hpcs.is.tsukuba.ac.jp%2F~msato%2Flecture-note%2Fkikaigo2007%2Flecture7.pdf&images=yes
http://alohakun.blog7.fc2.com/blog-entry-422.html