天天看點

了解ELF動态連結中GOT與PLT表

今天閱讀ELF檔案結構中的GOT表與PLT表,生啪啪的文字沒看懂,索性從一個小實驗說起 ,一來記錄自己的技術成長軌迹,二來幫助需要之人。。

前言理論篇:

第一:為什麼要實作延遲綁定?

開始把所有的函數都連結實際是一種浪費,是以采用延遲綁定技術,核心是第一次用的時候進行綁定,沒有用到不進行綁定。

優點:加快程式的啟動速度

第二:怎麼實作上面的延遲綁定?(這一塊詳細介紹在程式員的自我修養這本書的7.4節)

使用PLT的方法,每個外部函數在PLT中都有一個相應的項,比如外部函數XXX為[email protected],實作為:

jmp      “位址”

push    “ printf引用在重定位表的“.rel.plt”中的下标”;

jump   _dl_runtime_resolve//這個函數是完成符号解析和重定位的;

首先簡單的寫一個小程式:

<span style="font-size:24px;">#include <stdio.h>
int add(int a,int b)
{
	int c=0;
	c=a+b;
	printf("%d\n",c);</span>
           
<span style="font-size:24px;">        return 0;
}
void main()
{
	add(2,3);
}</span>
           

編 譯

gcc -g Got.c -o Got

反彙編看彙編代碼:

<span style="font-size:24px;">#include <stdio.h>
int add(int a,int b)
{
  4004f4:	55                   	push   %rbp
  4004f5:	48 89 e5             	mov    %rsp,%rbp
  4004f8:	48 83 ec 20          	sub    $0x20,%rsp
  4004fc:	89 7d ec             	mov    %edi,-0x14(%rbp)
  4004ff:	89 75 e8             	mov    %esi,-0x18(%rbp)
	int c=0;
  400502:	c7 45 fc 00 00 00 00 	movl   $0x0,-0x4(%rbp)
	c=a+b;
  400509:	8b 45 e8             	mov    -0x18(%rbp),%eax
  40050c:	8b 55 ec             	mov    -0x14(%rbp),%edx
  40050f:	01 d0                	add    %edx,%eax
  400511:	89 45 fc             	mov    %eax,-0x4(%rbp)
	printf("%d\n",c);
  400514:	b8 3c 06 40 00       	mov    $0x40063c,%eax
  400519:	8b 55 fc             	mov    -0x4(%rbp),%edx
  40051c:	89 d6                	mov    %edx,%esi
  40051e:	48 89 c7             	mov    %rax,%rdi
  400521:	b8 00 00 00 00       	mov    $0x0,%eax
  400526:	e8 c5 fe ff ff       	callq  4003f0 <[email protected]>
        return 0;
  40052b:	b8 00 00 00 00       	mov    $0x0,%eax

}
  400530:	c9                   	leaveq 
  400531:	c3                   	retq   

0000000000400532 <main>:
void main()
{
  400532:	55                   	push   %rbp
  400533:	48 89 e5             	mov    %rsp,%rbp
	add(2,3);
  400536:	be 03 00 00 00       	mov    $0x3,%esi
  40053b:	bf 02 00 00 00       	mov    $0x2,%edi
  400540:	e8 af ff ff ff       	callq  4004f4 <add>
} </span>
           
</pre><span style="font-size:24px">我們看到主函數中調用子函數add是沒問題的,看到子函數中調用“400526:<span style="white-space:pre"></span>e8 c5 fe ff ff      <span style="white-space:pre"></span>callq  4003f0 <[email protected]>”看到這個“[email protected]”這是一個延遲綁定,不是通過GOT中相應的項進行間接跳轉,而是通過PLT項來進行跳轉,每個外部函數在PLT中都有一個項,這裡是printf函數。并且[email protected]都有一個固定的結構:</span><p><span style="font-size:24px"><span style="background-color:rgb(240,240,240)">jmp      “位址”</span></span></p><p><span style="font-size:24px"><span style="background-color:rgb(240,240,240)">push    “ printf引用在重定位表的“.rel.plt”中的下标”;</span></span></p><p><span style="font-size:24px"><span style="background-color:rgb(240,240,240)">jump   _dl_runtime_resolve//這個函數是完成符号解析和重定位的;</span></span></p><p><span style="font-size:24px; background-color:rgb(240,240,240)">繼續看一下</span><span style="font-size:24px; background-color:rgb(240,240,240)">[email protected]的彙編代碼:果然是這樣的套路:</span></p><p><span style="font-size:24px; background-color:rgb(240,240,240)"></span></p><pre name="code" class="plain"><span style="font-size:24px;">00000000004003f0 <[email protected]>:
  4003f0:	ff 25 0a 0c 20 00    	jmpq   *0x200c0a(%rip)        # 601000 <_GLOBAL_OFFSET_TABLE_+0x18>
  4003f6:	68 00 00 00 00       	pushq  $0x0
  4003fb:	e9 e0 ff ff ff       	jmpq   4003e0 <_init+0x18></span>
           

在這裡用gdb來調試一下:

很奇怪的事出現這個:

了解ELF動态連結中GOT與PLT表

很納悶,對于我這種底層不是很懂的小白,之能首先懷疑是不是樣本的問題?

首先很肯定一點的不是樣本問題:歡迎各位大俠指正。

建議大家看一下這幾個部落格寫的比較好:

http://www.programlife.net/linux-got-plt.html;

http://blog.csdn.net/lmh12506/article/details/6801630;

總結篇:

總的來說:第一次其實是調用_dl_runtime_resolve進行GOT對應的表項的修改,以增加愛延遲綁定的目的,進而達到不用連結所用的函數,就是用到的時候再連結,當連結以後就直接從GOT調轉到真正的函數,進而增加效率。不要被生啪啪的理論文字吓到。

繼續閱讀