歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> so文件動態替換方法及Linux動態庫的用法

so文件動態替換方法及Linux動態庫的用法

日期:2017/2/28 16:24:08   编辑:Linux教程

在替換so文件時,如果在不停程序的情況下,直接用 cp new.so old.so 的方式替換程序使用的動態庫文件會導致正在運行中的程序崩潰。解決的辦法是采用“rm+cp” 或“mv+cp” 來替代直接“cp” 的操作方法。linux系統的動態庫有兩種使用方法:運行時動態鏈接庫,動態加載庫並在程序控制之下使用。

1、為什麼在不停程序的情況下,直接用 cp 命令替換程序使用的 so 文件,會使程序崩潰?

很多同學在工作中遇到過這樣一個問題,在替換 so 文件時,如果在不停程序的情況下,直接用cp new.so old.so的方式替換程序使用的動態庫文件會導致正在運行中的程序崩潰,退出。這與 cp 命令的實現有關,cp 並不改變目標文件的 inode,cp 的目標文件會繼承被覆蓋文件的屬性而非源文件。實際上它是這樣實現的:

strace cp libnew.so libold.so 2>&1 |grep open.*lib.*.so

open("libnew.so", O_RDONLY|O_LARGEFILE) = 3

open("libold.so", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4

在 cp 使用“O_WRONLY|O_TRUNC” 打開目標文件時,原 so 文件的鏡像被意外的破壞了。www.linuxidc.com這樣動態鏈接器 ld.so 不能訪問到 so 文件中的函數入口。從而導致 Segmentation fault,程序崩潰。ld.so 加載 so 文件及“再定位”的機制比較復雜,詳情可參見參考文獻2。

2、怎樣在不停止程序的情況下替換so文件,並且保證程序不會崩潰?

答案是采用“rm+cp” 或“mv+cp” 來替代直接“cp” 的操作方法。

在用新的so文件 libnew.so 替換舊的so文件 libold.so 時,如果采用如下方法:

rm libold.so

cp libnew.so libold.so

采用這種方法,目標文件 libold.so 的 inode 其實已經改變了,原來的 libold.so 文件雖然不能用 ”ls”查看到,但其 inode 並沒有被真正刪除,直到內核釋放對它的引用。同理,mv只是改變了文件名,其 inode 不變,新文件使用了新的 inode。這樣動態鏈接器 ld.so 仍然使用原來文件的 inode 訪問舊的 so 文件。因而程序依然能正常運行。

到這裡,我們回想在上線操作中在替換可執行程序時,為什麼直接使用“cp new old”這樣的命令時,系統會禁止這樣的操作,並且給出這樣的提示“cp: cannot create regular file `old': Text file busy”。這時,我們采用的辦法仍然是用“rm+cp”或者“mv+cp”來替代直接“cp”,這跟以上提到的so文件的替換有同樣的道理。

但是,為什麼系統會阻止 cp 覆蓋可執行程序,而不阻止覆蓋 so 文件呢?這是因為 Linux 有個 Demand Paging 機制,所謂“Demand Paging”,簡單的說,就是系統為了節約物理內存開銷,並不會程序運行時就將所有頁(page)都加載到內存中,而只有在系統有訪問需求時才將其加載。

“Demand Paging”要求正在運行中的程序鏡像(注意,並非文件本身)不被意外修改,因此內核在啟動程序後會鎖定這個程序鏡像的 inode。對於 so 文件,它是靠 ld.so 加載的,而ld.so畢竟也是用戶態程序,沒有權利去鎖定inode,也不應與內核的文件系統底層實現耦合。

Copyright © Linux教程網 All Rights Reserved