日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux got分析,聊聊Linux动态链接中的PLT和GOT(3)——公共GOT表项

發布時間:2024/2/28 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux got分析,聊聊Linux动态链接中的PLT和GOT(3)——公共GOT表项 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前文(聊聊Linux動態鏈接中的PLT和GOT(2)——延遲重定位)提到所有動態庫函數的plt指令最終都跳進公共plt執行,那么公共plt指令里面的地址是什么鬼?

把test可執行文的共公plt貼出來:

080482a0 :

80482a0: pushl 0x80496f0

80482a6: jmp *0x80496f4

...

第一句,pushl 0x80496f0,是將地址壓到棧上,也即向最終調用的函數傳遞參數。

第二句,jmp *0x80496f4,這是跳到最終的函數去執行,不過猜猜就能想到,這是跳到能解析動態庫函數地址的代碼里面執行。

0x80496f4里面住著是何方圣呢?下面使用gdb調試器將它請出來:

$ gdb -q ./test

...

(gdb)x/xw 0x80496f4

0x80496f4 8>: 0x00000000

(gdb) b main

Breakpoint 1 at 0x80483f3

(gdb) r

Starting program: /home/ivan/test/test/test

Breakpoint 1, 0x80483f3 in main ()

(gdb) x/xw 0x80496f4

0x80496f4 8>: 0xf7ff06a0

從調試過程可以發現,0x80496f4屬于GOT表中的一項,進程還沒有運行時它的值是0x00000000,當進程運行起來后,它的值變成了0xf7ff06a0。如果做更進一步的調試會發現這個地址位于動態鏈接器內,對應的函數是_dl_runtime_resolve。

嗯,是不是想到了什么呢。所有動態庫函數在第一次調用時,都是通過XXX@plt -> 公共@plt -> _dl_runtime_resolve調用關系做地址解析和重定位的。

談到這里,其實還有謎底是沒有解開的,以printf函數為例:

_dl_runtime_resolve是怎么知要查找printf函數的

_dl_runtime_resolve找到printf函數地址之后,它怎么知道回填到哪個GOT表項

到底_dl_runtime_resolve是什么時候被寫到GOT表的

前2個問題,只需要一個信息就可以了知道,這個信息就在藏在在函數對應的xxx@plt表中,以printf@plt為例:

printf@plt>:

jmp *0x80496f8

push $0x00

jmp common@plt

第二條指令就是秘密所在,每個xxx@plt的第二條指令push的操作數都是不一樣的,它就相當于函數的id,動態鏈接器通過它就可以知道是要解析哪個函數了。

真有這么神嗎?這不是神,是編譯鏈接器和動態鏈接器故意安排的巧合罷了。

使用readelf -r test命令可以查看test可執行文件中的重定位信息,其中.rel.plt這一段就大有秘密:

$ readelf -r test

....

Relocation section '.rel.plt' at offset 0x25c contains 3 entries:

Offset Info Type Sym.Value Sym. Name

080496f8 00000107 R_386_JUMP_SLOT 00000000 puts

080496fc 00000207 R_386_JUMP_SLOT 00000000 __gmon_start__

08049700 00000407 R_386_JUMP_SLOT 000000000 __libc_start_main

再看看各函數plt指令中的push操作數:

printf對應push 0x0

gmon_start對應push 0x8

__libc_start_main對應push 0x10

這3個push操作數剛好對應3個函數在.rel.plt段的偏移量。在_dl_runtime_resolve函數內,根據這個offset和.rel.plt段的信息,就知道要解析的函數。再看看.rel.plt最左邊的offset字段,它就是GOT表項的地址,也即_dl_runtime_resolve做完符號解析之后,重定位回寫的空間。

第三個問題:到底_dl_runtime_resolve是什么時候被寫到GOT表的。

答案很簡單,可執行文件在Linux內核通過exeve裝載完成之后,不直接執行,而是先跳到動態鏈接器(ld-linux-XXX)執行。在ld-linux-XXX里將_dl_runtime_resolve地址寫到GOT表項內。

事實上,不單單是預先寫_dl_runtime_resolve地址到GOT表項中,在i386架構下,除了每個函數占用一個GOT表項外,GOT表項還保留了3個公共表項,也即got的前3項,分別保存:

got[0]: 本ELF動態段(.dynamic段)的裝載地址

got[1]:本ELF的link_map數據結構描述符地址

got[2]:_dl_runtime_resolve函數的地址

動態鏈接器在加載完ELF之后,都會將這3地址寫到GOT表的前3項。

其實上述公共的plt指令里面,還有一個操作數是沒有分析的,其實它就是got[1](本ELF的link_map)地址,因為只有link_map結構,結合.rel.plt段的偏移量,才能真正找到該elf的.rel.plt表項。

有興趣的讀者可以使用gdb,在執行到main函數時,將GOT表的這3項數據看一下,驗證一下。

好了,談到這里是否對PLT和GOT機制有個更清晰認識了呢?最后一篇會使用圖文結構將整個PLT/GOT機制串起來。

總結

以上是生活随笔為你收集整理的linux got分析,聊聊Linux动态链接中的PLT和GOT(3)——公共GOT表项的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。