這個概念其實很好理解。對於一個可重定位目標文件,裏面一定有很多需要重定位的符號。這些符號需要在靜態鏈接器進行鏈接的時候回填絕對的虛擬內存地址。這種叫做位置有關代碼。
而位置無關代碼的意思是,在動態鏈接階段(這個階段可以發生在裝載時也可以發生在運行時)無需回填具體的代碼段,而是只需要回填全局偏移量表(GOT)與過程鏈接表(PLT)即可。
位置無關代碼與位置有關代碼的根本區別在於:
鏈接階段是否需要修改具體的代碼段中的符號地址。在靜態鏈接中需要回填,而在動態鏈接中藉助GOT與PLT很好的規避了對代碼段的修改。
具體來說,分爲對變量的引用與對函數的引用。
1.對變量的引用
動態鏈接階段只用將具體的虛擬地址回填到GOT[3]條目即可,無需修改代碼段
2.對函數的引用
如果用僞代碼來表示,我個人覺得可以寫成下面的代碼
static void* func;
void real_func()
{
....
}
void load_linker()
{
......
func = real_func(); // 3
......
}
void init()
{
load_linker(); // 2
}
func = init(); // 1
void call_func()
{
func();
}
這種惰性加載是不是很熟悉?第一次加載的時候,代碼實際上是加載了動態鏈接器給共享代碼分配虛擬內存地址並回填到GOT表,好了,之後所有的訪問都是直接跳轉到真正的函數地址。