溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

04-ARM裸機(jī)開發(fā)的命令行工具

發(fā)布時間:2020-07-13 13:53:53 來源:網(wǎng)絡(luò) 閱讀:2510 作者:少年不在了 欄目:系統(tǒng)運(yùn)維

一、交叉編譯工具的使用

?在進(jìn)行嵌入式開發(fā)時,通常有宿主機(jī)與目標(biāo)機(jī)的角色之分,宿主機(jī)是執(zhí)行編譯、鏈接嵌入式軟件的計算機(jī),而目標(biāo)機(jī)是運(yùn)行嵌入式軟件的硬件平臺。而這兩者之間有時硬件/軟件平臺可能不同,在宿主機(jī)上直接使用編譯器的程序在目標(biāo)機(jī)上無法運(yùn)行,因此就出現(xiàn)了交叉編譯工具。在針對ARM架構(gòu)上運(yùn)行的Linux目標(biāo)機(jī)來說,其專用的交叉編譯工具為arm-linux-gcc、arm-linux-ld等。

04-ARM裸機(jī)開發(fā)的命令行工具
?一個 C/C++文件要經(jīng)過預(yù)處理(preprocessing)、編譯(compilation)、匯編(assembly)和連接(linking)等 4 步才能變成可執(zhí)行文件。其每一步的作用在下表中進(jìn)行了說明:

步驟 說明
預(yù)處理 C/C++源文件中,以“ #”開頭的命令被稱為預(yù)處理命令,如包含命令“ #include”、宏定義命令“ #define”、條件編譯命令“ #if”、“ #ifdef”等。預(yù)處理就是將要包含(include)的文件插入原文件中、將宏定義展開、根據(jù)條件編譯命令選擇要使用的代碼,最后將這些東西輸出到一個“ .i”文件中等待進(jìn)一步處理。
編譯 編譯就是把 C/C++代碼(比如上述的“ .i”文件)“ 翻譯” 成匯編代碼。
匯編 匯編就是將第二步輸出的匯編代碼翻譯成符合一定格式的機(jī)器代碼,在 Linux 系統(tǒng)上一般表現(xiàn)為 ELF 目標(biāo)文件(OBJ 文件)。
鏈接 鏈接就是將上步生成的 OBJ 文件和系統(tǒng)庫的 OBJ 文件、 庫文件連接起來,最終生成了可以在特定平臺運(yùn)行的可執(zhí)行文件。

?編譯器利用上述四個步驟中的一個或多個來處理輸入文件,源文件的后綴表示源文件所用的語言,后綴控制編譯器的缺省動作。

后綴名 語言種類
.c C源程序
.i 預(yù)處理后的c文件
.s或.S 匯編語言源程序
.h 頭文件
.o 匯編后對象文件,包含了對各個函數(shù)的入口標(biāo)記,描述,當(dāng)程序要執(zhí)行時還需要鏈接(link).鏈接就是把多個.o文件鏈成一個可執(zhí)行文件

?在交叉編譯工具里經(jīng)常用到的命令有:

命令 介紹
arm-linux-gcc 編譯器
arm-linux-ld 鏈接器
arm-linux-objdump 反匯編工具
arm-linux-readelf elf文件查看器
arm-linux-objcopy 文件轉(zhuǎn)換工具

1.arm-linux-gcc
常用選項:

 -E:讓編譯器在預(yù)處理后停止編譯過程
 -o file:指定輸出文件為 file
 -S:只進(jìn)行編譯而不進(jìn)行匯編,生成匯編代碼
 -c:將匯編代碼轉(zhuǎn)化為“.o”的二進(jìn)制目標(biāo)代碼(-c可以一次性完成前三部工作)

