gcc、arm-linux-gcc和arm-elf-gcc的關係?

2021-03-06 嵌入式大雜燴

點擊上方「嵌入式大雜燴」,選擇「置頂公眾號」第一時間查看編程筆記!

轉自:

https://blog.csdn.net/ce123_zhouwei/article/details/8220664

一、GCC簡介

The GNU Compiler Collection,通常簡稱 GCC,是一套由 GNU 開發的編譯器集,為什麼是編輯器集而不是編譯器呢?那是因為它不僅支持 C 語言編譯,還支持 C++, Ada,Objective C 等許多語言。另外 GCC 對硬體平臺的支持,可以所無所不在,它不僅支持 X86處理器架構, 還支持 ARM, Motorola 68000, Motorola 8800,AtmelAVR,MIPS 等處理器架構。

二、GCC的組成結構


GCC 內部結構主要由 Binutils、gcc-core、Glibc 等軟體包組成。

舉例描述下上面 3 個包是如何進行運作的。有一個 c 源文件 test.c 源碼如下:

#include<stdio.h>
int main(int argc, char *argv[])
{
printf("Hello Linux!!\n");
return 0;
}

編譯命令為: gcc -o test test.c 編譯生成 test 可執行文件。gcc 編譯流程分為四個步驟:預處理、編譯 、彙編、連結。個人認為預處理和編譯主要由 gcc-core 來完成,彙編和連結主要由 Binutils 來完成。

那麼何時用到 glibc 呢?看到源碼中的 printf 函數沒有,這個函數在 GCC 中是以庫函數的形式存在,這個庫函數在 glibc 庫中,在 stdio.h 頭文件中被聲明。
總的來說,如果真正了解了上面 3 個軟體包的作用,自然就明白 GCC 是如何工作的。

三、交叉編譯

交叉編譯(或交叉建立)是這樣一種過程,它在一種機器結構下編譯的軟體將在另一種完全不同的機器結構下執行。一個常見的例子是在 PC 機上為運行在基於 ARM、PowerPC或 MIPS 的目標機的編譯軟體。

幸運的是,GCC 使得這一過程所面臨的困難要比聽起來小得多。GCC 中的一般工具通常都是通過在命令行上調用命令(如 gcc)來執行的。在使用交叉編譯的情況下,這些工具將根據它編譯的目標而命名。

例如,要使用交叉工具鏈為 ARM 機器編譯簡單的 Hello World 程序,你可以運行如下所示的命令:使用如下命令編譯並測試這個代碼: arm-linux-gcc -o hello hello.c。

四、arm-linux-gcc

arm-linux-gcc 是基於 ARM 目標機的交叉編譯軟體, arm-linux-gcc 跟 GCC 所需的安裝包不同:

x86 跟 ARM 所使用的指令集是不一樣的,所以所需要的 binutils 肯定不一樣;上面提到過 gcc-core 是依賴於 binutils 的,自然 ARM 跟 x86 所使用的 gcc-core 包也不一樣;glibc 一個 c 庫,最終是以庫的形式存在於編譯器中,自然 ARM 所使用的 glibc 庫跟 x86 同樣也不一樣,其它的依此類推。

五、arm-elf-gcc

arm-elf-gcc 跟 arm-linux-gcc 一樣,也是是基於 ARM 目標機的交叉編譯軟體。但是它們不是同一個交叉編譯軟體,兩者是有區別的,兩者區別主要在於使用不同的 C 庫文件。

arm-linux-gcc 使用 GNU 的 Glibc,而 arm-elf-gcc 一般使用 uClibc/uC-libc 或者使用 RedHat專門為嵌入式系統的開發的C庫newlib。只是所應用的領域不同而已,Glibc是針對PC開發的,uClibc/uC-libc是與Glibc API兼容的小型化C語言庫,實現了Glibc部分功能。

六、uClibc/uC-libc 

