天天看點

重學計算機組成原理(九)- 動态連結(上)1 連結可以分動、靜,共享運作省記憶體2 位址無關很重要,相對位址解煩惱

重學計算機組成原理(九)- 動态連結(上)1 連結可以分動、靜,共享運作省記憶體2 位址無關很重要,相對位址解煩惱

把對應的不同檔案内的代碼段,合并到一起,成為最後的可執行檔案

連結的方式,讓我們在寫代碼的時候做到了“複用”。

同樣的功能代碼隻要寫一次,然後提供給很多不同的程式進行連結就行了。

“連結”其實有點兒像我們日常生活中的标準化、子產品化生産。

有一個可以生産标準螺帽的生産線,就可生産很多不同的螺帽。

隻要需要螺帽,都可以通過連結的方式,去複制一個出來,放到需要的地方

但是,如果我們有很多個程式都要通過裝載器裝載到記憶體裡面,那裡面連結好的同樣的功能代碼,也都需要再裝載一遍,再占一遍記憶體空間。

這就好比,假設每個人都有騎自行車的需要,那我們給每個人都生産一輛自行車帶在身邊,固然大家都有自行車用了,但是馬路上肯定會特别擁擠。

重學計算機組成原理(九)- 動态連結(上)1 連結可以分動、靜,共享運作省記憶體2 位址無關很重要,相對位址解煩惱

1 連結可以分動、靜,共享運作省記憶體

我們上一節解決程式裝載到記憶體的時候,講了很多方法。說起來,最根本的問題其實就是記憶體空間不夠用。

如果能夠讓同樣功能的代碼,在不同的程式裡面,不需要各占一份記憶體空間,那該有多好啊!

就好比,現在馬路上的共享單車,我們并不需要給每個人都造一輛自行車,隻要馬路上有這些單車,誰需要的時候,直接通過手機掃碼,都可以解鎖騎行。

這個思路就引入一種新的連結方法,叫作動态連結(Dynamic Link)

相應的,我們之前說的合并代碼段的方法,就是靜态連結(Static Link)

在動态連結的過程中,我們想要“連結”的,不是存儲在硬碟上的目标檔案代碼,而是加載到記憶體中的共享庫(Shared Libraries)

這個加載到記憶體中的共享庫會被很多個程式的指令調用到。

  • 在Windows下,這些共享庫檔案就是.dll檔案,也就是Dynamic-Link Libary(DLL,動态連結庫)

    用了“動态連結”的意思

  • 在Linux下,這些共享庫檔案就是.so檔案,也就是Shared Object(一般我們也稱之為動态連結庫)。

    用了“共享”的意思

正好覆寫了兩方面的含義。

重學計算機組成原理(九)- 動态連結(上)1 連結可以分動、靜,共享運作省記憶體2 位址無關很重要,相對位址解煩惱

2 位址無關很重要,相對位址解煩惱

要在程式運作的時候共享代碼,這些機器碼必須“位址無關”

也就是說,我們編譯出來的共享庫檔案的指令代碼,是位址無關碼(Position-Independent Code)

換句話說就是,這段代碼,無論加載在哪個記憶體位址,都能夠正常執行

如果還不明白,我給你舉一個生活中的例子

如果我們有一個騎自行車的程式,要“前進500米,左轉進入天安門廣場,再前進500米”。

它在500米之後要到天安門廣場了,這就是位址相關的。

如果程式是“前進500米,左轉,再前進500米”,無論你在哪裡都可以騎車走這1000米,沒有具體地點的限制,這就是位址無關的。

大部分函數庫其實都可以做到位址無關,因為它們都接受特定的輸入,進行确定的操作,然後給出傳回結果就好了。

無論是實作一個向量加法,還是實作一個列印的函數,這些代碼邏輯和輸入的資料在記憶體裡面的位置并不重要。

而常見的位址相關的代碼,比如絕對位址代碼(Absolute Code)、利用重定位表的代碼等等,都是位址相關的代碼

回想一下我們之前講過的重定位表。在程式連結的時候,我們就把函數調用後要跳轉通路的位址确定下來了,這意味着,如果這個函數加載到一個不同的記憶體位址,跳轉就會失敗。

重學計算機組成原理(九)- 動态連結(上)1 連結可以分動、靜,共享運作省記憶體2 位址無關很重要,相對位址解煩惱

對于所有動态連結共享庫的程式來講,雖然我們的共享庫用的都是同一段實體記憶體位址,但是在不同的應用程式裡,它所在的虛拟記憶體位址是不同的。

沒辦法、也不應該要求動态連結同一個共享庫的不同程式,必須把這個共享庫所使用的虛拟記憶體位址變成一緻。

如果這樣的話,我們寫的程式就必須明确地知道内部的記憶體位址配置設定。

那麼問題來了,我們要怎麼樣才能做到,動态共享庫編譯出來的代碼指令,都是位址無關碼呢?

動态代碼庫内部的變量和函數調用都很容易解決,我們隻需要使用相對位址(Relative Address)

各種指令中使用到的記憶體位址,給出的不是一個絕對的位址空間,而是一個相對于目前指令偏移量的記憶體位址

因為 整個共享庫是放在一段連續的虛拟記憶體位址中的,無論裝載到哪一段位址,不同指令之間的相對位址都是不變的。

繼續閱讀