GCC編譯器原理(一)------交叉編譯器製做和GCC組件及命令

1.1 交叉編譯器製做

默認安裝的 GCC 編譯系統所產生的代碼適用於本機,即運行 GCC 的機器,但也可將 GCC 安裝成可以生成其餘的機器代碼。安裝一些必須的模塊,就可產生多種目標機器代碼,並且可經過命令行選擇一種但願使用的代碼。html

1.1.1 目標機

從網站 http://gcc.gnu.org/install/specific.html 能夠獲得有可能的最新目標機列表。在此站點中可找到更新過的目標機列表,以及向各類目標機進行移植的最新信息。關於每種可能的目標機都有一個簡短介紹,能夠查找說明獲得有關移植的一些特殊需求。已知目標的列表很是長,並且也總在加入一些新端口。前端

1.1.2 建立交叉編譯器---crosstool-ng

當前已經不須要咱們從源碼上進行編譯安裝一個交叉編譯器了,咱們能夠經過工具crosstool-ng 或是 buildroot 工具來進行交叉編譯器的製做linux

(1)下載

能夠在官網上面直接下載c++

官網:http://crosstool-ng.github.io/git

也能夠經過git命令直接進行clone下載:github

git clone https://github.com/crosstool-ng/crosstool-ng objective-c

直接執行git clone命令會在你的工做目錄中創建一個crosstool-ng目錄,裏面存放的是源碼。編程

(2)安裝

能夠進入以下網站查看具體的安裝幫助信息:http://crosstool-ng.github.io/docs/後端

  • 進入crosstool-ng的源碼目錄,執行以下命令進行配置: ./configure --prefix=/some/place
    • /some/place是本身的主機上的路徑。
    • ./configure命令會檢查出本身的主機上缺乏哪些軟件環境,檢查出來了逐一安裝便可。
  • 執行make命令
  • 執行make install命令
    • 注意以上兩個命令可能會報權限不足,在命令前面加sudo解決
  • 將編譯出來的bin文件加入到臨時環境變量: export PATH="${PATH}:/some/place/bin"
    • 此環境變量只在當前終端中有效,關閉或者切換終端後當即失效。
    • 若要在主機的任何地方任何終端上使用,必須將環境變量寫入 .bashrc中去:
      • 能夠經過echo命令將其寫入 .bashrc中,以下所示:
        • export PATH=/some/place/bin:$PATH
        • 使之生效:source /etc/bash.bashrc
      • 或者執行軟連接也能夠:sudo ln -s /some/place/bin/ct-ng /usr/local/bin/ct-ng

(3)測試

安裝成功後,執行 ct-ng 命令會打印以下信息:瀏覽器

(4)創建S3C2440交叉編譯工具鏈

【1】創建文件夾

創建工做文件夾:

rk3399@rk3399:~/work/tools/toolchain$ mkdir S3C2440_work src S3C2440

  • S3C2440_work:爲S3C2440交叉編譯工具鏈的工做目錄
  • Src:存放下載下來的工具軟件源碼包
  • S3C2440:存放交叉編譯工具鏈
【2】查看支持的交叉編譯工具鏈類型

執行命令:ct-ng list-samples

裏面會列出不少的交叉編譯工具樣本。介紹ARM的幾種:

  • arm-unknown-eabi:基於裸板的,即無操做系統
  • arm-unknown-linux-gnueabi 是基於linux
  • arm-unknown-linux-uclibcgnueabi是爲uclinux用的。
  • arm-cortex_a8-linux-gnueabicortex-a8用的。
  • arm-cortexa9_neon-linux-gnueabihf:爲cortex-a9帶neon用的,exynos4412就能夠用此種

S3C2440選擇arm-unknown-linux-gnueabi 此種編譯器。

全部的支持的編譯器存放在rk3399@rk3399:~/work/tools/crosstool-ng/samples 此目錄下。將其arm-unknown-linux-gnueabi 中的文件拷貝到咱們創建的S3C2440_work目錄下。

【3】工程配置

