0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

__x86.get_pc_thunk関数とは(OS開発用調査)

0
Posted at

背景(この章は全記事共通)

現在C言語にてOSを開発しています。
どんな機械語が生成されるかを把握するために、色々な検証をしています。

OSのソースは以下です。
投稿時点 : https://github.com/ooe1220/KansoOS/1de6692041b109c82d6824c27cf870ef29ed59cb
最新 : https://github.com/ooe1220/KansoOS

本記事はdocs/notesにある覚書の写しです。

目的

Linux上でC言語をアセンブリへ変換すると、__x86.get_pc_thunkという関数が生成されることがよくあります。

0000118d <main>:
    118d:	55                   	push   ebp
    118e:	89 e5                	mov    ebp,esp
    1190:	e8 10 00 00 00       	call   11a5 <__x86.get_pc_thunk.ax>
    1195:	05 47 2e 00 00       	add    eax,0x2e47
    119a:	8b 80 2c 00 00 00    	mov    eax,DWORD PTR [eax+0x2c]
    11a0:	83 c0 03             	add    eax,0x3
    11a3:	5d                   	pop    ebp
    11a4:	c3                   	ret    
test.c
//gcc -m32 -O0 test.c -o test.out
//objdump -d -M intel test.out
//readelf -S test.out

int global_var = 5;

int main(void)
{
    return global_var + 3;
}

__x86.get_pc_thunkの意味

x86にはmov eax, eipという命令がありません。
そこで__x86.get_pc_thunkを呼び出してeip(実行中の命令を指すレジスタ)の値を取得します。

call命令を実行するとCPUは自動的にcall命令が配置されている位置のアドレスをスタックに積んで、指定したアドレスへ跳びます。
実質call add = push 現在アドレス jmp 指定アドレスです。

__x86.get_pc_thunkの中身を見てみるとスタックから返りアドレスを取り出してEAXレジスタに格納しています。

000011a5 <__x86.get_pc_thunk.ax>:
    11a5:	8b 04 24             	mov    eax,DWORD PTR [esp]
    11a8:	c3                   	ret    

main関数内での作用

広域変数global_varを使用しています。global_varのアドレスはgotに格納されており、この変数を参照するには、現在地からのオフセットで指定します。

GOTのアドレスは以下の通り。

 [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
 [22] .got              PROGBITS        00003fdc 002fdc 000024 04  WA  0   0  4

main中では1195を取得する為に__x86.get_pc_thunk.axを呼び出しています。

    1190:	e8 10 00 00 00       	call   11a5 <__x86.get_pc_thunk.ax>
    1195:	05 47 2e 00 00       	add    eax,0x2e47
    119a:	8b 80 2c 00 00 00    	mov    eax,DWORD PTR [eax+0x2c]

以下の様に足すとGOTを指すことが出来ます。

 0x1195
+0x2e47
--------
 0x3fdc

GOTの中身

test@test-fujitsu:~/kaihatsu/ctest$ readelf -S test.out | grep got
  [13] .plt.got          PROGBITS        00001050 001050 000008 08  AX  0   0  8
  [22] .got              PROGBITS        00003fdc 002fdc 000024 04  WA  0   0  4                            ....      
test@test-fujitsu:~/kaihatsu/ctest$ objdump -s -j .got test.out

test.out:     文件格式 elf32-i386

Contents of section .got:
 3fdc e43e0000 00000000 00000000 46100000  .>..........F...
 3fec 00000000 00000000 00000000 8d110000  ................
 3ffc 00000000                             ....            
test@test-fujitsu:~/kaihatsu/ctest$ 

mov eax,DWORD PTR [eax+0x2c]はGOTの中身を参照しているのではなく、
GOTを基準アドレスとして global_var の実体位置を計算しています。
そのため、GOT開始アドレス0x3fdc0x2cを加算すると、global_varが配置されているアドレスになります。

3fdc + 0x2c = 4008

この場所を見てみるとint global_var = 5;の初期値と一致します。

test@test-fujitsu:~/kaihatsu/ctest$ objdump -s --start-address=0x4000 --stop-address=0x4020 test.out

test.out:     文件格式 elf32-i386

Contents of section .data:
 4000 00000000 04400000 05000000           .....@......

他のレジスタ向けの関数

今回はEAX向けの関数を使用する機械語が生成されましたが、対象レジスタに応じて以下のような関数も生成されます。

00001090 <__x86.get_pc_thunk.bx>:
    1090:	8b 1c 24             	mov    ebx,DWORD PTR [esp]
    1093:	c3                   	ret 
00001189 <__x86.get_pc_thunk.dx>:
    1189:	8b 14 24             	mov    edx,DWORD PTR [esp]
    118c:	c3                   	ret  
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?