原理概述
【linux】詳解——庫-CSDN博客
共享庫被加載后,系統會為該共享庫創建一個結構,這個結構體中的字段描述了庫的各種屬性。在內存中可能會加載很多庫,每一個庫都用一個結構體描述。把這些結構體用一些數據結構管理起來,系統對庫的管理就轉化成了對數據的管理
系統對加載到內存的共享庫的信息是很清楚的
進程地址空間示意圖
【Linux】進程地址空間-CSDN博客
每個進程都會有自己的地址空間,地址空間中的共享區用來映射共享庫。
CPU在代碼區執行數據時需要用到庫中的方法會根據編譯時就給定的地址跳轉到共享區,共享區的虛擬地址通過頁表的映射找到物理內存中相應的數據,然后加載到CPU運算。
如果虛擬地址在頁表中沒有與對應的物理地址建立映射關系就會發生缺頁中斷,系統會把磁盤中的對應的數據加載到內存,再讓虛擬地址和物理地址建立映射關系,然后這部分數據被CPU調度執行。
多個進程的頁表可能會映射同一個庫,即共享庫可以被多個進程使用。
當一個進程要對庫中定義的全局變量做寫入時,系統會檢查檢查該全局變量的引用計數,若庫是被多個進程共享的,就會發生寫時拷貝。一個進程對共享庫的任何操作都不會影響其他進程。
線性地址,虛擬地址,邏輯地址,進程地址空間,其實是一個概念。采用的是全0到全1的編址,用線性地址來描述這樣的編址方式是一種很形象的叫法。
虛擬地址和進程地址空間是進程層面的叫法,而邏輯地址是可執行程序中的地址分配方式。
編譯器給代碼的編址方式是虛擬地址,CPU執行拿到的地址也是虛擬地址。在CPU中,內置了指令集,能讓CPU完成一些簡單的動作。
比如函數跳轉,拿著該函數的地址跳轉到相應的地址空間,把相應的地址進行頁表映射,拿到物理內存中相應的數據加載到CPU中調度執行。
也就是說從編譯器為代碼分配地址到CPU調度執行的地址都是虛擬地址,如果想拿到具體的數據只需通過虛擬地址在頁表中找到對應的物理地址從而拿到相應的數據。
如果虛擬地址并沒有在頁表中與物理地址建立映射關系,即相應的數據并沒有被加載到內存中,就會發生缺頁中斷,數據會從磁盤加載到內存,然后對應的虛擬地址與物理地址建立映射關系。
動態庫在編譯時會帶上-fPIC選項,該選項表示與位置無關碼。
在編譯庫代碼時,不會按邏輯地址的方式分配。
而是采用偏移量的方式,這樣任意位置的代碼數據可以映射到共享區中的任意位置,只需要知道庫的開始位置被加載到哪里,只需用開始位置的地址加偏移量即可拿到該指令的虛擬地址,然后就是與頁表映射的一系列操作了。