2.arm-linux-ld
用于將多個目標(biāo)文件、庫文件連接成可執(zhí)行文件,常用選項:

 object-file-name:默認(rèn)是是OBJ 文件或庫文件(根據(jù)文件內(nèi)容,連接器能夠區(qū)分 OBJ 文件和庫文件)。如果 GCC 執(zhí)行連接操作,這些 OBJ 文件將成為連接器的輸入文件。
 -llibrary:連接名為 library 的庫文件。
 -nostdlib:不連接系統(tǒng)標(biāo)準(zhǔn)啟動文件和標(biāo)準(zhǔn)庫文件,只把指定的文件傳遞給連接器。這個選項常用于編譯內(nèi)核、 bootloader 等程序,它們不需要啟動文件、標(biāo)準(zhǔn)庫文件。
 -static:在支持動態(tài)連接(dynamic linking)的系統(tǒng)上,阻止連接共享庫。
 -shared:生成一個共享 OBJ 文件,它可以和其他 OBJ 文件連接產(chǎn)生可執(zhí)行文件。只有部分系統(tǒng)支持該選項。
 -T:只在連接 Bootloader、內(nèi)核等沒有底層軟件支持的軟件;連接運(yùn)行于操作系統(tǒng)之上的應(yīng)用程序時, 無需指定-T。

3.arm-linux-objcopy
被用來拷貝一個目標(biāo)文件的內(nèi)容到另一個文件中, 可以使用不同于源文件的格式來輸出目的文件,即可以進(jìn)行格式轉(zhuǎn)換。

 input-file、outfile:分別表示輸入目標(biāo)文件(源目標(biāo)文件)和輸出目標(biāo)文件(目的目標(biāo)文件)
 -I bfdname:用來指明源文件的格式, bfdname 是 BFD 庫中描述的標(biāo)準(zhǔn)格式名
 -O bfdname :使用指定的格式來輸出文件, bfdname 是 BFD 庫中描述的標(biāo)準(zhǔn)格式名
 -F bfdname :同時指明源文件、目的文件的格式
 -R sectionname:從輸出文件中刪掉所有名為 sectionname 的段。
 -S :不從源文件中拷貝重定位信息和符號信息到目標(biāo)文件中去
 -g :不從源文件中拷貝調(diào)試符號到目標(biāo)文件中去

在編譯 bootloader、 內(nèi)核時,常用 arm-linux-objcopy 命令將 ELF 格式的生成結(jié)果轉(zhuǎn)換為二進(jìn)制文件,比如:
$ arm-linux-objcopy -O binary -S elf_file bin_file
4.arm-linux-objdump
用于顯示二進(jìn)制文件信息。

 -b bfdname :指定目標(biāo)碼格式??梢允褂谩?arm-linux-objdump –i”命令查看支持的目標(biāo)碼格式列表。
 -disassemble :反匯編可執(zhí)行段(executable sections)。
 -disassemble-all :與-d 類似,反匯編所有段。
 -EB :指定字節(jié)序。
 --file-headers :顯示文件的整體頭部摘要信息。
 --section-headers:顯示目標(biāo)文件各個段的頭部摘要信息。
 -info :顯示支持的目標(biāo)文件格式和 CPU 架構(gòu),它們在“ -b”、“ -m”選項中用到。
 --section=name :僅僅顯示指定 section 的信息。
 --architecture=machine :指定反匯編目標(biāo)文件時使用的架構(gòu),當(dāng)待反匯編文件本身沒有描述架構(gòu)信息的時候(比如S-records),這個選項很有用。

5.arm-linux-readelf

-a 應(yīng)用程序    可查看文件運(yùn)行架構(gòu)、大小端、共享庫等信息。針對編譯時加上"-static"選項的應(yīng)用程序。
-d 應(yīng)用程序    可查看應(yīng)用程序的動態(tài)鏈接庫

二、Makefile工程管理器

?當(dāng)一個項目有上百個文件的代碼構(gòu)成的項目,如果其中只有一個或少數(shù)幾個文件進(jìn)行了修改,使用Gcc 編譯工具,就不得不把這所有的文件重新編譯一遍,因為編譯器并不知道哪些文件是最近更新的,只有全部重新才能得到可執(zhí)行文件。
?但是編譯過程是分為編譯、匯編、鏈接不同階段的,其中編譯階段僅檢查語法錯誤以及函數(shù)與變量的聲明是否正確聲明了,在鏈接階段則主要完成是函數(shù)鏈接和全局變量的鏈接。因此,那些沒有改動的源代碼根本不需要重新編譯,而只要把它們重新鏈接進(jìn)去就可以了。而Make工程管理器能夠自動識別更新了的文件代碼,同時又不需要重復(fù)輸入冗長的命令行。
?Make 工程管理器也就是個“自動編譯管理器” ,它能夠根據(jù)文件時間戳自動發(fā)現(xiàn)更新過的文件而減少編譯的工作量,同時,它通過讀入 Makefile 文件的內(nèi)容來執(zhí)行大量的編譯工作。
1.Makefile的構(gòu)成
?Makefile 是 Make 讀入的惟一配置文件,在一個 Makefile 中通常包含如下內(nèi)容:
· 需要由 make 工具創(chuàng)建的目標(biāo)體(target) ,通常是目標(biāo)文件或可執(zhí)行文件;
· 要創(chuàng)建的目標(biāo)體所依賴的文件(dependency_file) ;
· 創(chuàng)建每個目標(biāo)體時需要運(yùn)行的命令(command) 。