進入S3C2440_work目錄中,將crosstool.config 文件更名爲 .config,而後執行 ct-ng menuconfig命令進行配置

  • Paths and misc options:
    • Local tarballs directory:源碼包存放位置,修改成 /home/rk3399/work/tools/toolchain/src
    • Prefix directory :交叉編譯工具鏈存放位置,home/rk3399/work/tools/toolchain/S3C2440
    • Number of parallel jobs:工做線程,根據本身的CPU是多少核來選。
  • Target options:
    • Target Architecture:默認是ARM
    • Default instruction set mode:指令集模式,默認爲ARM
    • Architecture level:架構指令集,S3C2440爲armv4t
    • Emit assembly for CPU:指定目標處理器的名稱,GCC經過這個名字來決定經過彙編代碼來生成哪一種指令。填入 arm9tdmi
    • Tune for CPU:新版本中填入上面兩個選項就沒有這個選項了,就管了。
    • Floating point:浮點類型,能夠看芯片手冊的方框圖,看找不找不到對應的浮點數類型,S3C2440沒有硬件浮點,選擇軟件浮點。softfp (FPU)
  • Toolchain options:
    • Tuple's vendor string:編譯器前綴,設爲s3c2440,編譯以後就爲arm-s3c2440-linux-gnueabi-
    • Tuple's alias:給產生的交叉編譯工具起個別名,設置別名,這樣會給每一個工具建立一個軟連接,好比arm-linux-gcc連接到到 arm-unknown-linux-gnueabi-gcc,能夠省去本身創建軟連接的功夫。設置爲
  • Operating System:
    • Source of linux:linux源碼,這裏沒有本身須要的源碼包,能夠在 .config中修改配置,系統會自動去下載。
  • 剩餘的其餘選項保持默認便可。

架構和處理器名稱,能夠在芯片手冊的方框圖中找到,以下:

【4】編譯

執行命令 ct-ng build 便可開始編譯。

製做完成會打印出下面的語句:

(5)製做 exynos 4412 編譯器

基本步驟與上面相似,不一樣的是在crosstool-ng中編譯器的選擇方面和工程配置上面。

Exynos 4412 選擇的是 arm-cortexa9_neon-linux-gnueabihf 編譯器,exynos 4412自己就是帶neon的,處理器自己就是屬於cortexa9系列。

配置上只是更改下Target options 中的內容:

  • Target options:
    • Architecture level:架構指令集爲armv7a
    • Emit assembly for CPU:指定目標處理器的名稱爲cortex-a9
    • Floating point:與2440不一樣的是,a9系列帶應浮點,也就是neon,這裏要選擇硬件浮點
    • Use specific FPU:這裏要填上 neon

以後就是保存編譯了。

1.1.3 編譯程序的功能

編譯程序是一個翻譯器。它讀入一種語言格式的指令(一般是文本形式的編程語言),並將它們翻譯成可在計算機上運行的指令集合(一般是二進制硬件指令的集合)。

  • 編譯程序能夠分爲兩部分:前端和後端。
    • 前端讀出程序的源代碼,將找到的內容以樹的形式轉換到內存駐留表(memory-resident table)中。一旦構造了該樹,編譯程序的後端就會讀出樹中保存的信息,並將它們轉換成目標機器上的彙編語言。
    • 將源文件翻譯成可執行程序的大體步驟:
      • 詞法分析是編譯程序前端的最開始部分。它從輸入中讀出字符,肯定哪些是在一塊兒的,造成符號、數字和標點符號。
      • 語法分析處理會讀入來自詞法瀏覽器的符號流,以及後面跟着的一個規則集合,肯定它們之間的關係。 語法分析器的輸出結果是樹結構, 會被傳遞給編譯程序的後端。
      • 語法分析樹結構會被翻譯成僞彙編語言(psuedo-assembly language) ,叫作寄存器傳送語言(Register Transfer LanguageRTL)。
      • 編譯程序的後端由分析 RTL 代碼開始,而後執行一些優化操做。代碼中冗餘和未被使用的部分會被去掉。樹中有些部分會被移動到其餘位置以防止語句被沒必要要地屢次執行。總的說來,有十個以上的優化操做,並且有些優化操做會屢次瀏覽代碼。
      • RTL 被翻譯成目標機器上的彙編語言。
      • 激活彙編器去將彙編語言翻譯成目標文件。該文件不是可執行格式——它包括可執行的目標代碼,但並非最終運行的形式。另外,它更可能包括未解析的到其餘模塊例程和數據的引用。
      • 鏈接程序未來自彙編器的目標文件(其中有些可能保存在包含目標文件的庫中)組合成可執行程序。
  • 全部的命令行選項大體可分爲三類:
    • 指定語言 GCC 編譯程序有能力編譯多種語言,有些選項只可用於其中的一兩種。例如,-C89 選項只應用於 C 語言,指定適用於 1989 年的標準。
    • 指定平臺 GCC 編譯程序能夠爲多種平臺生成目標代碼,而有些選項只能應用於爲某個指定平臺生成代碼。例如,若是輸出平臺是 Intel 386,那麼-fp-ret-in-387 選項可用來指出要將函數調用返回的浮點數保存在硬件的浮點寄存器中。
    • 普適 不少選項對全部語言和平臺都適用。例如,-O 選項指示編譯程序要優化輸出代碼。

例子:gcc -ansi -c muxit.c -o muxit.o

  • -ansi 便是指定語言

1.2 GCC組件及命令

1.2.1 GCC組件

GCC 是由許多組件組成的,但它們也並不老是出現的。有些部分是和語言相關的,因此若是沒有安裝某種特定語言,系統中就不會出現相關的文件。

組件

描述

c++

gcc 的一個版本,默認語言設置爲 C++,並且在鏈接的時候自動包含標準 C++庫。這和g++同樣

cc1

實際的 C 編譯程序

cc1plus

實際的 C++編譯程序

collect2

在不使用 GNU 鏈接程序的系統上, 有必要運行 collect2 來產生特定的全局初始化代碼 (例如 C++的構造函數和析構函數)

configure

GCC 源代碼樹根目錄中的一個腳本。用於設置配置值和建立 GCC 編譯程序必需的 make程序的描述文件

crt0.o

這個初始化和結束代碼是爲每一個系統定製的,並且也被編譯進該文件,該文件而後會被鏈接到每一個可執行文件中來執行必要的啓動和終止程序

cygwin1.dll

Windows 的共享庫提供的 API,模擬 UNIX 系統調用

f77

該驅動程序可用於編譯 Fortran

f771

實際的 Fortran 編譯程序

g++

gcc 的一個版本,默認語言設置爲 C++,並且在連接的時候自動包含標準 C++庫。這和 c++ 是同樣的

gcc

該驅動程序用於執行編譯程序和鏈接程序以產生須要的輸出

gcj

該驅動程序用於編譯 Java

gnat1

實際的 Ada 編譯程序

gnatbind

一種工具,用於執行 Ada 語言綁定

gnatlink

一種工具,用於執行 Ada 語言鏈接

jc1

實際的 Java 編譯程序

libgcc

該庫包含的例程被做爲編譯程序的一部分,是由於它們可被鏈接到實際的可執行程序中。它們是特殊的例程,鏈接到可執行程序,來執行基本的任務,例如浮點運算。這些庫中的例程一般都是平臺相關的

libgcj

運行時庫包含全部的核心 Java

libobjc

對全部 Objective-C 程序都必須的運行時庫

libstdc++

運行時庫,包括定義爲標準語言一部分的全部的 C++類和函數

 

1.2.2 GCC 編譯器命令

GCC的命令不少,經常使用的選項以下:

選項

描述

-c

只編譯不連接。

會明確指示 GCC 去編譯源代碼,在硬盤上留下目標文件,且跳過將目標文件鏈接到可執行程序這一步。

缺省狀況下, GCC經過用`.o'替換源文件名後綴`.c', `.i', `.s',等產生目標文件名.可使用-o選項選擇其餘名字.

GCC忽略-c選項後面任何沒法識別的輸入文件(他們不須要編譯或彙編).

如:gcc -c hello.c

-o file

指定輸出的文件名

若是沒有使用 `-o' 選項,默認的輸出結果是:可執行文件爲`a.out'。gcc -c hello.c -o hello.o

-x language

明確指出後面輸入文件的語言爲language (而不是從文件名後綴獲得的默認選擇).這個選項應用於後面 全部的輸入文件,直到遇着下一個`-x'選項. language的可選值有`c', `objective-c', `c-header', `c++', `cpp-output', `assembler',和`assembler-with-cpp'.

-x none

關閉任何對語種的明確說明,所以依據文件名後綴處理後面的文件(就象是從未使用過`-x'選項).

若是隻操做四個階段(預處理,編譯,彙編,鏈接)中的一部分,可使用`-x'選項(或文件名後綴)告訴 gcc從哪裏開始,用`-c', `-S',或`-E'選項告訴gcc到 哪裏結束.注意,某些選項組合(例如, `-x cpp-output -E')使gcc不做任何事情.

-S

指示編譯程序生成彙編語言代碼,而後中止。

缺省狀況下, GCC經過用 `.o' 替換源文件名後綴 `.c'、`.i' 等等,產生 目標文件名。可使用-o選項選擇其餘名字。

彙編語言的形式依賴於編譯程序的目標平臺。若是編譯多個源文件,會爲每一個源文件都生成一個彙編語言模塊。

GCC忽略任何不須要編譯的輸入文件。

gcc -S helloworld.c

-E

預處理後即中止,不進行編譯。預處理後的代碼送往標準輸出

GCC忽略任何不須要預處理的輸入文件.

gcc -E helloworld.c

