這些工具完成將源代碼編譯,鏈接成可執(zhí)行代碼的功能。ADS提供下面的命令行開(kāi)發(fā)工具:armccarmcc是ARM C編譯器。這個(gè)編譯器通過(guò)了Plum Hall C Validation Suite為ANSI C的一致性測(cè)試。armcc用于將用ANSI C編寫(xiě)的程序編譯成32位ARM指令代碼。因?yàn)閍rmcc是我們最常用的編譯器,所以對(duì)此作一個(gè)詳細(xì)的介紹。在命令控制臺(tái)環(huán)境下,輸入命令:armcc –help可以查看armcc的語(yǔ)法格式以及最常用的一些操作選項(xiàng)armcc最基本的用法為: armcc [options] file1 file2 ... filen這里的option是編譯器所需要的選項(xiàng),fiel1,file2…filen是相關(guān)的文件名。 這里簡(jiǎn)單介紹一些最常用的操作選項(xiàng)。-c:表示只進(jìn)行編譯不鏈接文件; -C:(注意:這是大寫(xiě)的C)禁止預(yù)編譯器將注釋行移走;-D<symbol>:定義預(yù)處理宏,相當(dāng)于在源程序開(kāi)頭使用了宏定義語(yǔ)句#define symbol ,這里symbol默認(rèn)為1;-E:僅僅是對(duì)C源代碼進(jìn)行預(yù)處理就停止;-g<options>:指定是否在生成的目標(biāo)文件中包含調(diào)試信息表;-I<directory>:將directory所指的路徑添加到#include的搜索路徑列表中去; -J<directory>:用directory所指的路徑代替默認(rèn)的對(duì)#include的搜索路徑;-o<file>:指定編譯器最終生成的輸出文件名。-O0:不優(yōu)化;-O1:這是控制代碼優(yōu)化的編譯選項(xiàng),大寫(xiě)字母O后面跟的數(shù)字不同,表示的優(yōu)化級(jí)別就不同,-O1關(guān)閉了影響調(diào)試結(jié)果的優(yōu)化功能;-O2:該優(yōu)化級(jí)別提供了最大的優(yōu)化功能;-S:對(duì)源程序進(jìn)行預(yù)處理和編譯,自動(dòng)生成匯編文件而不是目標(biāo)文件;-U<symbol>:取消預(yù)處理宏名,相當(dāng)于在源文件開(kāi)頭,使用語(yǔ)句#undef symbol;-W<options>:關(guān)閉所有的或被選擇的警告信息;有關(guān)更詳細(xì)的選項(xiàng)說(shuō)明,讀者可查看ADS軟件的在線(xiàn)幫助文件。armcpparmcpp是ARM C++編譯器。它將ISO C++ 或EC++ 編譯成32位ARM指令代碼。tcctcc是Thumb C 編譯器。該編譯器通過(guò)了Plum Hall C Validation Suite為ANSI 一致性的測(cè)試。tcc將ANSI C源代碼編譯成16位的Thumb指令代碼。tcpptcpp是Thumb C++ 編譯器。 它將ISO C++ 和EC++ 源碼編譯成16位Thumb指令代碼。armasmarmasm是ARM和Thumb的匯編器. 它對(duì)用ARM 匯編語(yǔ)言和Thumb 匯編語(yǔ)言寫(xiě)的源代碼進(jìn)行匯編。armlinkarmlink是ARM連接器。該命令既可以將編譯得到的一個(gè)或多個(gè)目標(biāo)文件和相關(guān)的一個(gè)或多個(gè)庫(kù)文件進(jìn)行鏈接,生成一個(gè)可執(zhí)行文件,也可以將多個(gè)目標(biāo)文件部分鏈接成一個(gè)目標(biāo)文件,以供進(jìn)一步的鏈接。ARM鏈接器生成的是ELF格式的可執(zhí)行映像文件。armsdarmsd是ARM 和Thumb的符號(hào)調(diào)試器。它能夠進(jìn)行源碼級(jí)的程序調(diào)試。用戶(hù)可以在用C或匯編語(yǔ)言寫(xiě)的代碼中進(jìn)行單步調(diào)試,設(shè)置斷點(diǎn),查看變量值和內(nèi)存單元的內(nèi)容。
工程將所有的源碼文件組織在一起,并能夠決定最終生成文件存放的路徑,輸出的格式等。在CodeWarrior中新建一個(gè)工程的方法有兩種,可以在工具欄中單擊“New”按鈕,也可以在“File”菜單中選擇“New…”菜單。這樣就會(huì)打開(kāi)一個(gè)如圖8.1所示的對(duì)話(huà)框。圖8.1 新建工程對(duì)話(huà)框在這個(gè)對(duì)話(huà)框中為用戶(hù)提供了7種可選擇的工程類(lèi)型。ARM Executabl Image:用于由ARM指令的代碼生成一個(gè)ELF格式的可執(zhí)行映像文件;ARM Object Library:用于由ARM指令的代碼生成一個(gè)armar格式的目標(biāo)文件庫(kù);Empty Project:用于創(chuàng)建一個(gè)不包含任何庫(kù)或源文件的工程;Makefile Importer Wizard:用于將Visual C的nmake或GNU make文件轉(zhuǎn)入到CodeWarrior IDE 工程文件;Thumb ARM Executable Image:用于由ARM指令和Thumb指令的混和代碼生成一個(gè)可執(zhí)行的ELF格式的映像文件;Thumb Executable image:用于由Thumb指令創(chuàng)建一個(gè)可執(zhí)行的ELF格式的映像文件;Thumb Object Library:用于由Thumb指令的代碼生成一個(gè)armar格式的目標(biāo)文件庫(kù)。在這里選擇ARM Executable Image,在“Project name:”中輸入工程文件名,本例為“l(fā)edcircle”,點(diǎn)擊“Location:”文本框的“Set…”按鈕,瀏覽選擇想要將該工程保存的路徑,將這些設(shè)置好后,點(diǎn)擊“確定”,即可建立一個(gè)新的名為ledcircle的工程。這個(gè)時(shí)候會(huì)出現(xiàn)ledcircle.mcp的窗口,如圖8.2所示,有三個(gè)標(biāo)簽頁(yè),分別為files,link order,target默認(rèn)的是顯示第一個(gè)標(biāo)簽頁(yè)files。通過(guò)在該標(biāo)簽頁(yè)點(diǎn)擊鼠標(biāo)右鍵,選中“Add Files…”可以把要用到的源程序添加到工程中。圖8.2 新建工程打開(kāi)窗口對(duì)于本例,由于所有的源文件都還沒(méi)有建立,所以首先需要新建源文件。在“File”菜單中選擇“New”,在打開(kāi)的如圖8.1所示的對(duì)話(huà)框中,選擇標(biāo)簽頁(yè)File,在File name中輸入要?jiǎng)?chuàng)建的文件名,輸入“Init.s”,點(diǎn)擊“確定”關(guān)閉窗口。在打開(kāi)的文件編輯框中輸入下面的匯編代碼:;**************************************************************;Chinese Academy of Sciences, Institute of Automation;File Name: Init.s;Description: ;Author: JuGuang.Li;Date: ;************************************************************** IMPORT Main AREA Init,CODE,READONLY ENTRY LDR R0, =0x3FF0000 LDR R1, =0xE7FFFF80 ;配置SYSCFG,片內(nèi)4K Cache,4K SRAM STR R1, [R0] LDR SP, =0x3FE1000 ;SP指向4K SRAM的尾地址,堆棧向下生成 BL Main B . END在這段代碼中,偽操作IMPORT告訴編譯器符號(hào)Main不是在該文件中定義的,而是在其他源文件中定義的符號(hào),但是本源文件中可能要用到該符號(hào)。接下來(lái)用偽指令A(yù)REA定義段名為Init的段為只讀的代碼段,偽指令ENTRY指出了程序的入口點(diǎn)。下面就是用匯編指令實(shí)現(xiàn)了配置SYSCFG特殊功能寄存器,將S3C4510B片內(nèi)的8K一體化的SRAM配置為4K Cache,4K SRAM,并將用戶(hù)堆棧設(shè)置在片內(nèi)的SRAM中。4K SRAM的地址為0x3FE,0000~(0x3FE,1000-1),由于S3C4510B的堆棧由高地址向低地址生成,將SP初始化為0x3FE,1000。完成上述操作后,程序跳轉(zhuǎn)到Main函數(shù)執(zhí)行。保存Init.s匯編程序。用同樣的方法,再建立一個(gè)名為main.c的C源代碼文件。具體代碼內(nèi)容如下://*****************************************************************//Chinese Academy of Sciences, Institute of Automation//File Name: main.c//Description: //Author: JuGuang.Li//Date: //***************************************************************#define IOPMOD (*(volatile unsigned *)0x03FF5000) //IO port mode register#define IOPDATA (*(volatile unsigned *)0x03FF5008) //IO port data registervoid Delay(unsigned int);int Main(){unsigned long LED;IOPMOD=0xFFFFFFFF; //將IO口置為輸出模式IOPDATA=0x01;for(;;){ LED=IOPDATA; LED=(LED<<1); IOPDATA=LED; Delay(10); if(!(IOPDATA&0x0F)) IOPDATA=0x01;}return(0); }void Delay(unsigned int x){unsigned int i,j,k;for(i=0;i<=x;i++) for(j=0;j<0xff;j++) for(k=0;k<0xff;k++);} 該段代碼首先將I/O模式寄存器設(shè)置為輸出模式,為I/O數(shù)據(jù)寄存器賦初值為0x1,通過(guò)將I/O數(shù)據(jù)寄存器的數(shù)值進(jìn)行周期性的左移,實(shí)現(xiàn)使接在P0~P3口的LED顯示器輪流被點(diǎn)亮的功能。(注意這里的if語(yǔ)句,是為了保證當(dāng)I/O數(shù)據(jù)寄存器中的數(shù)在移位過(guò)程中,第4位為數(shù)字“1”時(shí),使數(shù)字1通過(guò)和0xFF相與,又重新回到I/O數(shù)據(jù)寄存器的第0位,從而保證了數(shù)字1一直在I/O數(shù)據(jù)寄存器的低四位之間移位。)在這里還有一個(gè)細(xì)節(jié),希望讀者注意。在建立好一個(gè)工程時(shí),默認(rèn)的target是DebugRel,還有另外兩個(gè)可用的target,分別為Realse和Debug,這三個(gè)target的含義分別為:DebugRel:使用該目標(biāo),在生成目標(biāo)的時(shí)候,會(huì)為每一個(gè)源文件生成調(diào)試信息;Debug:使用該目標(biāo)為每一個(gè)源文件生成最完全的調(diào)試信息;Release:使用該目標(biāo)不會(huì)生成任何調(diào)試信息。在本例中,使用默認(rèn)的DebugRel目標(biāo)。現(xiàn)在已經(jīng)新建了兩個(gè)源文件,要把這兩個(gè)源文件添加到工程中去。為工程添加源碼常用的方法有兩種,既可以使用入圖8.2所示方法,也可以在“Project”菜單項(xiàng)中,選擇“Add Files…”,這兩種方法都會(huì)打開(kāi)文件瀏覽框,用戶(hù)可以把已經(jīng)存在的文件添加到工程中來(lái)。當(dāng)選中要添加的文件時(shí),會(huì)出現(xiàn)一個(gè)對(duì)話(huà)框,如圖8.3所示,詢(xún)問(wèn)用戶(hù)把文件添加到何類(lèi)目標(biāo)中,在這里,我們選擇DebugRel目標(biāo)。把剛才創(chuàng)建的兩個(gè)文件添加到工程中來(lái)。圖8.3 選擇添加文件到指定目標(biāo)到目前為止,一個(gè)完整的工程已經(jīng)建立。下面該對(duì)工程進(jìn)行編譯和鏈接工作。
8.2.2 編譯和鏈接工程
在進(jìn)行編譯和鏈接前,首先講述一下如何進(jìn)行生成目標(biāo)的配置。點(diǎn)擊Edit菜單,選擇“DebugRel Settings…”(注意,這個(gè)選項(xiàng)會(huì)因用戶(hù)選擇的不同目標(biāo)而有所不同),出現(xiàn)如圖8.2所示的對(duì)話(huà)框。這個(gè)對(duì)話(huà)框中的設(shè)置很多,在這里指介紹一些最為常用的設(shè)置選項(xiàng),讀者若對(duì)其他未涉及到的選項(xiàng)感興趣,可以查看相應(yīng)的幫助文件。1. target設(shè)置選項(xiàng)Target Name文本框顯示了當(dāng)前的目標(biāo)設(shè)置。Linker選項(xiàng)供用戶(hù)選擇要使用的鏈接器。在這里默認(rèn)選擇的是ARM Linker,使用該鏈接器,將使用armlink鏈接編譯器和匯編器生成的工程中的文件相應(yīng)的目標(biāo)文件。 圖8.4 DebugRel設(shè)置對(duì)話(huà)框這個(gè)設(shè)置中還有兩個(gè)可選項(xiàng),None不是不用任何鏈接器,如果使用它,則工程中的所有文件都不會(huì)被編譯器或匯編器處理。ARM Librarian表示將編譯或匯編得到的目標(biāo)文件轉(zhuǎn)換為ARM庫(kù)文件。對(duì)于本例,使用默認(rèn)的鏈接器ARM Linker。Pre-linker:目前CodeWarrior IDE不支持該選項(xiàng)。Post-Linker:選擇在鏈接完成后,還要對(duì)輸出文件進(jìn)行的操作。因?yàn)樵诒纠,希望生成一個(gè)可以燒寫(xiě)到Flash中去的二進(jìn)制代碼,所以在這里選擇ARM fromELF,表示在鏈接生成映像文件后,再調(diào)用FromELF命令將含有調(diào)試信息的ELF格式的映像文件轉(zhuǎn)換成其他格式的文件。2. Language Settings因?yàn)楸纠邪袇R編源代碼,所以要用到匯編器。首先看ARM匯編器。這個(gè)匯編器實(shí)際就說(shuō)在8.1節(jié)中談到的armasm,默認(rèn)的ARM體系結(jié)構(gòu)是ARM7TDMI,正好符合目標(biāo)板S3C4510B,無(wú)需改動(dòng)。字節(jié)順序默認(rèn)就是小端模式。其他設(shè)置,就用默認(rèn)值即可。還有一個(gè)需要注意的就是ARM C編譯器,它實(shí)際就是調(diào)用的命令行工具armcc。使用默認(rèn)的設(shè)置就可以了。細(xì)心的讀者可能會(huì)注意到,在設(shè)置框的右下腳,當(dāng)對(duì)某項(xiàng)設(shè)置進(jìn)行了修改,該行中的某個(gè)選項(xiàng)就會(huì)發(fā)生相應(yīng)的改動(dòng),如圖8.5所示。實(shí)際上,這行文字就顯示的是在8.1中介紹的相應(yīng)的編譯或鏈接選項(xiàng),由于有了CodeWarrior,開(kāi)發(fā)人員可以不用再去查看繁多的命令行選項(xiàng),只要在界面中選中或撤消某個(gè)選項(xiàng),軟件就會(huì)自動(dòng)生成相應(yīng)的代碼,為不習(xí)慣在DOS下鍵入命令行的用戶(hù)提供了極大的方便。3. Linker設(shè)置鼠標(biāo)選中ARM Linker,出現(xiàn)如圖8.6所示對(duì)話(huà)框。這里詳細(xì)介紹該對(duì)話(huà)框的主要的標(biāo)簽頁(yè)選項(xiàng),因?yàn)檫@些選項(xiàng)對(duì)最終生成的文件有著直接的影響。在標(biāo)簽頁(yè)Output中,Linktype中提供了三種鏈接方式。Partial方式表示鏈接器只進(jìn)行部分鏈接,經(jīng)過(guò)部分鏈接生成的目標(biāo)文件,可以作為以后進(jìn)一步鏈接時(shí)的輸入文件。Simple方式是默認(rèn)的鏈接方式,也是最為頻繁使用的鏈接方式,它鏈接生成簡(jiǎn)單的ELF格式的目標(biāo)文件,使用的是鏈接器選項(xiàng)中指定的地址映射方式。Scattered方式使得鏈接器要根據(jù)scatter格式文件中指定的地址映射,生成復(fù)雜的ELF格式的映像文件。這個(gè)選項(xiàng)一般情況圖8.5 命令行工具選項(xiàng)設(shè)置圖8.6 鏈接器設(shè)置下,使用不太多。因?yàn)槲覀兯e的例子比較簡(jiǎn)單,選擇Simple方式就可以了。在選中Simple方式后,就會(huì)出現(xiàn)Simple image。RO Base:這個(gè)文本框設(shè)置包含有RO段的加載域和運(yùn)行域?yàn)橥粋(gè)地址。默認(rèn)是0x8000。這里用戶(hù)要根據(jù)自己硬件的實(shí)際SDRAM的地址空間來(lái)修改這個(gè)地址,保證在這里填寫(xiě)的地址,是程序運(yùn)行時(shí),SDRAM地址空間所能覆蓋的地址。針對(duì)本書(shū)所介紹的目標(biāo)板,就可以使用這個(gè)默認(rèn)地址值。RW Base:這個(gè)文本框設(shè)置了包含RW和ZI輸出段的運(yùn)行域地址。如果選中split選項(xiàng),鏈接器生成的映像文件將包含兩個(gè)加載域和兩個(gè)運(yùn)行域,此時(shí),在RW Base中所輸入的地址為包含RW和ZI輸出段的域設(shè)置了加載域和運(yùn)行域地址Ropi:選中這個(gè)設(shè)置將告訴鏈接器使包含有RO輸出段的運(yùn)行域位置無(wú)關(guān)。使用這個(gè)選項(xiàng),鏈接器將保證下面的操作:檢查各段之間的重定址是否有效;確保任何由armlink自身生成的代碼是只讀位置無(wú)關(guān)的。Rwpi:選中該選項(xiàng)將會(huì)告訴鏈接器使包含RW和ZI輸出段的運(yùn)行域位置無(wú)關(guān)。如果這個(gè)選項(xiàng)沒(méi)有被選中,域就標(biāo)識(shí)為絕對(duì)。每一個(gè)可寫(xiě)的輸入段必須是讀寫(xiě)位置無(wú)關(guān)的。如果這個(gè)選項(xiàng)被選中,鏈接器將進(jìn)行下面的操作,檢查可讀/可寫(xiě)屬性的運(yùn)行域的輸入段是否設(shè)置了位置無(wú)關(guān)屬性;檢查在各段之間的重地址是否有效;在Region$$Table和ZISection$$Table中添加基于靜態(tài)存儲(chǔ)器sb的選項(xiàng)。該選項(xiàng)要求RW Base有值,如果沒(méi)有給它指定數(shù)值的話(huà),默認(rèn)為0值。Split Image:選擇這個(gè)選項(xiàng)把包含RO和RW的輸出段的加載域分成2個(gè)加載域:一個(gè)是包含RO輸出段的域,一個(gè)是包含RW輸出段的域。這個(gè)選項(xiàng)要求RW Base有值,如果沒(méi)有給RW Base選項(xiàng)設(shè)置,則默認(rèn)是-RW Base 0。Relocatable:選擇這個(gè)選項(xiàng)保留了映像文件的重定址偏移量。這些偏移量為程序加載器提供了有用信息。在Options選項(xiàng)中,需要讀者引起注意的是Image entry point文本框。它指定映像文件的初始入口點(diǎn)地址值,當(dāng)映像文件被加載程序加載時(shí),加載程序會(huì)跳轉(zhuǎn)到該地址處執(zhí)行。如果需要,用戶(hù)可以在這個(gè)文本框中輸入下面格式的入口點(diǎn):入口點(diǎn)地址:這是一個(gè)數(shù)值,例如-entry 0x0符號(hào):該選項(xiàng)指定映像文件的入口點(diǎn)為該符號(hào)所代表的地址處,比如:-entry int_handler如果該符號(hào)有多處定義存在,armlink將產(chǎn)生出錯(cuò)信息。offset+object(section):該選項(xiàng)指定在某個(gè)目標(biāo)文件的段的內(nèi)部的某個(gè)偏移量處為映像文件的入口地址,例如:-entry 8+startup(startupseg)在此處指定的入口點(diǎn)用于設(shè)置ELF映像文件的入口地址。需要引起注意的是,這里不可以用符號(hào)main作為入口點(diǎn)地址符號(hào),否則將會(huì)出現(xiàn)類(lèi)似“Image dose not have an entry point(Not specified or not set due to multiple choice)”的錯(cuò)誤信息。關(guān)于ARM Linker的設(shè)置還有很多,對(duì)于想進(jìn)一步深入了解的讀者,可以查看幫助文件,都有很詳細(xì)的介紹。在Linker下還有一個(gè)ARM fromELF,如圖8.7所示:fromELF就是在8.1節(jié)中介紹的一個(gè)實(shí)用工具,它實(shí)現(xiàn)將鏈接器,編譯器或匯編器的輸出代碼進(jìn)行格式轉(zhuǎn)換的功能。例如,將ELF格式的可執(zhí)行映像文件轉(zhuǎn)換成可以燒寫(xiě)到ROM的二進(jìn)制格式文件;對(duì)輸出文件進(jìn)行反匯編,從而提取出有關(guān)目標(biāo)文件的大小,符號(hào)和字符串表以及重定址等信息。只有在Target設(shè)置中選擇了Post-linker,才可以使用該選項(xiàng)。在Output format下拉框中,為用戶(hù)提供了多種可以轉(zhuǎn)換的目標(biāo)格式,本例選擇Plain binary,這是一個(gè)二進(jìn)制格式的可執(zhí)行文件,可以被燒些的目標(biāo)板的Flash中。在Output file name文本域輸入期望生成的輸出文件存放的路徑,或通過(guò)點(diǎn)擊Choose...按鈕從文件對(duì)話(huà)框中選擇輸出文件。如果在這個(gè)文本域不輸入路徑名,則生成的二進(jìn)制文件存放在工程所在的目錄下。進(jìn)行好這些相關(guān)的設(shè)置后,以后在對(duì)工程進(jìn)行make的時(shí)候,CodeWarrior IDE 就會(huì)在鏈接完成后調(diào)用fromELF 來(lái)處理生成的映像文件。對(duì)于本例的工程而言,到此,就完成了make之前的設(shè)置工作了。圖8.7 ARM fromELF可選項(xiàng)點(diǎn)擊CodeWarrior IDE的菜單Project下的make菜單,就可以對(duì)工程進(jìn)行編譯和鏈接了。整個(gè)編譯鏈接過(guò)程如圖8.8所示:圖8.8 編譯和鏈接過(guò)程在工程ledcircle所在的目錄下,會(huì)生成一個(gè)名為:工程名_data目錄,在本例中就是ledcircle_data目錄,在這個(gè)目錄下不同類(lèi)別的目標(biāo)對(duì)應(yīng)不同的目錄。在本例中由于我們使用的是DebugRe目標(biāo),所以生成的最終文件都應(yīng)該在該目錄下。進(jìn)入到DebugRel目錄中去,讀者會(huì)看到make后生成的映像文件和二進(jìn)制文件,映像文件用于調(diào)試,二進(jìn)制文件可以燒寫(xiě)到S3C4510B的Flash中運(yùn)行。