最近處理乙個問題,需要在ubuntu下使用gcc編譯出多個平台版本做驗證,發現對交叉編譯這塊有點模糊。導致工作效率略受影響,因此打算學習一下。
交叉編譯器(cross compiler)就是乙個可以編譯在別的平台執行的程式的編譯器。例如在windows上編譯安卓apk的編譯器就是交叉編譯器。
在交叉編譯中,通常將編譯可執行檔案或者庫檔案的機器稱之為構建平台,而將這些可執行檔案或者庫檔案執行的平台稱為宿主平台。
導致交叉編譯器出現主要有一下幾個原因:
某些裝置資源有限無法執行編譯器,例如8051微控制器,顯然不能指望它自己編譯程式,它的資源有限到甚至系統都沒有;
需要對一套**編譯出在不同平台執行的版本,比如你想讓你的程式可以執行在windows,ubuntu,mac等不同系統,又不想在每一種上配置一遍編譯環境;
可以多台機器聯合編譯,提高效率;
為剛出現的機器編譯它的系統和編譯器等。
交叉編譯器,並不是僅僅只有乙個編譯器,他還涉及鏈結器、偵錯程式、標準庫等等,這些統稱為工具鏈。
在gnu中,對交叉編譯器的命名有乙個非強制的約定,交叉編譯器的命名形式為:name-arch-[vendor]-os-[abi] (os = system / kernel-system)
,例如gcc-arm-linux-gnueabi
就是編譯的目標平台是基於amr晶元的linux上,由於這個名字只是個約定,因此並不是大家都遵守。可能順序上有些不同,例如可能vendorh會在arch之前。但是一般情況都會把目標平台的架構、系統以及abi等表示清楚。
因此交叉編譯其實要做的就是找到對應的交叉編譯器,最常用的就是確定目標平台的硬體和系統,如果是比較主流的硬體和軟體產品例如樹梅派,一般廠商都會有提供。特別是基於gcc的交叉的交叉編譯器,例如上面提到的gcc-arm-linux-gnueabi
,其實使用上和gcc沒什麼特別的,主要就是它們預設指向的標頭檔案路徑和生成的二進位制檔案不同而已。
此外,說到交叉編譯,乙個必不可少的知識就是abi。
定義了函式呼叫標準,這是最核心的一套規則,它規定了如何將你呼叫乙個函式這一行**翻譯成機器**;
指導如何表示乙個需要暴露的函式,也稱之為「改名(name mingling)」;
定義可以數用那些資料型別,以及它們在記憶體中的布局。每種資料型別占用多少個位元組,資料是大端格式還是小端,等等。這些都需要乙個標準,不然不用說不同語言之間相互不能互動,就連同一種語言不同編譯器編譯出來的二進位制都可能不同。
堆疊的結構和行為方式等多個方面,比如棧向上還是向下生長等等。
我們知道api是別的(當然也可以是編寫者自己)程式設計師使用的。abi的使用者主要就是編譯器了,一般的程式設計師不可能也沒必要參與到abi的定製和直接使用abi。因此一般人沒必要了解abi的細節。文末附有因特爾 nios® ii 處理器的abi標準,感興趣可以了解一下。這裡只簡單說一下abi中的程式呼叫,對abi有個具體的了解。
如果學過彙編,就很容易理解這個函式呼叫標準是什麼,畢竟我們一般接觸最底層的應該是彙編了,直接寫機器指令的我相信有,但是我是沒機會見過了。在彙編中,我們呼叫乙個函式,主要做下面幾個事情:
儲存現場。計算單元所擁有的暫存器畢竟有限,所以我們要將目前正在執行的命令的位址、暫存器的資料儲存起來,使得當從呼叫的函式返回後,cpu 還能正常工作;
設定呼叫函式所需要的引數;
cpu 調轉到函式所在位址繼續執行;
程式結束後將需要返回給呼叫者的資料儲存、清理;
恢復現場;
cpu 繼續執行。
我們用高階語言編寫的程式,編譯器最終會幫我們翻譯成彙編**,最終翻譯成機器**。
感覺大家基本都這麼做的。如果所有人原本就這麼做,那何必多此一舉定乙個標準?因為上面提到的這幾不還很模糊,不具備可操作性。例如,儲存現場,是儲存在**?引數傳遞是通過特殊暫存器傳遞還是通過棧傳遞?返回值也類似?函式呼叫完成後誰負責做清理工作,呼叫者自己清理還是特定人員去清理?這裡的每一條都要說的清清楚楚明明白白。然後編譯器按照對應平台所設定的標準去生成正確的函式呼叫的彙編**。
當然,上面值是簡單說明了乙個程式內部的函式呼叫的彙編**生成,其實還有呼叫外部函式庫的函式的詳細步驟,也需要一一枚舉出來,編譯器和鏈結器才能正確知道如何找到和呼叫它們。
除了abi,還有乙個eabi。其中的e 表示embedded,是用於嵌入式系統的abi,主要目的是提公升系嵌入式系統的效能。eabi和abi的主要區別是eabi去掉了使用者**和系統核心之間的抽象,可以讓使用者**直接訪問硬體,提高了效能。
[1]
[2]
[3] how to survive embedded linux: how to compile
[2] n2cpu_nii51016.pdf
交叉編譯工具簡介
前言 交叉編譯,即在一種平台上編譯,並能夠執行在另一種體系結構完全不同的平台上。交叉編譯使用的工具,一般稱為交叉編譯工具,由於它是由多個程式構成,所以又稱為交叉編譯工具鏈。交叉開發工具鏈就是為了編譯 鏈結 處理和除錯跨平台體系結構的程式 每次執行工具鏈軟體時,通過帶有不同的引數,可以實現編譯 鏈結 ...
編譯和交叉編譯curl
root kwt virtual machine home kwt tar vxf curl 7.69 1.tar.gz 進入curl 7.69.1目錄 進入curl 7.69 1目錄 執行.configure命令生成makefile root kwt virtual machine home kw...
交叉編譯和交叉工具鏈(一)
一 交叉編譯簡介 1 什麼是交叉編譯 1.1 本地編譯 解釋什麼是交叉編譯之前,先要明白乙個概念 本地編譯 我們之前常見的軟體開發,都是屬於本地編譯 在當前的pc下,x86的cpu下,直接編譯出來程式,可以執行的程式 或者庫檔案 其可以直接在當前的環境,即x86的cpu下,當前電腦中,執行。此時的編...