target: dependency_files
    command
如:
hello.o: hello.c hello.h
    gcc –c hello.c –o hello.o

2.Makefile的變量
?變量是在 Makefile 中定義的名字,用來代替一個文本字符串,該文本字符串稱為該變量的值。在具體要求下,這些值可以代替目標(biāo)體、依賴文件、命令以及 makefile 文件中其他部分。在Makefile 中的變量定義有兩種方式:一種是遞歸展開方式,另一種是簡單方式。
?遞歸展開方式定義的變量是在引用在該變量時進(jìn)行替換的,即如果該變量包含了對其他變量的應(yīng)用,則在引用該變量時一次性將內(nèi)嵌的變量全部展開,缺點(diǎn)是不能在變量后追加內(nèi)容(因為語句:CFLAGS = $(CFLAGS) -O 在變量擴(kuò)展過程中可能導(dǎo)致無窮循環(huán)) 。簡單擴(kuò)展型變量的值在定義處展開,并且只展開一次,因此它不包含任何對其他變量的引用,從而消除變量的嵌套引用。
遞歸展開方式的定義格式為:VAR=var。
簡單擴(kuò)展方式的定義格式為:VAR:=var。
Make 中的變量使用均使用格式為:$(VAR)。
?預(yù)定義變量包含了常見編譯器、匯編器的名稱及其編譯選項:

命令格式 含義
AR 庫文件維護(hù)程序的名稱,默認(rèn)值為 ar
AS 匯編程序的名稱,默認(rèn)值為 as
CC C 編譯器的名稱,默認(rèn)值為 cc
CPP C 預(yù)編譯器的名稱,默認(rèn)值為$(CC) –E
CXX C++編譯器的名稱,默認(rèn)值為 g++
FC FORTRAN 編譯器的名稱,默認(rèn)值為 f77
RM 文件刪除程序的名稱,默認(rèn)值為 rm –f
ARFLAGS 庫文件維護(hù)程序的選項,無默認(rèn)值
ASFLAGS 匯編程序的選項,無默認(rèn)值
CFLAGS C 編譯器的選項,無默認(rèn)值
CPPFLAGS C 預(yù)編譯的選項,無默認(rèn)值
CXXFLAGS C++編譯器的選項,無默認(rèn)值
FFLAGS FORTRAN 編譯器的選項,無默認(rèn)值

Makefile 中常見自動變量

命 令 格 式 含 義
$* 不包含擴(kuò)展名的目標(biāo)文件名稱
$+ 所有的依賴文件,以空格分開,并以出現(xiàn)的先后為序,可能包含重復(fù)的依賴文件
$< 第一個依賴文件的名稱
$@ 目標(biāo)文件的完整名稱
$^ 所有不重復(fù)的依賴文件,以空格分開
$% 如果目標(biāo)是歸檔成員,則該變量表示目標(biāo)的歸檔成員名稱
$? 所有時間戳比目標(biāo)文件晚的依賴文件,并以空格分開

3.Makefile 規(guī)則
?Makefile 的規(guī)則是 Make 進(jìn)行處理的依據(jù),它包括了目標(biāo)體、依賴文件及其之間的命令語句。一般的,Makefile 中的一條語句就是一個規(guī)則。但為了簡化 Makefile 的編寫,make 還定義了隱式規(guī)則和模式規(guī)則。
?隱含規(guī)則能夠告訴 make 怎樣使用傳統(tǒng)的技術(shù)完成任務(wù),這樣,當(dāng)用戶使用它們時就不必詳細(xì)指定編譯的具體細(xì)節(jié),而只需把目標(biāo)文件列出即可。下面的Makefile中kang.o與yul.o的生成過程即可以省略。

OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
    $(CC) $^ -o $@

Makefile 中常見隱式規(guī)則目錄

對應(yīng)語言后綴名 規(guī) 則
C 編譯:.c 變?yōu)?o $(CC) –c $(CPPFLAGS) $(CFLAGS)
C++編譯:.cc 或.C 變?yōu)?o $(CXX) -c $(CPPFLAGS) $(CXXFLAGS)
Pascal 編譯:.p 變?yōu)?o $(PC) -c $(PFLAGS)
Fortran 編譯:.r 變?yōu)?o $(FC) -c $(FFLAGS)

?模式規(guī)則是用來定義相同處理規(guī)則的多個文件的。它不同于隱式規(guī)則,隱式規(guī)則僅僅能夠用 make 默認(rèn)的變量來進(jìn)行操作,而模式規(guī)則還能引入用戶自定義變量,為多個文件建立相同的規(guī)則,從而簡化 Makefile 的編寫。模式規(guī)則的格式類似于普通規(guī)則,這個規(guī)則中的相關(guān)文件前必須用“%”標(biāo)明。

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 讀入當(dāng)前目錄下的 file 文件作為 Makefile
-i 忽略所有的命令執(zhí)行錯誤
-I dir 指定被包含的 Makefile 所在目錄
-n 只打印要執(zhí)行的命令,但不執(zhí)行這些命令
-p 顯示 make 變量數(shù)據(jù)庫和隱含規(guī)則
-s 在執(zhí)行命令時不顯示命令
-w 如果 make 在執(zhí)行過程中改變目錄,則打印當(dāng)前目錄名

5.makefile中常用函數(shù)
?函數(shù)調(diào)用的格式為:$(function arguments)
?這里function 是函數(shù)名, arguments是該函數(shù)的參數(shù)。參數(shù)和函數(shù)名之間是用空格或 Tab 隔開,如果有多個參數(shù),它們之間用逗號隔開。這些空格和逗號不是參數(shù)值的一部分。
字符串替換和分析函數(shù):

函數(shù) 含義
$(subst from,to,text) 在文本text中使用to 替換每一處from.
$(patsubst pattern,replacement,text) 尋找text中符合格式pattern的字,用replacement替換它們.pattern和replacement 中可以使用通配符。
$(strip string) 去掉前導(dǎo)和結(jié)尾空格,并將中間的多個空格壓縮為單個空格。
$(findstring find,in) 在字符串in 中搜尋find,如果找到,則返回值是find ,否則返回值為空。
$(filter pattern...,text) 返 回 在 text 中 由 空 格 隔 開 且 匹 配 格 式 pattern... 的 字 , 去 除 不 符 合 格 式pattern... 的字。
$(filter-out pattern...,text) 返 回 在 text中 由 空 格 隔 開 且 不 匹 配 格 式 pattern...的 字 , 去 除 符 合 格 式pattern... 的字。
$(sort list) 將 list中的字按字母順序排序,并去掉重復(fù)的字。輸出由單個空格隔開的字的列表。

文件名函數(shù):

函數(shù) 含義
$(dir names...) 抽取names...中每一個文件名的路徑部分,文件名的路徑部分包括從文件名的首字符到最后一個斜杠(含斜杠)之前的一切字符。
$(notdir names...) 抽取names...中每一個文件名中除路徑部分外一切字符(真正的文件名)。
$(suffix names...) 抽取names...中每一個文件名的后綴。
$(basename names...) 抽取names...中每一個文件名中除后綴外一切字符。
$(addsuffix suffix,names...) 參數(shù)names...是一系列的文件名,文件名之間用空格隔開; suffix 是一個后綴名。將 suffix(后綴)的值附加在每一個獨(dú)立文件名的后面,完成后將文件名串聯(lián)起來,它們之間用單個空格隔開。
$(addprefix prefix,names...) 參數(shù) names是一系列的文件名,文件名之間用空格隔開; prefix 是一個前綴名。將preffix(前綴)的值附加在每一個獨(dú)立文件名的前面,完成后將文件名串聯(lián)起來,它們之間用單個空格隔開。
$(wildcard pattern) 參數(shù)pattern是一個文件名格式,包含有通配符(通配符和 shell 中的用法一樣)。函數(shù) wildcard 的結(jié)果是一列和格式匹配的且真實存在的文件的名稱,文件名之間用一個空格隔開。