uClinux有兩個經常使用的libc庫:uC-libc和uClibc。雖然兩者名字很相似,其實有差別,下面就簡單的介紹一下二者的不同之處。uC -libc是最早為uClinux開發的庫,是Jeff Dionne和Kenneth Albanowski為在EKLs項目中支持m68000在Linux-8086 C庫源碼上移植的。

uC-libc是一個完全的libc實現,但其中有一些api是非標準的,有些libc的標準也沒有實現。uC-libc穩定地支持 m68000,ColdFire和沒有MMU的ARM。其主要設計目標是「小」、「輕」,並儘量與標準一致,雖然它的API和很多libc兼容,但是似乎並不像它期望的那樣和所有標準一致。

uClibc就是為了解決這個問題從uC-libc中發展出來的。它的所有API都是標準的(正確的返回類型,參數等等),它彌補了uC-libc中沒有實現的libc標準,現在已經被移植到多種架構中。一般來講,它儘量兼容glibc以便使應用程式用uClibc改寫變的容易。

uClibc能夠在標準的 VM linux和uClinux上面使用。為了應用程式的簡潔,它甚至可以在許多支持MMU的平臺上被編譯成共享庫。Erik Anderson在uClibc背後做了很多的工作。uClibc支持許多系列的處理器:m68000,Coldfire,ARM,MIPS,v850, x86,i960,Sparc,SuperH,Alpha,PowerPC和Hitachi 8。

不斷增加的平臺支持顯示uClibc能夠很容易的適應新的架構。uClinux發行版提供了環境能夠讓你選擇使用uC-libc或是uClibc編譯。對於m68000和Coldfire平臺來說,選擇uC-libc還是稍微好一點,因為它支持共享庫,而共享庫是這些cpu經常使用的 libc。uClibc也幾乎和所有的平臺都能很好的工作。

newlib 是一個用於嵌入式系統的開放原始碼的C語言程序庫,由libc和libm兩個庫組成,特點是輕量級,速度快,可移植到很多CPU結構上。newlib實現了許多複雜的功能,包括字符串支持,浮點運算,內存分配(如malloc)和I/O流函數(printf,fprinf()等等)。其中libc提供了c 語言庫的實現,而libm提供了浮點運算支持。

七、C語言庫的選擇

在為ARM交叉編譯gcc編譯器時,對gcc指定不同的配置選項時,使用的C語言庫就不同,gcc編譯器默認使用Glibc,也可以使用 uClibc/uC-libc(基本兼容Glibc API),當使用--with-newlib時,gcc編譯器不使用Glibc。當沒有交叉編譯Glibc時,可以使用--with-newlib禁止連接Glibc而編譯bootstrap gcc編譯器。

從gcc源目錄下的config/arm中的t-linux和t-arm-elf中可以看出,不同的--target也影響gcc連接C語言庫,t-linux(--target=arm-linux)默認使用Glibc,-arm-elf(--target=arm-elf)使用- Dinhibit_libc禁止連接Glibc,這時我們就可以使用newlib等其他C語言庫編譯GCC工具鏈。

雖然GCC工具鏈配置了不同的的C語言庫,但由於這些C語言庫都可以用來支持GCC,它們對核心數據的處理上不存在較大出入。因而arm-linux-* 和 arm-elf-*區別主要表現在C語言庫的實現上,例如不同系統調用,不同的函數集實現,不同的ABI/啟動代碼以及不同系統特性等微小的差別。

arm-linux-*和 arm-elf-*的使用沒有一個絕對的標準,排除不同庫實現的差異,gcc可以編譯任何系統。arm-linux-*和 arm-elf-*都可以用來編譯裸機程序和作業系統,只是在遵循下面的描述時系統程序顯得更加協調:

arm-linux-*針對運行linux的ARM機器,其依賴於指定的C語言庫Glibc,因為同樣使用Glibc的linux而使得arm-linux-*在運行linux的ARM機器上編譯顯得更加和諧。

