複製鏈接
請複製以下鏈接發送給好友

地址無關代碼

鎖定
在計算機領域中,地址無關代碼 (position-independent code,PIC),又稱地址無關可執行文件 (position-independent executable,PIE) ,是指可在主存儲器中任意位置正確地運行,而不受其絕對地址影響的一種機器碼。PIC廣泛使用於共享庫,使得同一個庫中的代碼能夠被加載到不同進程的地址空間中。PIC還用於缺少內存管理單元的計算機系統中,使得操作系統能夠在單一的地址空間中將不同的運行程序隔離開來。
中文名
地址無關代碼
外文名
position-independent code
別    名
址無關可執行文件
學    科
計算機科學
定    義
代碼可在內存任意位置正確地運行
應    用
共享庫

地址無關代碼定義

地址無關代碼(PIC)是指運行和放置地址無關的代碼。 其實這裏PIC是一個相對意思,因為生成代碼或多或少都使用了位置無關代碼,該實現的基本思想是:把指令中需要修改的部分分離出來,跟數據部分放在一起,這樣指令部分就可以保持不變,而數據部分則在每個進程擁有一個副本。地址無關代碼能夠在不做修改的情況下被複制到內存中的任意位置。這一點不同於重定位代碼,因為重定位代碼需要經過鏈接器或加載器的特殊處理才能確定合適的運行時內存地址。 地址無關代碼需要在源代碼級別遵循一套特定的語義,並且需要編譯器的支持。那些引用了絕對內存地址的指令(比如絕對跳轉指令)必須被替換為PC相對尋址指令。這些間接處理過程可能導致PIC的運行效率下降,但是大多數處理器對PIC都有很好的支持,使得這效率上的這一點點下降基本可以忽略。

地址無關代碼動態庫

動態庫又稱動態鏈接庫英文為DLL,是Dynamic Link Library 的縮寫形式,DLL是一個包含可由多個程序同時使用的代碼和數據的庫,DLL不是可執行文件。動態鏈接提供了一種方法,使進程可以調用不屬於其可執行代碼的函數。動態鏈接庫和動態鏈接是重要的軟件運行機制,它既是多個進程共享資源的主要方式,也是操作系統嚮應用程序提供系統服務的主要手段。動態鏈接主要有2個特點:動態的加載,當運行模塊在需要的時候才將動態鏈接庫加載映射入運行模塊的虛擬地址空間;動態的解析,只有當要調用的函數被調用的時候,才會把這個函數在虛擬內存空間的起始地址解析出來。除了資源共享這個最基本的目的之外,利用動態鏈接機制還可實現共享庫重定向等重要應用。動態庫一般存放系統運行過程中所產生的所有信息、原始數據、用户輸入的信息、推理的中間結果以及推理過程的紀錄 [1] 
例如Linux下的動態鏈接庫文件是ELF格式的。Linux的動態鏈接實現機制引入了全局偏移 表和過程鏈接表,實現了位置無關代碼(PIC)。同時,ELF文件的分層管理模型在Linux 動態鏈接機制中也起着重要的作用。ELF 格式的共享庫使用 PIC 技術使代碼和數據的引用與地址無關,程序可以被加載到地址空間的任意位置。PIC 在代碼中的跳轉和分支指令不使用絕對地址。PIC 在 ELF 可執行映像的數據段中建立一個存放所有全局變量指針的全局偏移量表。

地址無關代碼引用問題

與地址無關的代碼,也就是需要考慮代碼中會對地址進行引用的情況,共享對象(GCC中的動態鏈接文件)中地址引用可以分為以下幾種情況:模塊內函數調用、跳轉等、模塊內數據的訪問,如模塊內定義的靜態變量,全局變量等、模塊外部的函數調用、跳轉等和模塊外部的數據的訪問,比如別的模塊定義的全局變量。
模塊(動態鏈接文件)內部的函數的調用:由於此時調用者與被調者都是位於同一個模塊,所以調用者與被調者之間的相對位置是固定的,因此,對被調者的調用就可以使用相對地址來替代絕對地址,對於這種指令就是不需要重定位的。
模塊內部的數據調用:與上面分析同理,由於數據定義與引用指令是位於同一個模塊的,因此它們之間的相對位置是固定的。但是此時有一些區別,現代體系結構中,數據的相對尋址沒有基於當前指令的尋址方式,因此ELF採用了一個巧妙的方法來獲取當前PC(程序計數器)的值,再在該基礎上添加一個偏移,即可訪問到變量。
模塊外部的函數的調用:此時對外部符號的引用顯然是與地址有關的,按照先前説的基本思想,此時需要將與地址相關的部分放到數據段裏。ELF 的做法是在數據段中建立一個指向這些函數的指針數組,也即是全局偏移表(GOT,Global Offset Tabel),當代碼需要引用這些外部函數時,則可以通過GOT 中的相對應的項間接引用。動態鏈接器在裝載模塊的時候會查找每個函數所在地址,並填充GOT中的各個表項,以保證每個指針均指向正確的地址。同時由於GOT本身是放在數據段的,因此它可以在模塊裝載的時候被修改,並且每個進程都可有自己的副本。
模塊外部的數據的調用:該方法與模塊外部的函數訪問方法相同,同樣引入 GOT ,只是此時GOT 的表項中存儲的是變量的地址。

地址無關代碼機器語言

機器語言(machine language)是一種指令集的體系。這種指令集稱為機器碼(machine code),是計算機的CPU可直接解讀的數據。機器碼有時也被稱為原生碼(Native Code),這個名詞比較強調某種編程語言或庫與運行平台相關的部分。
機器語言是用二進制代碼表示的計算機能直接識別和執行的一種機器指令的集合。它是計算機的設計者通過計算機的硬件結構賦予計算機的操作功能。機器語言具有靈活、直接執行和速度快等特點。不同種類的計算機其機器語言是不相通的,按某種計算機的機器指令編制的程序不能在另一種計算機上執行。
要用機器語言編寫程序,編程人員需首先熟記所用計算機的全部指令代碼和代碼的涵義。手編程序時,程序員要自己處理每條指令和每一數據的存儲分配和輸入輸出,還需記住編程過程中每步所使用的工作單元處在何種狀態。這是一件十分繁瑣的工作,編寫程序花費的時間往往是實際運行時間的幾十倍或幾百倍。而且,這樣編寫出的程序完全是0與1的指令代碼,可讀性差且容易出錯。在現今,除了計算機生產廠家的專業人員外,絕大多數程序員已經不再學習機器語言。
參考資料
  • 1.    張和君,張躍.Linux動態鏈接機制研究及應用[J].計算機工程,2006(22):64-66.