Linux動態連結之二:優化加速之延遲繫結PLT
動態連結速度損耗主要兩方面:
1.對全域性和靜態的資料訪問都要進行復雜的GOT定位,然後再間接跳轉定址;
2.動態連結的很多工作是在程式執行時完成的,動態連結器需尋找並裝載目標共享物件、符號查詢、地址重定位等,如果不加以優化,會出現程式啟動過慢的情況。
故而需要出臺一些優化動態連結策略的方法。
動態連結下,模組之間包含大量的函式引用(全域性變數往往較少,過多的全域性變數會導致模組間的耦合度很大,不符合軟體編輯規範,參考豐田車載軟體系統功能失效事件)。
動態連結會耗費不少時間解決模組之間的函式引用的符號查詢及重定位(GOT表填充和更新),但是其實程式執行過程中,可能很多函式時用不到的(比如C++程式設計#include <stdlib.h>
printf()
),比如一些錯誤處理函式或者一些使用者很少用到的功能模組等,延遲繫結的核心思想是函式第一次被用到時才進行繫結,這種做法可以大大加速程式的啟動速度,特別有利於一些有大量函式引用和大量模組的軟體。
ELF針對延遲繫結,採用的是PLT(procedure linkage table)機制來實現,這種方法使用了很多精巧的指令序列來完成。在Linux中,動態連結在掃描可執行檔案時,一旦掃描到外部函式的引用,則glibc會啟用繫結函式_dl_runtime_resolve(module, function)
來確定模組module中的function函式的在GOT的填充工作。(舉個例子,liba.so需要呼叫libc.so中的bar()函式,那麼當liba.so第一次呼叫bar()時,需要呼叫_dl_runtime_resolve
延遲繫結PLT(Procedure Linkage Table)在GOT表基礎又做了一次間接跳轉。即模組內關於外部函式的地址引用,這下並不直接通過GOT跳轉,而是通過一個叫做PLT項的結構來進行,每個外部函式引用都對應PLT表中的一個表項,比如
bar()
函式在PLT表中的表項稱為[email protected]
,實現如下:
bar@plt:
jmp *(bar@GOT)
push n
push moduleID
jump _dl_runtime_resolve
可以看到
表項採用了類似於樁程式碼的格式。[email protected]
第一指令中[email protected]
指向GOT表中函式bar()
對應項地址,如果GOT表中關於bar()
的地址已經被填充非空,則顯然將會直接跳轉到GOT表給出的bar()
函式地址,實現正常的函式呼叫。
但所謂延遲繫結,即是指在初始未遇到bar()
函式之前,GOT表中並無函式bar()
的地址資訊,而是將後續push n
指令的地址填充到GOT中bar()
表項中,這時jmp指令將會直接跳轉繼續執行後續的push n...
等指令,該步操作很簡單也不需要遍歷定址目標符號,故而代價很低,只需要在生成樁程式碼時將push n
指令位置填入即可。而後的操作便是正常引數壓棧工作,其中push n
中的引數n對應的是bar()
函式符號在重定位表.rel.plt中的下標,push moduleID
中的moduleID則是模組ID,呼叫_dl_runtime_resolve
函式完成具體的符號解析和重定位工作,將外部模組中bar()
函式的真正地址填入GOT對應的[email protected]
表項。這樣當我們下次再次回到PLT表[email protected]
表項中轉時,便會進入正常的函式呼叫過程,而不會繼續執行push n
及之後的程式碼,那段程式碼只會在符號未被解析時執行only一次。
上述是PLT的原理,而PLT機制的具體實現則複雜得多。ELF將GOT表分成全域性變數專用表”.got”和函式引用專用子表”.got.plt”,所有外部函式的引用中轉全部被集中到”.got.plt”子表中(前面提到過每個共享模組都有自己的一份GOT表,通過推出GOT表來實現程式碼段的地址無關性,而將地址相關性轉移到GOT表上,這也是為啥GOT表示放在.data段中的原因)。關於”.got.plt”子表需要注意的是它的前三項:第一項為”.dynamic”段地址,第二項為本模組的ID,第三項儲存的是_dl_runtime_resolve()地址。
其中第二項和第三項由動態連結器在裝載共享模組的時候負責初始化。 PLT每項規定16個位元組,剛好可以放3條指令,如下:
bar@plt:
jmp *(bar@GOT)
push n
jmp PLT0
其中函式PLT0是通用的的,形式如下:
PLT0:
push *(GOT+4)
jmp *(GOT+8)
對照圖片可以看到,moduleID是方便_dl_runtime_resolve()
找到目標模組的”.got.plt”函式地址子表,而n則對應要修正函式的表項下標。這樣便實現了一個利用樁程式碼完成的PLT延遲繫結操作。
相關推薦
Linux動態連結之二:優化加速之延遲繫結PLT
1. PLT延遲繫結的提出 動態連結速度損耗主要兩方面: 1.對全域性和靜態的資料訪問都要進行復雜的GOT定位,然後再間接跳轉定址; 2.動態連結的很多工作是在程式執行時完成的,動態連結器需尋找並裝載目標共享物件、符號查詢、地址重定位等,如果不加以優化,會
C#進階系列——動態Lamada(二:優化)
前言:前幾天寫了一篇動態Lamada的文章C#進階系列——動態Lamada,受園友的啟發,今天打算來重新優化下這個動態Lamada的工具類。在此做個筆記,以免以後忘了。 一、原理分析 上篇裡面我們說了動態Lamada的使用必要性以及使用場景,但是感覺用在專案裡面還不太方便,最難用的就是需要傳遞屬性名稱的字
Directx3D9學習之二:Windows程式設計之最簡單視窗程式
Window style 視窗的風格,定義了一些視窗外觀和表現的標誌組合,WS_OVERLAPPEDWINDO是幾個標誌結合的位或,包含最小化,最大化按鈕,邊框,標題欄等等 第五個引數: Size and position 位置和大小 CW_USEDEFAULT 使用預設值 第六個引數: Parent
linux學習之二:日常的基礎命令收集
幫助文檔 gedit 查看 日期 取整 style 位置 某月 linux 1、 ls 2、pwd 顯示當前目錄所在位置 3、date 日期時間 4、cal 日歷 默認顯示當前該月 cal 2012 :查看2012年的日歷 cal 月 年 : 查看某年某月
【2017-07-01】Linux應用開發工程師面試問題記錄之二:關於結構體的大小及內存對齊問題
偶數 而且 strong span net 但是 開發 f11 flag Tencent後臺服務器開發有一道題是計算一個結構體的sizeof的大小: struct strData { int m_Int; char m_Char; short m_Short; char
Linux時間子系統之二:Alarm Timer
數據 類型 oid mtime orm 分別是 type mon 超時 一、前言 嚴格來講Alarm Timer也算POSIX Timer一部分,包含兩種類型CLOCK_REALTIME_ALARM和CLOCK_BOOTTIME_ALARM。分別是在CLOCK_REALTI
Linux運維學習筆記之二:常用命令2
linux 運維 筆記71、passwd:修改用戶密碼語法passwd [參數]username選項-k --keep-tokens :保留即將過期的用戶在期滿後仍能使用-l --lock :鎖定用戶無權更改其密碼,只能root才能操作-u --unlock :解除鎖定-S --status :查看用戶狀
linux學習之二:Linux磁盤與文件管理系統
roo 針對 mkf 維護 def 都是 linu mke2fs remount 上次寫了Linux檔案與操作,這次繼續寫Linux磁盤與文件管理系統。 首先,我們要先來認識一下EXT2文件系統,這是Linux最傳統的磁盤系統。 1.EXT2文件系統 在說文件系統以前還是要
.Neter玩轉Linux系列之二:Linux下的文件目錄及文件目錄的權限
pac linux 在那 用戶 目錄結構 重要 bsp 樹狀 hub 一、Linux下的文件目錄 簡介:linux的文件系統是采用級層式的樹狀目錄結構,在此 結構中的最上層是根目錄“/”,然後在此目錄下再創建 其他的目錄。深刻理解linux文件目錄是
搭建Linux-java web運行環境之二:安裝mysql
navi sql glibc x86 卸載 系統服務 依賴 host mys 環境 OS:Red Hat Enterprise Linux Server release 7.3 (Maipo) JDK:jdk-7u80-linux-x64.tar.gz Tomcat:ap
簡單知識點例項之二:如何動態生成div框並且同時非同步載入資料
一、動態生成框並且同時ajax非同步請求資料 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <htm
LINUX檔案伺服器之二:NFS伺服器
什麼是NFS??? NFS為Network File System的簡稱,它的目的就是讓不同的機器,不同的作業系統可以彼此共享資料。 網路檔案系統 (NFS) 是 Unix 系統和網路附加儲存檔案管理器常用的網路檔案系統 , 允許多個客戶端通過網路共享檔案訪問。它可用於提供對共享二進位制目錄
Linux中斷(interrupt)子系統之二:arch相關的硬體封裝層
Linux的通用中斷子系統的一個設計原則就是把底層的硬體實現儘可能地隱藏起來,使得驅動程式的開發人員不用關注底層的實現,要實現這個目標,核心的開發者們必須把硬體相關的內容剝離出來,然後定義一些列標準的介面供上層訪問,上層的開發人員只要知道這些介面即可完成對中斷的進一步處理和控制。對底層的封裝主要包括
JVM原理及優化之二:記憶體管理
1. 記憶體分配策略: 1. 物件優先在Eden分配 2. 大物件直接進入老年代 3. 長期存活物件將進入老年代(當它的年齡增加到一定程度 (預設為15歲 ),就會被晉升到老年代中 。物件晉升老年代的年齡閾值,可以通過引數 -XX:MaxTenuringThreshold來
Jenkins學習使用之二: Linux節點增加
一、通過Jenkins的“系統管理-->節點管理”,點選“新建節點”,輸入節點名稱,選擇“固定節點”或者“複製現有節點”,然後點選“確定”。 二、在下列頁面中填入必要的資訊: 1、併發構建數:在此節點上可以同時執行的構建job數量,在此預設為1 2
2117資料結構實驗之連結串列二:逆序建立連結串列
#include <stdio.h> #include <stdlib.h> struct node { int data; struct node *next; }*p, *q, *tail; int main() { int
【U3D效能優化教程——CPU篇】之二:靜態批處理&靜態批處理
這篇文章由唐三胖ヾ(•ω•`)o網路整理總結,針對DrawCall概念的系列優化教程。 通過這篇文章,你可以知道 1)動態/靜態批處理的概念 2)什麼時候會動態批
2117 資料結構實驗之連結串列二:逆序建立連結串列
資料結構實驗之連結串列二:逆序建立連結串列 Time Limit: 1000MS Memory Limit: 65536KB Problem Description 輸入整數個數N,再輸入N個整數,
Linux作業系統備份之二:通過tar拷貝分割槽實現Linux操作資料的線上備份
在《Linux作業系統備份之一:使用LVM快照實現Linux作業系統資料的線上備份》文章中,我們介紹了使用LVM快照實現操作性系統線上備份的方法,LVM快照可以實現線上作業系統資料的備份,線上的意思也就是說,不中斷業務的條件下,完成作業系統資料的備份。 今天我們介紹另外一種線上備份Linux作業系統
.Neter玩轉Linux系列之二:Linux下的檔案目錄及檔案目錄的許可權
基礎篇 實戰篇 一、Linux下的檔案目錄 簡介:linux的檔案系統是採用級層式的樹狀目錄結構,在此 結構中的最上層是根目錄“/”,然後在此目錄下再建立 其他的目錄。深刻理解linux檔案目錄是非常重要的,如下圖所示: 將來你用哪個使用者登入,你就會在那個使用