arm-elf-*則是一個獨立的編譯體系,不依賴於指定的C語言庫Glibc,可以使用newlib等其他C語言庫,不要求作業系統支持,當其使用為嵌入式系統而設計的一些輕巧的C語言庫時編譯裸機程序(沒有linux等大型作業系統的程序),如監控程序,bootloader等能使得系統程序更加小巧快捷。

往期筆記:

【Linux筆記】系統目錄結構

【Linux筆記】Vi/Vim編輯器

C語言指針變量的運算

智能桌面天氣預報系統(終)

點擊左下角的【閱讀全文】,獲取本公眾號往期所有筆記推送

相關焦點

  • gcc&arm-linux-gcc編譯過程詳解
    :1.gcc 2.指針,3.Makefile ,今天是第一部分gcc,內容同樣適用於arm-linux-gcc。老規矩,文字無法完整描述視頻內容,如果覺得這些文章對你有用,想進一步學習更深層次的乾貨,請訪問100ask.taobao.com購買arm裸機1期加強版視頻課程。
  • 3分鐘看懂gcc、arm-Linux-gcc和arm-elf-gcc的組成及區別
    GCC 內部結構主要由 Binutils、gcc-core、Glibc 等軟體包組成。1. Binutils:它是一組開發工具,包括連接器,彙編器和其他用於目標文件和檔案的工具。關於 Binutils 的介紹可以參考 Binutils 簡單介紹。這個軟體包依賴於不同的目標機的平臺。
  • /arm-none-linux-gnueabi-gcc: No such file or directory
    arm-none-linux-gnueabi-nmarm-none-linux-gnueabi-c++ arm-none-linux-gnueabi-objcopyarm-none-linux-gnueabi-c++filt arm-none-linux-gnueabi-objdumparm-none-linux-gnueabi-cpp arm-none-linux-gnueabi-ranlibarm-none-linux-gnueabi-g
  • 在 Ubuntu 20.04 上安裝 gcc-arm-none-eabi
    -10.3-2021.10-x86_64-linux.tar.bz2 Linux x86_64 TarballMD5: 2383e4eb4ea23f248d33adc70dc3227e2、先卸載已有的「gcc-arm-none-eabi」(如果有地話)sudo apt remove gcc-arm-none-eabi
  • ARM交叉編譯器掃盲
    Application),一般適合 ARM7、Cortex-M 和 Cortex-R 內核的晶片使用,所以不支持那些跟作業系統關係密切的函數,比如fork(2),他使用的是 newlib 這個專用於嵌入式系統的C庫。
  • 【教程】arm-linux-gcc 4.3.2編譯uboot-1.1.6
    在第三期項目的視頻中,官方提供了一整套新的工具鏈,bootloader,內核和文件系統(arm-linux-gcc_4.3.2, uboot-2012.04.01
  • GNU/GCC 基礎介紹
    包括gcc,g ++,ar,as,ld,objcopy,objdump等。不同的平臺都有一套完整的工具。否則就是gcc嵌入式(MIPS):mips-linux-gnu-。arm對應的是arm-linux-gnu,不同的平臺取代不同。
  • C語言編譯器之一,GCC
    最初是為C語言而編寫,後面陸陸續續擴充了C++、 Objective-C、 Fortran、Java、Ada和Go語言,也包括了這些語言的庫(如libstdc++,libgcj等),因此GCC是GNU編譯器套件。         Gcc編譯器鏡像在其官方FTP伺服器上可以下載,目前最新版本為gcc-11.2.0。
  • gcc中 -pthread和 -lpthread的區別
    $ gcc -v x.o -ox -pthread  /usr/lib/gcc/i486-linux-gnu/4.2.4/collect2 --eh-frame-hdr -m elf_i386 --hash-style=both  -dynamic-linker /lib/ld-linux.so.2 -ox  /usr/lib/gcc/i486
  • 一次搞定 Arm Linux 交叉編譯
    為了讓這個流程變得簡單,開發者們為不同的晶片開發了不同的編譯器,比如針對 Arm 平臺的 arm-linux-gcc,針對 mips 平臺的 mips-linux-gnu-gcc,這些編譯器都是基於 GCC 針對具體的架構指令集進行對應配置,所以它們在運行的時候就就會生成和該目標平臺對應的可執行文件。
  • GCC的gcc和g++區別
    和g++是一個東西,只是有兩個不同的名字而已,今天在linux下編譯一個c代碼時出現了錯誤才找了一下gcc和g++的區別。gcc是GCC中的GUN C Compiler(C 編譯器)g++是GCC中的GUN C++ Compiler(C++編譯器)一個有趣的事實就是,就本質而言,gcc和g++並不是編譯器,也不是編譯器的集合,它們只是一種驅動器,根據參數中要編譯的文件的類型,調用對應的GUN編譯器而已。
  • GCC:優化 Linux、網際網路和一切 | Linux 中國
    因為 GCC 提供了跨計算環境的可移植性,它使得代碼能夠更容易地在各種新的和傳統的客戶機和伺服器平臺上進行測試。GCC 為 C、C++ 和 Fortran 編譯器提供了 OpenMP 4.0 的完整支持,為 C 和 C++ 編譯器提供了 OpenMP 4.5 完整支持。對於 OpenACC、 GCC 支持大部分 2.5 規範和性能優化,並且是唯一提供 OpenACC 支持的非商業、非學術編譯器。
  • Linux GCC常用命令
    假設有一個由test1.c和 test2.c兩個源文件組成的程序,為了對它們進行編譯,並最終生成可執行程序test,可以使用下面這條命令: gcc test1.c test2.c -o test 如果同時處理的文件不止一個,GCC仍然會按照預處理、編譯和連結的過程依次進行。
  • Linux gcc版本如何升級
    純手工打造每一篇開源資訊與技術乾貨,數十萬程式設計師和Linuxer
  • SQLite3在ARM Cortex-A9開發板上的移植
    /configure   --prefix=$PWD/build     --host=arm-linux      CC=/opt/arm-linux-gcc-4.6.4/bin/arm-linux-gcc  OR  # .
  • 手把手教你使用VSCode + gdb + gdbserver調試ARM程序
    gdb調試相關文章:GDB調試器原來那麼簡單而在嵌入式Linux中,我們如何對開發板上的arm程序進行調試呢?我們可以使用VSCode+gdb+gdbserver來調試我們arm開發板上的arm程序。下面簡單介紹一下使用方法,前提是開發板與PC可以進行無線/有線通信。
  • linux安裝gcc的shell腳本
    ,當然安裝編譯過程還是有點長的,腳本暫只支持以CentOS系統(系統版本5~7有測試過)來安裝(其它系統需要調整下快速安裝組件命令 yum 和對應的安裝包名)#!'# 鏡像地址MIRRORS_URL="http://mirror.linux-ia64.org/gnu/gcc"if [ -z $1 ] || [[ $1 == "new" ]]; then    echo "gcc version is empty!"
  • Linux GCC 常用命令
    \n"); return 0;}這個程序,一步到位的編譯指令是:gcc test.c -o test實質上,上述編譯過程是分為四個階段進行的,即預處理(也稱預編譯,Preprocessing)、編譯(Compilation)、彙編 (Assembly)和連接(Linking)。
  • 【Linux公開課】GCC簡介與gcc工具軟體
    Linux世界又是一個極其開放和自由的世界,極具個性化,給用戶提供了各種可能的選擇,也正是因為如此,給一些有「選擇困難症」的新手帶來了選擇上的困難,也讓一些急於求成的新手產生了「病急亂投醫,逢廟就燒香」的舉動。這一章的內容就是一劑良藥,能有效的解決這兩類問題。
  • 編譯器 clang gcc g++
    目標是創建一套完全自由的作業系統)g++GNU c++編譯器gcc、g++、clang 都是編譯器。gcc 和 g++ 都能夠編譯c/c++,但是編譯時候行為不同。linux 安裝 gccapt install build-essential #安裝gcc、g++與make編譯器過程一個C/C++文件要經過預處理(preprocessing)、編譯(compilation