linux核心介面 Linux二進位制相容性問題

2021-07-25 13:02:35 字數 2569 閱讀 4127

linux上二進位制有乙個顯著的特點就是可移植性不強。我們在不同的發行版之間,不同的核心版本之間,程式往往是不能通用的。

硬體平台

眾所周知的,硬體平台不一樣,指令集不一樣,二進位制就幾乎沒有可移植的能力。

在架構上,必須要區分x86和

x64兩種架構,一般的

x64的機器都能執行

x86的程式,但是如果你把程式編譯為

x86,你就得面對大量的

x64伺服器的效能瓶頸。這個架構上的區別在任何的平台上都一樣的,並不是

linux

的特有問題。

而abi的不同則是

linux

核心和glibc

的公升級導致的規範變化導致的。不同的

abi程式和庫在不同的環境下很高概率是不能執行的,除非是低版本最原始的

abi在現代系統上跑一般都可以向下相容。而這種不相容主要發生在

c++身上,因為

c++近幾年的特性改變速度相對較快,管理困難。

x86上常見的

elf abi

有:os/abi:                            unix - linux

os/abi:                            unix - system v

os/abi:                            unix - gnu

其中gnu和

linux

兩種是相同的,只是使用不同版本的

readelf

會現實不同的結果。而

system v

則是最古老的,也是相容性最好的。有的老一些的系統上只識別

system v

的abi

。但是system v abi for x86_64卻是比linux還要先進的abi。因為這個abi把大部分的引數轉由暫存器傳遞,而不是由棧傳遞,對棧的使用減少就增加了以往的快取溢位的難度。還有x32上的return to libc等攻擊的手法也得變通,難度提高。

乙個elf支援被編譯成各種大小端,我們不能用編譯成大端的

elf在小端的核心上執行。但是考慮到

intel

的cpu

全部是小端,所以我們在

intel

平台上編譯部署不需要過多的考慮這個問題

gcc在編譯的時候可以使用

--enable-kernel

指定最低支援的核心版本,這個選項會在

elf頭部新增

.note.abi-tag

,如果你用

readelf

讀取頭部,會發現:

這裡面就是規定的最低支援的核心版本,執行時會直接檢查這個與當前核心版本之間的區別,不滿足就會fatal: kernel too old。這種不相容你也可以通過

file

命令發現,這個命令會輸出二進位制的最小相容的版本。有的庫也攜帶著這個限制,有的則沒有,你的程序所依賴的任何乙個庫滿足了這個限制都會導致執行不成功。

gcc傾向於動態編譯和動態載入,

golang

就是吐槽這一點的生動代表。但是動態編譯攜帶庫確實能減小大工程結果檔案大小,而且這是

linux

系統的傳統價值觀。所以在很多地方還是有必要性的。

而各個系統所有的庫的版本不一樣,很多庫的呼叫名的symbol都會在後面追加版本號,如果版本號不匹配,庫則不能通用,例如我們經常見到

libc.so.6: version `glibc_2.14' not found

這類的列印。

strings /lib64/libc.so.6 |grep glibc_  

通過這個命令可以排查,大部分的庫問題根源都在

libc

,但是不是絕對的。

libgcc_s.so.1

是gcc

的元件,編譯時候執行時候都需要,乙個版本

gcc編譯的程式常常不能在裝有另乙個版本

gcc的平台上執行,就是這個原因,所以從高到低版本的遷移需要帶著它。

libc.so.6

是最底層的庫,作業系統和其中所有應用程式幾乎都依賴,是應用程式能夠跟作業系統通訊的基礎。原本

unix

中的libc

和gnu

開發的第三方版本

glibc

,像這裡的名字雖然是

libc

,但事實上就是

glibc

,功能沒有太大差別。

libm.so.6

則是對libc

裡面的數學部分優化後的版本。

另外乙個需要注意的地方是連線的時候不需要指定後面的版本號,因為系統一般會建立到這個版本號的軟鏈結,現代的gcc即使在連線的時候不指定版本號,並且不存在軟連線,他也能正確的找到完整名字的庫檔案,實際的鏈結的是帶版本號的庫,所以即使你在編譯的時候使用了不帶庫版本號的動態庫,使用時還是需要攜帶帶版本號的庫檔案。

gcc的

5.1版本的編譯器會在編譯時做大量激進的優化,但是有的優化是只對於最新的

cpu特性有效,老一些的

cpu在硬體層面就不支援這些優化,所以如此編譯的程式就有相容性問題。方法是用更老的編譯器或者是用

5.2之後解決了這個問題的更新的編譯器。

Linux核心模組(二)

ko kernel object so shared object root rhel6 ls lib modules uname r kernel arch x86 kvm kvm amd.ko kvm intel.ko kvm.ko 通過移除核心模組可達到禁用該模組的作用 root rhel6 ...

Linux核心分析 實驗二

該實驗要求完成乙個簡單的時間片輪轉多道程式核心 首先我們看看mykernel裡面的mypcb.h define max task num 10 max num of task in system define kernel stack size 1024 8struct thread typedef...

Linux核心list head學習(二)

前一篇文章討論了list head 結構的基本結構和實現原理,本文主要介紹一下例項 自己如果想在應用程式中使用list head 的相應操作 當然應該沒人使用了,c stl提供了list 用起來貌似更方便 在應用程式中需要包含自己的 list.h 標頭檔案 注 這個list.h 是為了配合示例程式而...