6.使用 autotools
?編寫 Makefile 不是一件輕松的事,尤其對于一個較大的項目而言更是如此。autotools 系列工具只需用戶輸入簡單的目標(biāo)文件、依賴文件、文件目錄等就可以輕松地生成 Makefile 。另外,這些工具還可以完成系統(tǒng)配置信息的收集,從而可以方便地處理各種移植性的問題。autotools 是系列工具主要包含:aclocal、autoscan、autoconf、autoheader、automake。
?使用 autotools 主要就是利用各個工具的腳本文件以生成最后的 Makefile。其總體流程是:
· 使用 aclocal 生成一個“aclocal.m4”文件,該文件主要處理本地的宏定義;
· 改寫“configure.scan”文件,并將其重命名為“configure.in” ,并使用 autoconf 文件生成 configure 文件。

命令 執(zhí)行過程
autoscan 它會在給定目錄及其子目錄樹中檢查源文件,若沒有給出目錄,就在當(dāng)前目錄及其子目錄樹中進(jìn)行檢查。它會搜索源文件以尋找一般的移植性問題并創(chuàng)建一個文件“configure.scan” 。
autoconf configure.in 是 autoconf 的腳本配置文件,它的原型文件“configure.scan”。
autoheader 接著使用 autoheader 命令,它負(fù)責(zé)生成 config.h.in 文件。
automake automake 要用的腳本配置文件是 Makefile.am,用戶需要自己創(chuàng)建相應(yīng)的文件。之后,automake 工具轉(zhuǎn)換成Makefile.in。
configure 在這一步中,通過運(yùn)行自動配置設(shè)置文件 configure,把 Makefile.in 變成了最終的Makefile。

04-ARM裸機(jī)開發(fā)的命令行工具

三、鏈接器器腳本

?鏈接器主要有兩個作用,一是將若干輸入文件(.o文件)根據(jù)一定規(guī)則合并為一個輸出文件(例如ELF格式的可執(zhí)行文件);二是將符號與地址綁定(當(dāng)然加載器也要完成這一部分工作)。
?如果沒有為程序提供一個鏈接器腳本,鏈接器將會使用默認(rèn)的編譯在鏈接器執(zhí)行文件內(nèi)部的腳本。可以使用命令’–verbose’顯示默認(rèn)的鏈接腳本。通過在命令行使用’-T’命令使用自己的腳本。如果使用此命令,你的鏈接腳本將會替代默認(rèn)鏈接腳本。
?一個可執(zhí)行的程序通常是由:代碼段,數(shù)據(jù)段,bss段構(gòu)成的。同樣,在用于鏈接這個程序的連接器腳本中,就會反映出這幾個段的信息。最簡單的可能的腳本只有一個命令:’SECTIONS’。

SECTIONS {
    . = 0x30000000;           //起始鏈接地址
    .text :                            //代碼段
    {
        head.o(.text)              //保證head.o首先被鏈接,也就是程序執(zhí)行的時候先執(zhí)行這部代碼  
        init.o(.text)
        nand.o(.text)
        *(.text) 
    }
    .rodata ALIGN(4) :      //只讀數(shù)據(jù)段,字節(jié)對齊
        {*(.rodata*)} 
    .data   ALIGN(4) :        //可讀寫且需要初始化數(shù)據(jù),字節(jié)對齊
        { *(.data) }
    __bss_start = .;          //把當(dāng)前地址存入bss_start這個變量中,可讀寫的置零初始化數(shù)據(jù)bss段
        .bss ALIGN(4)  :
        { *(.bss)  *(COMMON) }
    __bss_end = .;           //把當(dāng)前地址存入bss_end這個變量中
}

參考文獻(xiàn):
嵌入式Linux系統(tǒng)開發(fā)完全手冊_基于4412_上冊
Linux下的C編程基礎(chǔ)
LD說明文檔--3.LD鏈接腳本

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI