您好,登錄后才能下訂單哦!
?在進行嵌入式開發時,通常有宿主機與目標機的角色之分,宿主機是執行編譯、鏈接嵌入式軟件的計算機,而目標機是運行嵌入式軟件的硬件平臺。而這兩者之間有時硬件/軟件平臺可能不同,在宿主機上直接使用編譯器的程序在目標機上無法運行,因此就出現了交叉編譯工具。在針對ARM架構上運行的Linux目標機來說,其專用的交叉編譯工具為arm-linux-gcc、arm-linux-ld等。
?一個 C/C++文件要經過預處理(preprocessing)、編譯(compilation)、匯編(assembly)和連接(linking)等 4 步才能變成可執行文件。其每一步的作用在下表中進行了說明:
步驟 | 說明 |
---|---|
預處理 | C/C++源文件中,以“ #”開頭的命令被稱為預處理命令,如包含命令“ #include”、宏定義命令“ #define”、條件編譯命令“ #if”、“ #ifdef”等。預處理就是將要包含(include)的文件插入原文件中、將宏定義展開、根據條件編譯命令選擇要使用的代碼,最后將這些東西輸出到一個“ .i”文件中等待進一步處理。 |
編譯 | 編譯就是把 C/C++代碼(比如上述的“ .i”文件)“ 翻譯” 成匯編代碼。 |
匯編 | 匯編就是將第二步輸出的匯編代碼翻譯成符合一定格式的機器代碼,在 Linux 系統上一般表現為 ELF 目標文件(OBJ 文件)。 |
鏈接 | 鏈接就是將上步生成的 OBJ 文件和系統庫的 OBJ 文件、 庫文件連接起來,最終生成了可以在特定平臺運行的可執行文件。 |
?編譯器利用上述四個步驟中的一個或多個來處理輸入文件,源文件的后綴表示源文件所用的語言,后綴控制編譯器的缺省動作。
后綴名 | 語言種類 |
---|---|
.c | C源程序 |
.i | 預處理后的c文件 |
.s或.S | 匯編語言源程序 |
.h | 頭文件 |
.o | 匯編后對象文件,包含了對各個函數的入口標記,描述,當程序要執行時還需要鏈接(link).鏈接就是把多個.o文件鏈成一個可執行文件 |
?在交叉編譯工具里經常用到的命令有:
命令 | 介紹 |
---|---|
arm-linux-gcc | 編譯器 |
arm-linux-ld | 鏈接器 |
arm-linux-objdump | 反匯編工具 |
arm-linux-readelf | elf文件查看器 |
arm-linux-objcopy | 文件轉換工具 |
1.arm-linux-gcc
常用選項:
-E:讓編譯器在預處理后停止編譯過程
-o file:指定輸出文件為 file
-S:只進行編譯而不進行匯編,生成匯編代碼
-c:將匯編代碼轉化為“.o”的二進制目標代碼(-c可以一次性完成前三部工作)
2.arm-linux-ld
用于將多個目標文件、庫文件連接成可執行文件,常用選項:
object-file-name:默認是是OBJ 文件或庫文件(根據文件內容,連接器能夠區分 OBJ 文件和庫文件)。如果 GCC 執行連接操作,這些 OBJ 文件將成為連接器的輸入文件。
-llibrary:連接名為 library 的庫文件。
-nostdlib:不連接系統標準啟動文件和標準庫文件,只把指定的文件傳遞給連接器。這個選項常用于編譯內核、 bootloader 等程序,它們不需要啟動文件、標準庫文件。
-static:在支持動態連接(dynamic linking)的系統上,阻止連接共享庫。
-shared:生成一個共享 OBJ 文件,它可以和其他 OBJ 文件連接產生可執行文件。只有部分系統支持該選項。
-T:只在連接 Bootloader、內核等沒有底層軟件支持的軟件;連接運行于操作系統之上的應用程序時, 無需指定-T。
3.arm-linux-objcopy
被用來拷貝一個目標文件的內容到另一個文件中, 可以使用不同于源文件的格式來輸出目的文件,即可以進行格式轉換。
input-file、outfile:分別表示輸入目標文件(源目標文件)和輸出目標文件(目的目標文件)
-I bfdname:用來指明源文件的格式, bfdname 是 BFD 庫中描述的標準格式名
-O bfdname :使用指定的格式來輸出文件, bfdname 是 BFD 庫中描述的標準格式名
-F bfdname :同時指明源文件、目的文件的格式
-R sectionname:從輸出文件中刪掉所有名為 sectionname 的段。
-S :不從源文件中拷貝重定位信息和符號信息到目標文件中去
-g :不從源文件中拷貝調試符號到目標文件中去
在編譯 bootloader、 內核時,常用 arm-linux-objcopy 命令將 ELF 格式的生成結果轉換為二進制文件,比如:$ arm-linux-objcopy -O binary -S elf_file bin_file
4.arm-linux-objdump
用于顯示二進制文件信息。
-b bfdname :指定目標碼格式。可以使用“ arm-linux-objdump –i”命令查看支持的目標碼格式列表。
-disassemble :反匯編可執行段(executable sections)。
-disassemble-all :與-d 類似,反匯編所有段。
-EB :指定字節序。
--file-headers :顯示文件的整體頭部摘要信息。
--section-headers:顯示目標文件各個段的頭部摘要信息。
-info :顯示支持的目標文件格式和 CPU 架構,它們在“ -b”、“ -m”選項中用到。
--section=name :僅僅顯示指定 section 的信息。
--architecture=machine :指定反匯編目標文件時使用的架構,當待反匯編文件本身沒有描述架構信息的時候(比如S-records),這個選項很有用。
5.arm-linux-readelf
-a 應用程序 可查看文件運行架構、大小端、共享庫等信息。針對編譯時加上"-static"選項的應用程序。
-d 應用程序 可查看應用程序的動態鏈接庫
?當一個項目有上百個文件的代碼構成的項目,如果其中只有一個或少數幾個文件進行了修改,使用Gcc 編譯工具,就不得不把這所有的文件重新編譯一遍,因為編譯器并不知道哪些文件是最近更新的,只有全部重新才能得到可執行文件。
?但是編譯過程是分為編譯、匯編、鏈接不同階段的,其中編譯階段僅檢查語法錯誤以及函數與變量的聲明是否正確聲明了,在鏈接階段則主要完成是函數鏈接和全局變量的鏈接。因此,那些沒有改動的源代碼根本不需要重新編譯,而只要把它們重新鏈接進去就可以了。而Make工程管理器能夠自動識別更新了的文件代碼,同時又不需要重復輸入冗長的命令行。
?Make 工程管理器也就是個“自動編譯管理器” ,它能夠根據文件時間戳自動發現更新過的文件而減少編譯的工作量,同時,它通過讀入 Makefile 文件的內容來執行大量的編譯工作。
1.Makefile的構成
?Makefile 是 Make 讀入的惟一配置文件,在一個 Makefile 中通常包含如下內容:
· 需要由 make 工具創建的目標體(target) ,通常是目標文件或可執行文件;
· 要創建的目標體所依賴的文件(dependency_file) ;
· 創建每個目標體時需要運行的命令(command) 。
target: dependency_files
command
如:
hello.o: hello.c hello.h
gcc –c hello.c –o hello.o
2.Makefile的變量
?變量是在 Makefile 中定義的名字,用來代替一個文本字符串,該文本字符串稱為該變量的值。在具體要求下,這些值可以代替目標體、依賴文件、命令以及 makefile 文件中其他部分。在Makefile 中的變量定義有兩種方式:一種是遞歸展開方式,另一種是簡單方式。
?遞歸展開方式定義的變量是在引用在該變量時進行替換的,即如果該變量包含了對其他變量的應用,則在引用該變量時一次性將內嵌的變量全部展開,缺點是不能在變量后追加內容(因為語句:CFLAGS = $(CFLAGS) -O 在變量擴展過程中可能導致無窮循環) 。簡單擴展型變量的值在定義處展開,并且只展開一次,因此它不包含任何對其他變量的引用,從而消除變量的嵌套引用。
遞歸展開方式的定義格式為:VAR=var。
簡單擴展方式的定義格式為:VAR:=var。
Make 中的變量使用均使用格式為:$(VAR)。
?預定義變量包含了常見編譯器、匯編器的名稱及其編譯選項:
命令格式 | 含義 |
---|---|
AR | 庫文件維護程序的名稱,默認值為 ar |
AS | 匯編程序的名稱,默認值為 as |
CC | C 編譯器的名稱,默認值為 cc |
CPP | C 預編譯器的名稱,默認值為$(CC) –E |
CXX | C++編譯器的名稱,默認值為 g++ |
FC | FORTRAN 編譯器的名稱,默認值為 f77 |
RM | 文件刪除程序的名稱,默認值為 rm –f |
ARFLAGS | 庫文件維護程序的選項,無默認值 |
ASFLAGS | 匯編程序的選項,無默認值 |
CFLAGS | C 編譯器的選項,無默認值 |
CPPFLAGS | C 預編譯的選項,無默認值 |
CXXFLAGS | C++編譯器的選項,無默認值 |
FFLAGS | FORTRAN 編譯器的選項,無默認值 |
Makefile 中常見自動變量
命 令 格 式 | 含 義 |
---|---|
$* | 不包含擴展名的目標文件名稱 |
$+ | 所有的依賴文件,以空格分開,并以出現的先后為序,可能包含重復的依賴文件 |
$< | 第一個依賴文件的名稱 |
$@ | 目標文件的完整名稱 |
$^ | 所有不重復的依賴文件,以空格分開 |
$% | 如果目標是歸檔成員,則該變量表示目標的歸檔成員名稱 |
$? | 所有時間戳比目標文件晚的依賴文件,并以空格分開 |
3.Makefile 規則
?Makefile 的規則是 Make 進行處理的依據,它包括了目標體、依賴文件及其之間的命令語句。一般的,Makefile 中的一條語句就是一個規則。但為了簡化 Makefile 的編寫,make 還定義了隱式規則和模式規則。
?隱含規則能夠告訴 make 怎樣使用傳統的技術完成任務,這樣,當用戶使用它們時就不必詳細指定編譯的具體細節,而只需把目標文件列出即可。下面的Makefile中kang.o與yul.o的生成過程即可以省略。
OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
$(CC) $^ -o $@
Makefile 中常見隱式規則目錄
對應語言后綴名 | 規 則 |
---|---|
C 編譯:.c 變為.o | $(CC) –c $(CPPFLAGS) $(CFLAGS) |
C++編譯:.cc 或.C 變為.o | $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) |
Pascal 編譯:.p 變為.o | $(PC) -c $(PFLAGS) |
Fortran 編譯:.r 變為-o | $(FC) -c $(FFLAGS) |
?模式規則是用來定義相同處理規則的多個文件的。它不同于隱式規則,隱式規則僅僅能夠用 make 默認的變量來進行操作,而模式規則還能引入用戶自定義變量,為多個文件建立相同的規則,從而簡化 Makefile 的編寫。模式規則的格式類似于普通規則,這個規則中的相關文件前必須用“%”標明。
OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
$(CC) $^ -o $@
%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
4.Make 管理器的使用
?make 有豐富的命令行選項,可以完成各種不同的功能。
命 令 格 式 | 含 義 |
---|---|
-C dir | 讀入指定目錄下的 Makefile |
-f file | 讀入當前目錄下的 file 文件作為 Makefile |
-i | 忽略所有的命令執行錯誤 |
-I dir | 指定被包含的 Makefile 所在目錄 |
-n | 只打印要執行的命令,但不執行這些命令 |
-p | 顯示 make 變量數據庫和隱含規則 |
-s | 在執行命令時不顯示命令 |
-w | 如果 make 在執行過程中改變目錄,則打印當前目錄名 |
5.makefile中常用函數
?函數調用的格式為:$(function arguments)
?這里function 是函數名, arguments是該函數的參數。參數和函數名之間是用空格或 Tab 隔開,如果有多個參數,它們之間用逗號隔開。這些空格和逗號不是參數值的一部分。
字符串替換和分析函數:
函數 | 含義 |
---|---|
$(subst from,to,text) | 在文本text中使用to 替換每一處from. |
$(patsubst pattern,replacement,text) | 尋找text中符合格式pattern的字,用replacement替換它們.pattern和replacement 中可以使用通配符。 |
$(strip string) | 去掉前導和結尾空格,并將中間的多個空格壓縮為單個空格。 |
$(findstring find,in) | 在字符串in 中搜尋find,如果找到,則返回值是find ,否則返回值為空。 |
$(filter pattern...,text) | 返 回 在 text 中 由 空 格 隔 開 且 匹 配 格 式 pattern... 的 字 , 去 除 不 符 合 格 式pattern... 的字。 |
$(filter-out pattern...,text) | 返 回 在 text中 由 空 格 隔 開 且 不 匹 配 格 式 pattern...的 字 , 去 除 符 合 格 式pattern... 的字。 |
$(sort list) | 將 list中的字按字母順序排序,并去掉重復的字。輸出由單個空格隔開的字的列表。 |
文件名函數:
函數 | 含義 |
---|---|
$(dir names...) | 抽取names...中每一個文件名的路徑部分,文件名的路徑部分包括從文件名的首字符到最后一個斜杠(含斜杠)之前的一切字符。 |
$(notdir names...) | 抽取names...中每一個文件名中除路徑部分外一切字符(真正的文件名)。 |
$(suffix names...) | 抽取names...中每一個文件名的后綴。 |
$(basename names...) | 抽取names...中每一個文件名中除后綴外一切字符。 |
$(addsuffix suffix,names...) | 參數names...是一系列的文件名,文件名之間用空格隔開; suffix 是一個后綴名。將 suffix(后綴)的值附加在每一個獨立文件名的后面,完成后將文件名串聯起來,它們之間用單個空格隔開。 |
$(addprefix prefix,names...) | 參數 names是一系列的文件名,文件名之間用空格隔開; prefix 是一個前綴名。將preffix(前綴)的值附加在每一個獨立文件名的前面,完成后將文件名串聯起來,它們之間用單個空格隔開。 |
$(wildcard pattern) | 參數pattern是一個文件名格式,包含有通配符(通配符和 shell 中的用法一樣)。函數 wildcard 的結果是一列和格式匹配的且真實存在的文件的名稱,文件名之間用一個空格隔開。 |
6.使用 autotools
?編寫 Makefile 不是一件輕松的事,尤其對于一個較大的項目而言更是如此。autotools 系列工具只需用戶輸入簡單的目標文件、依賴文件、文件目錄等就可以輕松地生成 Makefile 。另外,這些工具還可以完成系統配置信息的收集,從而可以方便地處理各種移植性的問題。autotools 是系列工具主要包含:aclocal、autoscan、autoconf、autoheader、automake。
?使用 autotools 主要就是利用各個工具的腳本文件以生成最后的 Makefile。其總體流程是:
· 使用 aclocal 生成一個“aclocal.m4”文件,該文件主要處理本地的宏定義;
· 改寫“configure.scan”文件,并將其重命名為“configure.in” ,并使用 autoconf 文件生成 configure 文件。
命令 | 執行過程 |
---|---|
autoscan | 它會在給定目錄及其子目錄樹中檢查源文件,若沒有給出目錄,就在當前目錄及其子目錄樹中進行檢查。它會搜索源文件以尋找一般的移植性問題并創建一個文件“configure.scan” 。 |
autoconf | configure.in 是 autoconf 的腳本配置文件,它的原型文件“configure.scan”。 |
autoheader | 接著使用 autoheader 命令,它負責生成 config.h.in 文件。 |
automake | automake 要用的腳本配置文件是 Makefile.am,用戶需要自己創建相應的文件。之后,automake 工具轉換成Makefile.in。 |
configure | 在這一步中,通過運行自動配置設置文件 configure,把 Makefile.in 變成了最終的Makefile。 |
?鏈接器主要有兩個作用,一是將若干輸入文件(.o文件)根據一定規則合并為一個輸出文件(例如ELF格式的可執行文件);二是將符號與地址綁定(當然加載器也要完成這一部分工作)。
?如果沒有為程序提供一個鏈接器腳本,鏈接器將會使用默認的編譯在鏈接器執行文件內部的腳本。可以使用命令’–verbose’顯示默認的鏈接腳本。通過在命令行使用’-T’命令使用自己的腳本。如果使用此命令,你的鏈接腳本將會替代默認鏈接腳本。
?一個可執行的程序通常是由:代碼段,數據段,bss段構成的。同樣,在用于鏈接這個程序的連接器腳本中,就會反映出這幾個段的信息。最簡單的可能的腳本只有一個命令:’SECTIONS’。
SECTIONS {
. = 0x30000000; //起始鏈接地址
.text : //代碼段
{
head.o(.text) //保證head.o首先被鏈接,也就是程序執行的時候先執行這部代碼
init.o(.text)
nand.o(.text)
*(.text)
}
.rodata ALIGN(4) : //只讀數據段,字節對齊
{*(.rodata*)}
.data ALIGN(4) : //可讀寫且需要初始化數據,字節對齊
{ *(.data) }
__bss_start = .; //把當前地址存入bss_start這個變量中,可讀寫的置零初始化數據bss段
.bss ALIGN(4) :
{ *(.bss) *(COMMON) }
__bss_end = .; //把當前地址存入bss_end這個變量中
}
參考文獻:
嵌入式Linux系統開發完全手冊_基于4412_上冊
Linux下的C編程基礎
LD說明文檔--3.LD鏈接腳本
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。