gcc -E helloworld.c -o helloworld.i

-C

告訴預處理器不要丟棄註釋,配合 `-E' 選項使用。

-P

告訴預處理器不要產生 `#line' 命令,配合 `-E' 選項使用

-v

(在標準錯誤)顯示執行編譯階段的命令.同時顯示編譯器驅動程序,預處理器,編譯器的版本號.

-pipe

在編譯過程的不一樣階段間使用管道而非臨時文件進行通訊.這個選項在某些系統上沒法工做,由於那些系統的 彙編器不能從管道讀取數據. GNU的彙編器沒有這個問題.

-ldl

表示生成的對象模塊須要用到共享庫:$ gcc say.c -ldl -o say

主要是用到了 dlopen 等函數須要用到此選項

-I

指定頭文件路徑

-e name

指定 name 爲程序的入口地址

-ffreestanding

編譯獨立的程序,不會自動連接 C 運行庫、啓動文件等;他隱含聲明瞭 `-fno-builtin' 選項,並且對main函數沒有特別要求。

-finline-functions

-fno-inline-funcitons

啓用內聯函數

關閉內聯函數

-g

以操做系統的本地格式(stabs,COFF,XCOFF 或 DWARF)產生調試信息,GDB可以使用這些調試信息。

-ggdb

以本地格式(若是支持)輸出調試信息,儘量包括GDB擴展。

-L <directory>

指定連接時查找路徑,多個路徑之間用冒號隔開

-nostartfiles

不連接系統標準啓動文件,好比crtbegin.o、crtend.o,而標準庫文件仍然正常使用。

-nostdlib

不連接系統標準啓動文件和標準庫文件,只把指定的文件傳遞給鏈接器。

-static

在支持動態鏈接(dynamic linking)的系統上阻止鏈接共享庫。即只能使用靜態連接。

-shared

生成一個共享目標文件,他能夠和其餘目標文件連接產生可執行文件。

-O
-O1

優化。對於大函數,優化編譯佔用稍微多的時間和至關大的內存。

不使用 `-O' 選項時,編譯器的目標是減小編譯的開銷,使編譯結果可以調試。

語句是獨立的:若是在兩條語句之間用斷點停止程序,能夠對任何變量從新賦值,或者在函數體內把程序計數器指到其餘語句,以及從源程序中精確地獲取你期待的結果。

不使用 `-O' 選項時,只有聲明瞭register的變量才分配使用寄存器。編譯結果比不用 `-O' 選項的GCC要略遜一籌.

使用了 `-O' 選項,編譯器會試圖減小目標碼的大小和執行時間。

若是指定了`-O'選項,,`-fthread-jumps' 和 `-fdefer-pop' 選項將被打開。

-O2

多優化一些。

除了涉及空間和速度交換的優化選項,執行幾乎全部的優化工做。例如不進行循環展開(loop unrolling)和函數內嵌(inlining)。

和 -O 選項比較,這個選項既增長了編譯時間,也提升了生成代碼的運行效果。

-O3

優化的更多。除了打開 -O2所作的一切,它還打開了-finline-functions選項。

-O0

不優化。若是指定了多個 -O選項,無論帶不帶數字,最後一個選項纔是生效的選項。

-Wall

對源代碼中的多數編譯警告進行啓用

-fpic

若是支持這種目標機,編譯器就生成位置無關目標碼。適用於共享庫(shared library)。

-fPIC

若是支持這種目標機,編譯器就輸出位置無關目標碼。適用於動態鏈接(dynamic linking),即便分支須要大範圍轉移。

-fPIE

使用地址無關代碼模式編譯可執行文件

-Xlinker option

把選項option傳遞給鏈接器,能夠用他傳遞系統特定的鏈接選項, GNU CC沒法識別這些選項。

若是須要傳遞攜帶參數的選項,必須使用兩次 `-Xlinker',一次傳遞選項,另外一次傳遞他的參數。

例如,若是傳遞 `-assert definitions',必須寫成 `-Xlinker -assert -Xlinker definitions',而不能寫成 `-Xlinker "-assert definitions"',由於這樣會把整個字符串當作一個參數傳遞,顯然這不是鏈接器期待的。

-Wl option

把選項option傳遞給鏈接器。若是option中含有逗號,就在逗號處分割成多個選項。

-fomit-frame-pointer

禁止使用 EBP 做爲函數幀指針

-fno-builtin

禁止 GCC 編譯器內置函數

-ffunction-sections

將每一個函數編譯到獨立的代碼段

-fdata-sections

將全局/靜態變量編譯到獨立的數據段

相關文章
相關標籤/搜索