本文內容包括:
編譯器和交叉編譯器的介紹交叉編譯器的命名規則如何交叉編譯C程式碼大端、小端的通俗講解如何判斷你的系統是大端系統還是小端系統要學習linux核心開發,編譯器或者交叉編譯器是繞不過去的坎。
編譯器的作用是把人類容易標識的程式程式碼轉換為機器所理解的機器程式碼,那交叉編譯器呢?
交叉編譯器也是實現類似的功能,只不過,咳咳,此處劃重點:
編譯器生下的孩子(編譯出來的二進位制檔案)是自己的(能在編譯器所在硬體平臺上執行),
而交叉編譯器生下的孩子(編譯出來的二進位制檔案)是別人的(不能在交叉編譯器所在的硬體平臺上執行)。
為什麼會有交叉編譯器一說呢?
因為早期的嵌入式硬體(比如)arm的效能較低,不適合在上面進行程式編譯這種耗費cpu的任務,所以,交叉編譯器應用而生了:我們在pc機上(pc機是x86架構)安裝arm的交叉編譯器,並(在pc機上)編譯出能在arm體系上執行的二進位制程式碼,這就是交叉編譯器所做的事情。
了解這個歷史原因之後,可能會有腦子靈光的童鞋提問:
現在arm的效能已經有了大幅提升,還需要交叉編譯器嗎?
答案是:需要。
有些arm的linux系統中,已經可以使用gcc,可以編譯一些比較上層的應用,但是這是有一個前提的:那就是linux系統已經run起來了。那如果arm的板子連linux核心都沒有,你怎麼使用gcc?另外linux核心是需要提前做好的,如果arm系統都沒有起來,怎麼編譯linux核心? 你只能通過在PC機上進行交叉編譯。
以上就是關於交叉編譯器的作用的介紹,接下來我們看一下交叉編譯器的命名規則。
交叉編譯工具鏈的命名規則一般為:
$arch [-$vendor] -$os [-[gnu][eabi][hf]]-gcc
arch - 體系架構,如arm,mips等,不可省略vendor - 工具鏈提供商,可省略os - 目標作業系統,不可省略eabi - 嵌入式應用二進位制介面(Embedded Application Binary Interface),可選的引數包括:abi: 二進位制應用介面。
eabi: 嵌入式二進位制應用介面,主要針對嵌入式平臺。
gnu: 加gnu表示編譯器使用的是gnu glibc的庫
el:表示使用軟浮點處理單元(softfp)。其實在armel中,關於浮點數計算的約定有三種。以gcc為例,對應的-mfloat-abi引數值有三個:soft,softfp,hard。soft是指所有浮點運算全部在軟體層實現,效率當然不高,會存在不必要的浮點到整數、整數到浮點的轉換,只適合於早期沒有浮點計算單元的ARM處理器;softfp是目前armel的預設設定,它將浮點計算交給FPU處理,但函式引數的傳遞使用通用的整型暫存器而不是FPU暫存器;hard則使用FPU浮點暫存器將函式引數傳遞給FPU處理。需要注意的是,在相容性上,soft與後兩者是相容的,但softfp和hard兩種模式不相容,armel使用softfp,因此將hard模式的armel單獨作為一個abi,稱之為armhf
hf: 表示使用硬體浮點處理單元(hard)
以上就是交叉編譯器的命名規則了,我們來看看幾個例子吧:
arm-none-eabi-gcc:針對arm的裸機程式的gcc編譯器,如果你在arm板子上直接執行c程式,可能需要這個。
arm-uclinux-gcc:針對arm的uclinux的交叉編譯器
arm-linux-gcc : 針對arm的linux的交叉編譯器
arm-linux-gnueabi-gcc:針對arm的linux的交叉編譯器,此編譯器使用gnu glibc的庫
arm-linux-gnueabihf-gcc:針對arm的linux的交叉編譯器,此編譯器使用硬體浮點處理浮運算。
arm-linux-gnueabiel-gcc:針對arm的linux的交叉編譯器,此編譯器使用軟浮點處理浮點運算。
了解了交叉編譯器之後,我們用它來編譯一個最簡單的程式。
程式碼如下:
#include <stdio.h>
void main()
{
printf("hello arm");
}
在pc上編譯:
# arm-linux-gnueabi-gcc -o main main.c
在pc上執行:
root@ubuntu:/home/jinxin/app# ./main
bash: ./main: cannot execute binary file: Exec format error
執行出錯了,為什麼呢?
因為當前pc是x86架構,而剛剛編譯出來的二進位制檔案是arm格式的:
root@ubuntu:/home/jinxin/app# file main
main: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=ec9b455a1c1df94060c7364d0efc42975207fca9, not stripped
如果想要正常執行,需要把編譯出來的二進位制程式碼拷貝到arm的板子上去執行。
以上的輸出,有一個需要強調的地方:LSB
這裡的LSB是幹什麼的呢?接下來我們就來看看大小端。
大端和小端主要描述了資料在記憶體裡的儲存的順序。
大端模式,是指資料的高位元組儲存在記憶體的低地址中,而資料的低位元組儲存在記憶體的高地址中;
小端模式,是指資料的高位元組儲存在記憶體的高地址中,而資料的低位元組儲存在記憶體的低地址中;
比如:
x86是小端模式,而網路位元組序是大端模式。所以,專門出了網路位元組序和主機位元組序之間的轉換介面(ntohs、htons、ntohl、htonl)。以上的LSB,全稱Least Significant Bi,表示可執行檔案是小端格式的。
而arm則支援大小端模式,但是同一時刻只能支援一種,一般情況下,arm配置為大端模式,這也是跟x86分庭抗禮的意思。
針對arm,我再強調一下:如果arm硬體配置為大端,那麼編譯器要使用大端配置,核心、檔案系統、應用程式也要編譯為大端的格式。
那如何知道你的系統是大端還是小端呢?
一個最簡單的測試你係統是大端還是小端的程式:
#include <stdio.h>
void main()
{
int a = 0x1234;
char b = *(char*)&a;
if(0x34 == b){
printf("your system is little endian\\n");
} else {
printf("your system is big endian\\n");
}
}
在我的pc上執行,輸出:
root@ubuntu:/home/jinxin/app# ./endian
your system is little endian
以上基本內容,你學懂了嗎?
記得關注鑫哥,持續分享linux核心知識。
-
1 #
-
2 #
很明顯看編譯器,和編譯器有關係
華為的工資雖然很高,但是想進去可不容易。我記得13年那會兒去面試的時候面試官出過這麼一個題目:要求寫一段最簡單的c程式判斷當前的系統是大端系統還是小端系統。這個題目你會嗎?也許看完本文就一清二楚了。#程式設計師# #Linux# #linux# #運維# #c語言# #C語言#