嵌入式系統(tǒng)原理與應(yīng)用 第3版 課件 第4章 微處理器ARM程序設(shè)計(jì)_第1頁
嵌入式系統(tǒng)原理與應(yīng)用 第3版 課件 第4章 微處理器ARM程序設(shè)計(jì)_第2頁
嵌入式系統(tǒng)原理與應(yīng)用 第3版 課件 第4章 微處理器ARM程序設(shè)計(jì)_第3頁
嵌入式系統(tǒng)原理與應(yīng)用 第3版 課件 第4章 微處理器ARM程序設(shè)計(jì)_第4頁
嵌入式系統(tǒng)原理與應(yīng)用 第3版 課件 第4章 微處理器ARM程序設(shè)計(jì)_第5頁
已閱讀5頁,還剩70頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第4章微處理器ARM編程程序設(shè)計(jì)不但要掌握處理器的指令功能與使用,還必須借助ARM的集成開發(fā)環(huán)境進(jìn)行程序的代碼編輯、編譯、和調(diào)試運(yùn)行。為了提高編程效率,縮短開發(fā)周期,還必須學(xué)會使用C/C++語言進(jìn)行程序設(shè)計(jì)。這就要求我們掌握ARM9匯編語言偽指令、匯編語言程序的語法結(jié)構(gòu)、ARM處理器的C語言編程、匯編語言與C語言混合編程的ATPCS規(guī)則等。本章主要講述ARM偽指令、ARM匯編語言程序設(shè)計(jì)、ARM匯編語言與C語言的混合編程以及子程序或函數(shù)之間的相互調(diào)用。最后通過實(shí)例講述ARM匯編語言與C語言之間的參數(shù)傳遞方法、程序之間的相互調(diào)用等。124.1ARM匯編偽指令A(yù)RM匯編語言源程序是由偽指令、ARM指令和宏指令組成。偽指令完成的操作稱為偽操作。偽指令的定義:在ARM匯編語言程序里,有一些特殊指令助記符,這些特殊的助記符與指令系統(tǒng)的助記符不同,沒有相對應(yīng)的操作碼,也就是不會生成機(jī)器碼,僅僅是在編譯軟件中起著格式化的作用,通常稱這些特殊指令助記符為偽指令。偽指令的作用:是為完成匯編程序作各種準(zhǔn)備工作的,這些偽指令僅在匯編過程中起作用,一旦匯編結(jié)束,偽指令的使命就結(jié)束了。宏指令:實(shí)際上是一段獨(dú)立的程序代碼,在匯編程序中通過宏名來調(diào)用,而在程序被匯編時(shí),調(diào)用的宏將被展開,用宏的定義體代替宏名。因此宏可以使程序代碼更加簡潔直觀,是用指令占用的空間換取執(zhí)行的時(shí)間。ARM匯編可以在Windows操作系統(tǒng)下的ADS1.2集成開發(fā)環(huán)境中進(jìn)行,也可以在Linux操作系統(tǒng)下的GUN開發(fā)環(huán)境中進(jìn)行。以下介紹ADS1.2開發(fā)環(huán)境中ARM匯編器中使用的偽指令。34.1.1數(shù)據(jù)常量定義偽指令數(shù)據(jù)常量定義偽指令EQU用于為程序中的常量、標(biāo)號等定義一個(gè)等效的字符名稱,類似于C語言中的#define。EQU語法格式如下:

常量名稱EQU表達(dá)式{,類型}

其中:名稱為EQU偽指令定義的字符名稱,當(dāng)表達(dá)式為32位的常量時(shí),可以指定表達(dá)式的數(shù)據(jù)類型,可以使用以下三種類型:CODE16、CODE32和DATA

。EQU可用符號“*”代替。應(yīng)用示例:Data_inEQU200;定義標(biāo)號Data_in的值為200

,AddrEQU0xff,CODE32;

定義標(biāo)號Addr的值為0xff,且該處為32位的ARM指令地址

注意:EQU可以定義字節(jié)、半字、字長度的數(shù)據(jù)值,也可以認(rèn)為是常數(shù),主要在于應(yīng)用的場合;也可以定義32位的地址值等。44.1.2數(shù)據(jù)變量定義偽指令數(shù)據(jù)變量定義偽指令用于定義ARM匯編程序中的變量、對變量賦值以及定義寄存器的別名等操作。全局變量偽指令GBLA、GBLL和GBLS全局變量一般是指在這個(gè)匯編程序中定義,需要在另外一個(gè)匯編程序中應(yīng)用的變量。GBLA(GBLL或GBLS)全局變量名GBLA用于定義一個(gè)全局的數(shù)字變量,并初始化為0。GBLL用于定義一個(gè)全局的邏輯變量,并初始化F。GBLS用于定義一個(gè)全局的字符串變量,并初始化為空。應(yīng)用示例:(說明全局變量名必須唯一)GBLAVariable1;定義全局的數(shù)字變量,變量名為Variable1GBLLVariable2;定義全局的邏輯變量,變量名為Variable2GBLSVariable3;定義全局的字符串變量,變量名為Variable352.局部變量偽指令LCLA、LCLL和LCLS

局部變量是指在某個(gè)匯編程序中定義并使用的變量,在其它匯編程序中不能使用。語法格式如下:

LCLA(LCLL或LCLS)局部變量名

LCLA偽指令用于定義一個(gè)局部的數(shù)字變量,并初始化為0。LCLL偽指令用于定義一個(gè)局部的邏輯變量,并初始化為F(假)。LCLS偽指令用于定義一個(gè)局部的字符串變量,并初始化為空。應(yīng)用示例:(局部必須唯一)LCLAVariable4;定義局部的數(shù)字變量,變量名為Variable463.變量賦值偽指令SETA、SETL和SETS

變量賦值偽指令既可以給全局變量賦值,也可以給局部變量賦值。偽指令SETA、SETL、SETS用于給一個(gè)已經(jīng)定義的全局變量或局部變量賦值。偽指令的格式如下:

變量名SETA(SETL或SETS)表達(dá)式

SETA偽指令用于給一個(gè)數(shù)字變量賦值。SETL偽指令用于給一個(gè)邏輯變量賦值。SETS偽指令用于給一個(gè)字符串變量賦值。應(yīng)用示例:Variable1SETA0xbb;將該變量賦值為數(shù)字值0xbbVariable2SETL{TRUE};將該變量賦值為邏輯“真”Variable3SETS“Testing”;將該變量賦值為字符串Testing74.寄存器列表定義偽指令RLIST

RLIST偽指令可用于對一個(gè)通用寄存器列表定義名稱,使用該偽指令定義的名稱可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器訪問次序根據(jù)寄存器的編號由低到高,列表中的寄存器排列次序必須從小到大。偽指令格式如下:

寄存器列表名稱RLIST{寄存器列表}

應(yīng)用示例:

Reglist1RLIST{R0-R6,R8,R10};將寄存器列表名稱定義為Reglist1,以后可直接指令中使用84.1.3內(nèi)存分配偽指令內(nèi)存分配偽指令一般用于為特定的數(shù)據(jù)分配存儲單元,同時(shí)可完成已分配存儲單元的初始化。以下介紹常見的內(nèi)存分配數(shù)據(jù)定義偽指令。1.字節(jié)分配偽指令DCB

該偽指令用于分配一片連續(xù)的字節(jié)(8bit)存儲單元,并用偽指令中指定的表達(dá)式初始化。其中表達(dá)式的值可以為0~255或字符串。DCB偽指令也可以用符號“=”代替。指令格式如下:

標(biāo)號DCB表達(dá)式應(yīng)用示例:Str1DCB“Thisisastring”;分配一片連續(xù)的字節(jié)存儲單元并初始化。Str2DCB0x0,0x02,0x03,0x04,0x05

;分配一片連續(xù)的字節(jié)存儲單元并初始化的另一種方式。92.半字分配偽指令DCW(或DCWU)

該偽指令用于分配一片連續(xù)的半字(16bit)存儲單元,并用偽指令中指定的表達(dá)式初始化。其中表達(dá)式可以為程序標(biāo)號或表達(dá)式。DCW要求半字對齊,而DCWU不要求半字對齊。指令格式如下:

標(biāo)號DCW(或DCWU)

表達(dá)式

應(yīng)用示例:DataTestDCW1,2,3;分配連續(xù)的半字存儲單元并初始化注意:每一個(gè)數(shù)字均占2字節(jié)存儲單元,即半字。3.字分配偽指令DCD(或DCDU)

該偽指令用于分配一片連續(xù)的字存儲(32bit)單元,并用偽指令中指定的表達(dá)式初始化。可以使用符號“&”代替。指令格式如下:

標(biāo)號DCD(或DCDU)表達(dá)式

應(yīng)用示例:WordDataDCD1,2,3;分配連續(xù)的字存儲單元并初始化,每個(gè)數(shù)字占4字節(jié)內(nèi)存單元即字單元104.DCFS(或DCFSU)偽指令

該指令用于為單精度的浮點(diǎn)數(shù)分配一片連續(xù)的存儲單元,每個(gè)雙精度數(shù)占1個(gè)字單元,并用偽指令中指定的表達(dá)式初始化。偽指令格式如下

標(biāo)號DCFS(或DCFSU)表達(dá)式應(yīng)用示例:SFloatDataDCFS–5E7,2E-8

;分配連續(xù)的字存儲單元并初始化為指定的單精度數(shù)。5.DCFD(或DCFDU)偽指令

該偽指令用于為雙精度的浮點(diǎn)數(shù)分配一片連續(xù)的存儲單元,每個(gè)雙精度數(shù)占2個(gè)字單元,并用偽指令中指定的表達(dá)式初始化。偽指令格式如下:

標(biāo)號DCFD(或DCFDU)

表達(dá)式應(yīng)用示例:FloatDataDCFD–5E7,2E-8

;分配連續(xù)的字存儲單元并初始化為指定的雙精度數(shù)。116.DCQ(或DCQU)偽指令

該指令用于分配一片以8字節(jié)為單位連續(xù)的存儲區(qū)域,并用偽指令中指定的表達(dá)式初始化。偽指令格式如下:

標(biāo)號DCQ(或DCQU)表達(dá)式應(yīng)用示例:

B8DataDCFD100,200;分配2個(gè)連續(xù)的8字節(jié)存儲單元并初始化。7.SPACE

偽指令

該指令用于分配一片連續(xù)的字節(jié)存儲單元并初始化為0。其中表達(dá)式是要分配的字節(jié)數(shù)。SPACE也可以用符號“%”來代替。偽指令格式如下:

標(biāo)號SPACE表達(dá)式

應(yīng)用示例:

SpaceDataSPACE100;分配連續(xù)100個(gè)字節(jié)單元并用0初始化。128.MAP偽指令

該指令用于定義一個(gè)結(jié)構(gòu)化的內(nèi)存表首地址。MAP也可以用符號“^”來代替。表達(dá)式可以是程序中的標(biāo)號或數(shù)學(xué)表達(dá)式?;芳拇嫫骺蛇x,當(dāng)它不存在時(shí),表達(dá)式的值為內(nèi)存表的首地址;當(dāng)該項(xiàng)存在時(shí),內(nèi)存表的首地址即為表達(dá)式的值與寄存器的值之和。MAP偽指令常與FIELD偽指令配合使用來定義一個(gè)內(nèi)存表。

MAP表達(dá)式{,基址寄存器}應(yīng)用示例:MAP0x0100,R0;定義結(jié)構(gòu)化首地址值為0x0100+R09.FIELD偽指令

該指令用于定義一個(gè)結(jié)構(gòu)化內(nèi)存表的數(shù)據(jù)域,也可用符號“#”代替,表達(dá)式的值為當(dāng)前數(shù)據(jù)域在內(nèi)存中所占的字節(jié)數(shù)。FIELD偽指令常與MAP偽指令配合使用來定義結(jié)構(gòu)化的內(nèi)存表。MAP偽指令定義內(nèi)存表的首地址,F(xiàn)IELD偽指令定義內(nèi)存表中的各個(gè)數(shù)據(jù)域字節(jié)個(gè)數(shù),并可以為每個(gè)數(shù)據(jù)域指定一個(gè)標(biāo)號供其他的指令引用。它們與C語言中的struct結(jié)構(gòu)體雷同。FIELD偽指令的格式如下:

標(biāo)號FIELD表達(dá)式13應(yīng)用示例:1)在內(nèi)存中定義異常模式程序入口地址的結(jié)構(gòu)化存儲空間,即每個(gè)字單元中的內(nèi)容是相對應(yīng)的異常模式程序入口地址。由它們組成的表稱為異常向量表2)在內(nèi)存中定義ARM的32個(gè)中斷程序或中斷函數(shù)入口地址的結(jié)構(gòu)化存儲空間,即每個(gè)字單元中的內(nèi)容是相應(yīng)的中斷程序或中斷函數(shù)入口地址。由它們組成的表稱為中斷向量表。;異常向量表定義如下:^_ISR_STARTADDRESS;指定結(jié)構(gòu)體地址的開始位置HandleReset#4;占用第1個(gè)字單元(4字節(jié))HandleUndef #4;占用第2個(gè)字單元(4字節(jié))HandleSWI #4;占用第3個(gè)字單元(4字節(jié))HandlePabort #4;占用第4個(gè)字單元(4字節(jié))HandleDabort #4;占用第5個(gè)字單元(4字節(jié))HandleReserved#4;(預(yù)留)占用第6個(gè)字單元(4字節(jié))HandleIRQ #4;占用第7個(gè)字單元(4字節(jié))HandleFIQ #4;占用第8個(gè)字單元(4字節(jié));以上的字單元內(nèi)容通過程序?qū)⑺鼈兏髯缘漠惓3绦蛉肟诘刂穼懭氲较鄳?yīng)的內(nèi)存空間中。;起到由固定的異常向量地址轉(zhuǎn)向到存儲器的虛擬異常向量地址。以下是內(nèi)存中斷向量表定義:HandleEINT0 #4;占用第9個(gè)字單元(4字節(jié))HandleEINT1 #4;占用第10個(gè)字單元(4字節(jié))

…HandleADC #4;占用第40個(gè)字單元(4字節(jié));以上4行實(shí)際使用時(shí)應(yīng)該有32行,分別為32個(gè)ARM中斷源定義存儲它們?nèi)肟诔绦虻牡刂分?通過將匯編中斷服務(wù)程序入口標(biāo)號或C語言中斷函數(shù)名賦值到定義的存儲單元中,就可以執(zhí)行相應(yīng)的中斷程序或調(diào)用中斷函數(shù)了。關(guān)于它們具體操作在ARM中斷程序設(shè)計(jì)8.2節(jié)中講述。1410.LTORG偽指令

文字池偽指令LTORG,用于聲明一個(gè)數(shù)據(jù)緩沖池(文字池)的開始。通常ARM匯編器把文字池放在代碼段的最后面,但必須在END偽指令之前。LTORG偽指令經(jīng)常放在無條件跳轉(zhuǎn)指令之后,或子程序返回指令之后,這樣處理器不會錯(cuò)誤地將字緩沖池中的數(shù)據(jù)當(dāng)作指令來執(zhí)行。使用時(shí)只需要用偽指令LTORG聲明,文字池中的內(nèi)容是由匯編器自動生成的。應(yīng)用示例:

startBLfunc1;調(diào)用子程序

func1LDRR1,=0x33333334;子程序入口,LDR是偽指令,立即數(shù)不可用前述的12bit來表示…;0x33333334將會自動寫入到文字池預(yù)留的3000個(gè)字節(jié)單元中

MOVPC,RL;子程序返回

LTORG;聲明文字池DataSPACE3000;預(yù)留3000字節(jié)存儲空間

END;匯編結(jié)束偽指令154.1.4匯編控制偽指令匯編控制偽指令用于控制匯編程序的執(zhí)行流程,主要有條件匯編偽指令、宏定義偽指令和重復(fù)匯編控制偽指令等,該類偽指令如下:1)條件匯編控制:IF,ELSE,ENDIF2)宏定義:MACRO和MEND3)重復(fù)匯編:WHILE和WEND161.IF、ELSE、ENDIF

偽指令I(lǐng)F、ELSE、ENDIF偽指令能夠根據(jù)條件把一段程序代碼包括在匯編程內(nèi)或?qū)⑵渑懦趨R編程序之外。“[”可代替IF,“|”可代替ELSE,“]”可代替ENDIF。偽指令的格式如下:IF邏輯表達(dá)式

指令序列1

ELSE

指令序列2

ENDIF

在格式中,如果邏輯表達(dá)式為真,則指令序列1被匯編;

否則,指令序列2被匯編。ELSE可有可無。應(yīng)用示例:GBLLTHUMBCODE;定義全局邏輯變量[{CONFIG}=16;如果變量CONFIG==16,即目前處于16位Thumb模式,;則條件為真。這里花括號{}是指取變量的值THUMBCODESETL{TRUE};Thumb狀態(tài)模式變量賦值為真CODE32;轉(zhuǎn)入ARM模式,以下是32位ARM指令代碼|;ELSETHUMBCODESETL{FALSE};Thumb狀態(tài)模式變量賦值為假]2.MACRO和MEND偽指令MACRO用于標(biāo)識宏定義的開始,MEND用于標(biāo)識宏定義的結(jié)束。用MACRO和MEND定義的代碼,稱為宏定義,這樣在程序中就可以通過宏指令多次調(diào)用該代碼段。宏指令的格式如下:MACRO$標(biāo)號

宏名$參數(shù)1,$參數(shù)2,……

指令序列

MEND

其中,$表示其后的標(biāo)號或參數(shù)是宏變量,使用時(shí)可以進(jìn)行宏替換。例如:$標(biāo)號在宏指令被展開時(shí),標(biāo)號會被替換為用戶定義的符號,宏指令的參數(shù)可以使用一個(gè)或多個(gè),$參數(shù)n在宏指令被展開時(shí),這些參數(shù)被相應(yīng)的數(shù)值所替換。1718應(yīng)用示例:MACRO;定義異常向量轉(zhuǎn)移宏匯編,主要用于中斷模式$HandlerLabelHANDLER$HandleLabel$HandlerLabelSUBSP,SP,#4;①修改堆棧指針,用于保存跳轉(zhuǎn)地址STMFDSP!,{R0};②壓棧保護(hù)R0寄存器內(nèi)容LDRR0,=$HandleLabel;③將轉(zhuǎn)移的地址存入R0LDRR0,[R0];④將$HandleLabel的內(nèi)容送R0STRR0,[SP,#4];⑤將R0的內(nèi)容壓棧到①的單元中LDMFDSP!,{R0,PC};⑥彈?;貜?fù)R0,PC指向$HandleLabelMEND該宏主要實(shí)現(xiàn)由異常向量地址處的程序計(jì)數(shù)器PC值(HandlerXxx)向內(nèi)存儲器中的定義的異常模式程序入口地址(HandleXxx的內(nèi)容)處跳轉(zhuǎn)。即從固定的異常向量指針處跳轉(zhuǎn)到內(nèi)存儲器中程序可控的入口地址處。對于普通中斷調(diào)用執(zhí)行時(shí)的語法是:HandlerIRQHANDLERHandleIRQ實(shí)現(xiàn)PC指針從HandlerIRQ跳轉(zhuǎn)到HandleIRQ的功能。193.MEXIT

偽指令

MEXIT偽指令用于從宏定義中跳轉(zhuǎn)出去。偽指令格式如下:MEXIT

若需要從MACRO和MEND定義的宏體中跳出來時(shí)可以使用該偽指令。4.WHILE和WEND偽指令

WHILE用于標(biāo)識條件循環(huán)偽指令的開始,WEND用于標(biāo)識循環(huán)體的結(jié)束。偽指令格式如下:

WHILE邏輯表達(dá)式

指令序列WEND如果條件為真,幾乎重復(fù)匯編相同的或幾乎相同的一段程序代碼。該偽指令可以嵌套使用。204.1.5匯編程序中常用偽指令偽指令名稱功能描述AREA定義代碼段或數(shù)據(jù)段CODE16、CODE32告訴匯編器其后是Thumb程序、ARM程序ENTRY指定程序的入口點(diǎn)ALIGN指定程序或數(shù)據(jù)的對齊方式,如半字對齊,字對齊等END匯編程序結(jié)束EXPORT/GLOBAL在本匯編程序中聲明標(biāo)號可以在其他源文件使用IMPORT/EXTURN在其他文件中用上一欄方法聲明,在本文件中聲明使用GET/INCLUDE將一個(gè)其他源文件包含到本文件中使用INCBIN將一個(gè)二進(jìn)制的文件包含在本文件中使用RN給特定的寄存器重新命名ROUT標(biāo)記局部標(biāo)號使用范圍的界限KEEP保留符號表中的局部符號表4-1常用匯編程序偽指令表211.AREA偽指令

用于定義一個(gè)代碼段或數(shù)據(jù)段,它是每個(gè)匯編程序不可缺少的部分。語法如下:

AREA段名,屬性1,屬性2,……

其中,段名若以數(shù)字開頭,則該段名需用“|”括起來,如|1_test|。屬性字段表示該代碼段(或數(shù)據(jù)段)的相關(guān)屬性,多個(gè)屬性用逗號分隔。屬性段如表4-2所示。屬性偽指令功能描述CODE聲明定義的是一個(gè)代碼段DATA聲明定義的是一個(gè)數(shù)據(jù)段READONLY指定本段為只讀,是代碼段的默認(rèn)屬性READWRITE指定本段為可讀可寫,是數(shù)據(jù)段的默認(rèn)屬性ALIGN={exp}指定段的對齊方式為2exp,exp取值在0~31。默認(rèn)為字對齊COMMON指定一個(gè)通用段,該段不包含任何用戶代碼和數(shù)據(jù)NOINIT指定此數(shù)據(jù)段僅保留內(nèi)存單元,而沒有將初值寫入到內(nèi)存單元應(yīng)用示例:

AREAStart,CODE,READONLY

這里定義一個(gè)代碼段,段名:Start,屬性為只讀。注意:一個(gè)大的匯編程序可以包含多個(gè)代碼段和數(shù)據(jù)段,一個(gè)匯編程序至少包含一個(gè)代碼段。222.CODE16和CODE32偽指令CODE16偽指令的功能是告訴匯編器后面的指令序列為16位的Thumb指令。CODE32偽指令的功能是告訴匯編器后面的指令序列為32位的ARM指令。注意:CODE16和CODE32只告訴其后指令的類型,該偽操作本身不進(jìn)行ARM工作狀態(tài)的切換。3.ENTRY偽指令

該指令指定程序的入口點(diǎn)。偽指令格式是:ENTRY應(yīng)用示例:AREAStartUp,CODE,READONLY;指定一個(gè)代碼段StartUp,屬性為只讀ENTRY;指定代碼段程序入口點(diǎn)CODE32;指定其后為32位ARM指令LDRR0,=start+1;使用ARM偽指令LDR給R0賦值,并使R0[0]=1BXR0;R0[0]=1將跳轉(zhuǎn)到Thumb指令程序處執(zhí)行

…CODE16;指定其后為16位Thumb指令程序startMOVR1,#20

…END;匯編結(jié)束注意:一個(gè)程序(可以包含多個(gè)源文件)中至少要有一個(gè)ENTRY,但一個(gè)源文件中最多只有一個(gè)ENTRY(可以沒有ENTRY)。234.END偽指令END偽指令告訴匯編器源文件已經(jīng)結(jié)束,也就是說其后的指令將不起作用,一個(gè)源文件只能使用一次END偽指令。偽指令格式如下:END5.EXPORT/GLOBAL偽指令

該兩條偽指令用于在程序中聲明一個(gè)全局標(biāo)號,可以在其它文件中使用。該偽指令語法格式如下:

EXPORT標(biāo)號{[WEAK]}GLOBAL標(biāo)號{[WEAK]}其中:[WEAK]選項(xiàng)聲明其它的同標(biāo)號優(yōu)先于該標(biāo)號被應(yīng)用。EXPORT/GLOBAL同功能。應(yīng)用示例:AREAExample,CODE,READONLYEXPORTDoAddDoAddADDR0,R1,R2246.IMPORT偽指令I(lǐng)MPORT偽指令是用于通知編譯器聲明的標(biāo)號是在其它匯編語言文件中已經(jīng)聲明,在本文件中使用的標(biāo)號。而且無論當(dāng)前源文件是否引用該標(biāo)號,該標(biāo)號均會被加入到當(dāng)前源文件的符號表中。偽指令語法格式如下:IMPORT標(biāo)號{[WEAK]}

其中:[WEAK]

選項(xiàng)聲明在其它文件中沒有定義時(shí),編譯器也不給出錯(cuò)誤信息。在多數(shù)情況下將該標(biāo)號置為0,若該標(biāo)號為B或BL指令引用,則將B或BL指令置為NOP操作。7.EXTERN偽指令EXTERN偽指令用于通知編譯器要使用的標(biāo)號在其他的源文件中定義,但要在當(dāng)前源文件中引用。如果當(dāng)前源文件實(shí)際并未引用該標(biāo)號,該標(biāo)號就不會被加入到當(dāng)前源文件的符號表中。偽指令語法格式如下:

EXTERN標(biāo)號{[WEAK]}標(biāo)號在程序中區(qū)分大小寫,[WEAK]選項(xiàng)表示當(dāng)所有的源文件都沒有定義這樣一個(gè)標(biāo)號時(shí),編譯器也不給出錯(cuò)誤信息。在多數(shù)情況下將該標(biāo)號置為0,若該標(biāo)號為B或BL指令引用,則將B或BL指令置為NOP操作。258.GET/INCLUDE偽指令

這兩條偽指令是將一個(gè)源文件包含到當(dāng)前的源文件中,并將包含的文件在當(dāng)前文件中進(jìn)行匯編處理。指令格式如下:

GET文件名或

INCLUDE文件名應(yīng)用舉例:GETd:\arm\filename.s;文件名使用全文件名,即包含文件的路徑9.INCBIN偽指令I(lǐng)NCBIN偽指令是將一個(gè)已經(jīng)編譯好的二進(jìn)制文件包含到當(dāng)前源程序中,匯編器不再進(jìn)行匯編處理。指令格式如下:

INCBIN文件名應(yīng)用示例:INCBINd:\arm\binfile.bin注意:與GET/INCLUDE偽指令的區(qū)別。INCBIN偽指令是將一個(gè)已經(jīng)編譯好的二進(jìn)制文件或數(shù)據(jù)文件包含到當(dāng)前源文件中使用;而GET/INCLUDE偽指令是將一個(gè)匯編源文件(未編譯的)包含到當(dāng)前文件中使用。2610.RN偽指令RN偽指令是給一個(gè)通用寄存器重新命名一個(gè)別名,在特定環(huán)境下使用。指令的格式如下:

別名RN通用寄存器應(yīng)用示例:COUNTRNR6;定義R6為計(jì)數(shù)器COUNT,定義后直接使用COUNT11.KEEP偽指令KEEP偽指令指示編譯器保留符號表中的局部符號。偽指令的格式如下:KEEP{symbol}其中:symbol是要保留的局部符號;如果沒有此項(xiàng),則除了基于寄存器的所有符號都將保含在目標(biāo)文件的符號表中。12.ROUTROUT偽指令用于定義局部標(biāo)號的有效范圍。偽指令的格式如下:{name}ROUT其中:name是定義作用范圍的名稱。當(dāng)沒有使用ROUT偽指令時(shí),局部標(biāo)號的作用范圍為其所在段。ROUT的作用范圍是在本ROUT偽指令和下一條ROUT偽指令之間(指同一段中的偽指令)。274.1.6匯編語言中的運(yùn)算符與表達(dá)式在匯編語言設(shè)計(jì)中,也經(jīng)常使用各種表達(dá)式。表達(dá)式一般由變量、常量、運(yùn)算符和括號組成。常用的表達(dá)式有算術(shù)表達(dá)式、邏輯表達(dá)式、關(guān)系表達(dá)式和字符串表達(dá)式,其運(yùn)算遵循以下優(yōu)先級:

括號運(yùn)算符的優(yōu)先級最高。一般在搞不清優(yōu)先級的情況下,可以增加括號來提高表達(dá)式的優(yōu)先級別;

單目運(yùn)算符的優(yōu)先級高于其他運(yùn)算符;

優(yōu)先級相同的雙目運(yùn)算符運(yùn)算順序是從左到右;

優(yōu)先級相同的單目運(yùn)算符運(yùn)算順序是從右到左。281.數(shù)字運(yùn)算符與表達(dá)式數(shù)字表達(dá)式一般由算術(shù)常量、算術(shù)變量、算術(shù)運(yùn)算符和括號組成。與數(shù)字運(yùn)算符和表達(dá)式有關(guān)的內(nèi)容如下:⑴算術(shù)運(yùn)算符與表達(dá)式主要有:“+”、“-”、“×”、“/”、“MOD”運(yùn)算符。以下是由X和Y以及運(yùn)算符所構(gòu)成的算術(shù)表達(dá)式和含義:X+Y表示X與Y之和;X-Y表示X與Y之差;X×Y表示X與Y之乘積;X/Y表示X除以Y之商;X:MOD:Y表示X除以Y的余數(shù)。⑵移位運(yùn)算符與表達(dá)式主要有:“ROL”、“ROR”、“SHL”、“SHR”運(yùn)算符。以下是由X和Y以及其運(yùn)算符所構(gòu)成的移位表達(dá)式和含義:X:ROL

:Y表示X循環(huán)左移Y位;

X

:ROR

:Y表示X循環(huán)右移Y位;X:SHL

:Y表示X左移Y位;

X:SHR

:Y表示X右移Y位。292.邏輯運(yùn)算符與表達(dá)式邏輯表達(dá)式一般由邏輯常量、邏輯變量、邏輯運(yùn)算符和括號組成。與邏輯運(yùn)算符和表達(dá)式有關(guān)的內(nèi)容如下:⑴位邏輯運(yùn)算符與表達(dá)式主要有:“AND”、“OR”、“NOT”、“EOR”運(yùn)算符。以下是由X和Y以及其運(yùn)算符所構(gòu)成的位邏輯運(yùn)算表達(dá)式和含義:X:AND

:Y表示將X與Y按位進(jìn)行邏輯“與”運(yùn)算;X

:OR

:Y表示將X與Y按位進(jìn)行邏輯“或”運(yùn)算;:NOT

:Y表示將Y按位進(jìn)行邏輯“非”運(yùn)算;X:EOR

:Y表示將X與Y按位進(jìn)行邏輯“異或”運(yùn)算。⑵邏輯運(yùn)算符與表達(dá)式主要有:“LAND”、“LOR”、“LNOT”、“LEOR”運(yùn)算符。以下是由X和Y以及其運(yùn)算符所構(gòu)成的邏輯運(yùn)算表達(dá)式和含義:X:LAND

:Y表示將X與Y進(jìn)行邏輯“與”運(yùn)算;X

:LOR

:Y表示將X與Y進(jìn)行邏輯“或”運(yùn)算;:LNOT

:Y表示將Y進(jìn)行邏輯“非”運(yùn)算;X:LEOR

:Y表示將X與Y進(jìn)行邏輯“異或”運(yùn)算。303.關(guān)系運(yùn)算符與表達(dá)式關(guān)系表達(dá)式一般由常量、變量、關(guān)系運(yùn)算符和括號組成。如果比較的兩個(gè)變量關(guān)系滿足,則輸出為“真”,否則,輸出為“假”。關(guān)系運(yùn)算符主要有:“=”、“>”、“<”、“>=”“<=”、“/=”、“<>”,以下是由變量X、Y所構(gòu)成的關(guān)系表達(dá)式及含義:X=Y(jié)表示X等于Y;X

>Y表示X大于Y;X<Y表示X小于Y;X>=Y(jié)表示X大于等于Y;X<=Y(jié)表示X小于等于Y;

X/=Y(jié)表示X不等于Y;X<>Y表示X不等于Y;314.字符串運(yùn)算符與表達(dá)式字符串表達(dá)式一般由字符串常量、字符串變量、字符串運(yùn)算符和括號組成。編譯器所支持的最大字符串長度是512字節(jié)。注意:下面的表達(dá)式也可以是變量或常量。⑴LEN運(yùn)算符LEN運(yùn)算符返回的是字符串變量中的字符串長度,語法格式是:

:LEN:字符表達(dá)式⑵CHR運(yùn)算符CHR運(yùn)算符是將0~255中的整數(shù)轉(zhuǎn)換為一個(gè)字符,語法格式是:

:CHR:整數(shù)表達(dá)式⑶STR運(yùn)算符STR運(yùn)算符是將一個(gè)數(shù)字表達(dá)式或一個(gè)邏輯表達(dá)式轉(zhuǎn)換成一個(gè)字符串。對于數(shù)字表達(dá)式將其轉(zhuǎn)換為一個(gè)由16進(jìn)制數(shù)組成的字符串;對于一個(gè)邏輯表達(dá)式將其轉(zhuǎn)換成字符T或F。語法格式是::STR:表達(dá)式324.字符串運(yùn)算符與表達(dá)式(續(xù))⑷LEFT運(yùn)算符LEFT運(yùn)算符返回的是左端字符串X,從左邊取出Y個(gè)字符組成的子串。語法格式是:X:LEFT:Y

其中X是源字符串;Y是一個(gè)整數(shù),表示從左側(cè)取出字符的個(gè)數(shù)。⑸RIGHT運(yùn)算符RIGHT運(yùn)算符返回的是左端字符串X,從右邊取出Y個(gè)字符組成的子串。語法格式是:X:RIGHT:Y

其中X是源字符串;Y是一個(gè)整數(shù),表示從右側(cè)取出字符的個(gè)數(shù)。⑹CC運(yùn)算符CC運(yùn)算符是將其左端和右端的2個(gè)字符連接為一個(gè)長的字符串,X在前,Y在后。其語法格式是:X:CC:Y

其中X、Y均為字符串表達(dá)式。335.其他運(yùn)算符和表達(dá)式⑴?運(yùn)算符

?運(yùn)算符返回代碼行所生成的可執(zhí)行代碼的字節(jié)長度。

語法格式如下:?行標(biāo)號⑵DEF運(yùn)算符

DEF運(yùn)算符判斷是否定義了其后的符號。

語法格式如下::DEF

:X如果符號X已經(jīng)定義,其值為真,否則為假。注意:目前在集成開發(fā)環(huán)境ADS1.2中,也支持對C語言環(huán)境下的部分操作符和表達(dá)式的應(yīng)用,或者說與GNU開發(fā)環(huán)境下使用基本相同的操作符與表達(dá)式。344.1.7Linux操作系統(tǒng)中GNU開發(fā)環(huán)境下的偽指令在上面介紹的偽指令都是在Windows操作系統(tǒng)中,ADS集成開發(fā)環(huán)境里使用的偽指令,它們也被稱為標(biāo)準(zhǔn)的ARM偽指令。在Linux操作系統(tǒng)中,GNU開發(fā)環(huán)境下的偽指令與ADS中具有相同的作用,但是它們的書寫格式是有區(qū)別的。目前在ARM的產(chǎn)品開發(fā)中,引入Linux操作系統(tǒng)的產(chǎn)品較多,因此本節(jié)以比較的方法介紹GNU環(huán)境下的偽指令,加快讀者對其偽指令的理解和掌握。351.內(nèi)存分配偽指令

GNU開發(fā)環(huán)境下有更多的內(nèi)存分配偽指令,下表列出了最常用到的大部分偽指令,要知道更多的內(nèi)容請參見有關(guān)GNU環(huán)境下的偽指令。ADS偽指令GNU偽指令GNU偽指令語法格式功能簡述EQU/SETX.equ/.set.equsymbol,expr定義symbol的值是exprDCB.byte/.ascii.byteexpr{,expr}…定義字節(jié)數(shù)據(jù)單元DCW.hword/.short.shortexpr{,expr}…定義半字?jǐn)?shù)據(jù)單元DCD.word/.long/.int.longexpr{,expr}…定義字?jǐn)?shù)據(jù)單元DCQ.quad.quadexpr{,expr}…定義8字節(jié)數(shù)據(jù)單元DCFS.float/.single.floatexpr{,expr}…定義單精度數(shù)單元DCFD.double.doubleexpr{,expr}…定義雙精度數(shù)單元SPACE.zero.zerosize分配size字節(jié)單元,初始化為0LTORG.ltorg/.pool.ltorg聲明緩沖池SPACE.space/.skip.spacesize{,value}與zero基本相同,填充值是value注意:表里的SETX代表ADS下的SETA、SETL、SETS偽指令。362.匯編控制偽指令匯編控制偽指令主要有條件編譯控制偽指令和宏定義偽指令。與ADS環(huán)境下的偽指令區(qū)別請仔細(xì)觀察注釋字段。⑴條件編譯控制偽指令.ifGNU環(huán)境下的.if偽指令也是根據(jù)表達(dá)式值的真與假,決定是否要編譯它下面的代碼,用.endif偽指令作為條件控制偽指令的結(jié)束,中間可以使用.else偽指令進(jìn)行分支選擇。它的指令格式豐富,形式是多種多樣的。以下進(jìn)行簡要介紹:.ifdefsymbol/*與ADS偽指令I(lǐng)F:DEF:symbol功能相同*/

指令序列1

@如果symbol以定義,則匯編指令序列1.else

/*與ADS偽指令ELSE功能相同*/

指令序列2.endif

/*與ADS偽指令ENDIF功能相同*/注意:在GNU環(huán)境下的匯編語句注釋使用符號“@”開頭到本行結(jié)束,或與C語言使用相同的注釋符:

/*語句說明*/。37⑵.macro、.exitm與.endm偽指令宏定義體的作用在前面已經(jīng)講述,以下是在GNU環(huán)境下的宏體定義語法格式。.macro/*與ADS偽指令MACRO功能相同*/\標(biāo)號:宏體名\參數(shù)1,\參數(shù)2…

指令序列1

.exitm@需要跳出宏體時(shí)使用這條偽指令。對應(yīng)ADS下的偽指令MEXIT

指令序列2.endm/*與ADS偽指令MEND功能相同*/

關(guān)于宏的調(diào)用與前述相同。在ADS集成開發(fā)環(huán)境中使用符號“$”表示宏變量,在GNU環(huán)境下使用符號“\”表示宏變量。383.匯編程序控制偽指令

GNU環(huán)境下的匯編程序控制偽指令同樣也很豐富,以下也是通過比較的方法將它們列于下表中。ADS偽指令GNU偽指令語法格式功能簡述包含在段定義中.section.sectionsection_name定義域中包含的段無.type.typesymbol,description指定符號類型(對象或函數(shù))定義碼段的字串.text.text{subsection}聲明一個(gè)代碼段定義數(shù)據(jù)段的字串.data.data{subsection}聲明一個(gè)初始化數(shù)據(jù)段無.bss.bss{subsection}聲明一個(gè)未初始化數(shù)據(jù)段CODE16.code16/.thumb.code16/.thumb聲明以下代碼是Thumb指令CODE32.code32/.arm.code32/.arm聲明以下代碼是ARM指令A(yù)LIGN.align/.balign.align{expt}聲明對齊方式INCLUDE.include.includefilename在當(dāng)前文件中引用filenameEXPORT.global/.globl.globalsymbol聲明標(biāo)號,在其它文件中使用IMPORT.extern.externsymbol聲明外部標(biāo)號在當(dāng)前文件使用END.end.end匯編結(jié)束RN.reg.regalias,Rn定義通用寄存器別名有特用394.2ARM匯編語言程序設(shè)計(jì)程序是由指令組成的,要編寫好程序其一就是要掌握指令的功能與使用方法,其二就是要熟悉匯編語言的程序結(jié)構(gòu)等。在此基礎(chǔ)上,熟悉程序?qū)崿F(xiàn)中使用的算法、控制過程與步驟,復(fù)雜時(shí)畫好程序的流程圖,然后進(jìn)行程序的編寫。評價(jià)一個(gè)程序的好壞,就是在實(shí)現(xiàn)預(yù)先規(guī)定的運(yùn)算或控制過程功能的前提下,一是程序占用的存儲空間最小,即使用的指令條數(shù)最少;二是代碼的運(yùn)行速度最快。但這兩者又是很難同時(shí)滿足,往往取一個(gè)折中的實(shí)現(xiàn)方案。本節(jié)主要介紹與之相關(guān)的主要內(nèi)容。404.2.1ARM匯編中的源文件類型

在ARM的程序設(shè)計(jì)中,必不可少的部分使用匯編語言編寫,大部分程序使用C/C++語言開發(fā),常用的源文件如下表所列。源程序文件文件類型后綴說明匯編程序文件*.s或*.S用匯編語言編寫的ARM程序或Thumb程序匯編頭文件*.a或*.A使用偽指令定義的端口地址、內(nèi)存分配等內(nèi)容C程序文件*.c或*.C使用C語言編寫的程序代碼C程序頭文件*.h或*.H使用預(yù)處理命令定義的常量、宏體,函數(shù)的聲明等414.2.2ARM匯編語言的語句格式1.基本語句格式ARM(Thumb)匯編語言的語句格式為:{標(biāo)號} {指令或偽指令} {;注釋}規(guī)則:如果一條語句太長,可將其分為若干行來書寫,在行的尾部用續(xù)行符“\”來標(biāo)識下一行與本行為同一條語句。

每一條指令助記符可以全部用大寫、或全部用小寫,但不能在一條指令中大、小寫混用。注意:在使用ADS1.2編輯ARM程序時(shí),書寫標(biāo)號一定要頂格,在指令前如果沒有標(biāo)號時(shí)指令一定要退格書寫。由于ADS環(huán)境下標(biāo)號后沒有冒號“:”,ADS是通過頂格來區(qū)分標(biāo)號和ARM指令的。422.匯編語言程序中常用的符號

在匯編語言程序設(shè)計(jì)中,可以使用各種符號代替地址、變量和常量等,以增加程序的可讀性。以下為符號命名的約定:

符號名不應(yīng)與指令或偽指令同名。

符號在其作用范圍內(nèi)必須唯一。

符號區(qū)分大小寫,同名的大、小寫符號被視為兩個(gè)不同的符號。

自定義的符號名不能與系統(tǒng)保留字相同。3.程序中的常量

程序中的常量是指其值在程序的運(yùn)行過程中不能被改變的量。ARM(Thumb)匯編程序所支持的常量有邏輯常量、數(shù)字常量和字符串常量。

數(shù)字常量一般為32位的整數(shù),無符號常量取值范圍為0~232-1,有符號常量取值范圍為-231~231-1。

邏輯常量只有兩種取值:真(True)或假(False)。

字符串常量為一個(gè)固定的字符串,一般用來提示程序運(yùn)行時(shí)的信息。435.程序中的變量代換

程序中的變量可通過代換操作取得一個(gè)常量。代換操作符為“$”。如果“$”在數(shù)字變量前面,編譯器會將該數(shù)字變量的值轉(zhuǎn)換為十六進(jìn)制的字符串,并將該十六進(jìn)制的字符串代換“$”后的數(shù)字變量。ARM中的常量使用EQU定義,ARM中使用GBLA、GBLL、GBLS定義全局變量,使用LCLA、LCLL、LCLS定義局部變量,使用SETA、SETL、SETS為它們賦值。例如:

GBLSSTR1

GBLSSTR2

STR1

SETS

”pen”

STR2SETS“Thisisa$STR1"編譯后的結(jié)果是STR2的值為Thisisapen.444.2.3ARM匯編語言的程序結(jié)構(gòu)ARM匯編語言程序是以段(Sectoin)為單位組織源文件的。段是相對獨(dú)立的、具有特定名字的、不可分割的指令序列或數(shù)字序列。段可以分為代碼段和數(shù)據(jù)段,代碼段的內(nèi)容為執(zhí)行代碼,數(shù)據(jù)段存放代碼段運(yùn)行時(shí)需要用到的數(shù)據(jù)。一個(gè)匯編程序至少應(yīng)該有一個(gè)代碼段,也可以分割為多個(gè)代碼段和數(shù)據(jù)段,多個(gè)段在程序編譯鏈接時(shí)最終形成一個(gè)可執(zhí)行的映象文件(*.elf)??蓤?zhí)行映象文件通常由以下幾部分構(gòu)成:

一個(gè)或多個(gè)代碼段,代碼段的屬性為只讀。

零個(gè)或多個(gè)包含初始化數(shù)據(jù)的數(shù)據(jù)段,數(shù)據(jù)段的屬性為可讀寫。

零個(gè)或多個(gè)不包含初始化數(shù)據(jù)的數(shù)據(jù)段,數(shù)據(jù)段的屬性為可讀寫。匯編連接器根據(jù)系統(tǒng)默認(rèn)或用戶設(shè)定的規(guī)則,將各個(gè)段安排在存儲器中的相對位置,因此源程序中段之間的相對位置與可執(zhí)行的映像文件中段的相對位置一般不會相同。ARM匯編程序結(jié)構(gòu)分為基于Windows環(huán)境下ADS匯編語言程序設(shè)計(jì)結(jié)構(gòu)和Linux環(huán)境下GNU匯編語言程序設(shè)計(jì)結(jié)構(gòu),以下分別介紹。451.基于Windows環(huán)境下ADS的匯編語言程序結(jié)構(gòu)

ADS環(huán)境下的ARM匯編語言程序結(jié)構(gòu)與GNU環(huán)境下的匯編語言程序結(jié)構(gòu)大體相同,整個(gè)程序也是以段為單元來組織代碼。其語法規(guī)則總結(jié)如下:

所有標(biāo)號必須在一行的頂格書寫,其后不要添加“:”號。

所有的指令均不能頂格寫。

大小寫敏感(可以全部大寫或全部小寫,但不能大小寫混合使用)。

注釋使用分號“;”。應(yīng)用示例:AREAInit,CODE,READONLYENTRYstartLDRR0,=0x3FF5000;使用偽指令LDR將立即數(shù)0x3FF5000→R0

LDRR1,[R0]

;讀R0地址單元內(nèi)容→R1

LDRR0,=0x3FF5004;使用偽指令LDR將立即數(shù)0x3FF5004→R0

LDRR2,[R0]

ADDR3,R2,R1;R3←R2+R1

LDRR0,=0x3FF5008;使用偽指令LDR將立即數(shù)0x3FF5008→R0STRR3,[R0]

;R3的內(nèi)容寫入R0內(nèi)容作為字地址的存儲單元中

END

;標(biāo)識匯編源程序結(jié)束,其后如果還有內(nèi)容將會被忽略。在ADS環(huán)境中,使用偽指令A(yù)REA定義一個(gè)段,并說明定義段的屬性。本例定義了一個(gè)段名為Init的代碼段CODE,屬性為只讀READONLY;ENTRY偽指令標(biāo)識程序的入口點(diǎn);start為程序標(biāo)號,必須頂格書寫;462.基于Linux環(huán)境下GNU的匯編語言程序結(jié)構(gòu)Linux環(huán)境下GNU的匯編語言規(guī)則總結(jié)如下:

所有標(biāo)號必須在一行的頂格書寫,并且其后必須添加“:”號;

所有的指令均不能頂格寫;

大小寫敏感(可以全部大寫或全部小寫,但不能大小寫混合使用);

注釋使用符號“@”或使用C語言的/*注釋內(nèi)容*/注釋符。(注釋的內(nèi)容由“@”號起到此行結(jié)束,注釋可以在一行的頂格書寫)。應(yīng)用示例:.text@表示為只讀代碼段_start:.globalstart@_start作為連接器使用。在GNU環(huán)境下,必須在這使用此標(biāo)號.globalmain@聲明全局標(biāo)號main,在其它程序中調(diào)用,在C中就是調(diào)用的main函數(shù)

bmain@跳轉(zhuǎn)到main函數(shù)main:

movr0,#0/*使用mov指令將立即數(shù)0送r0*/

ldrr1,=0x01/*使用ldr偽指令將立即數(shù)0x01送r1*/addop:addr2,r1,r0@r2=r1+r0

movpc,lr@返回pc處

.end/*.end匯編結(jié)束偽指令*/473.ADS與GNU環(huán)境下程序代碼的比較與移植

在ADS環(huán)境下的匯編代碼與GNU環(huán)境下的匯編代碼有較多的不同點(diǎn),主要是符號與偽指令的不同,ARM指令的格式是基本相同的。掌握了它們之間的不同點(diǎn),將會更好地進(jìn)行它們之間的代碼移植。下表列出了在兩個(gè)環(huán)境下常用的偽指令的對應(yīng)關(guān)系。ADS偽指令GNU偽指令A(yù)DS偽指令GNU偽指令I(lǐng)NCLUDE.includeALIGN.alignTCLK2EQU30.equTCLK2,30MACRO.macroEXPORT.globalMEND.endmIMPORT.externEND.endDCD.long/.intAREAx,CODE,READONLY.textIF:DEF:.ifdefAREAy,DATA,READWRITE.dataELSE.elseCODE32.armENDIF.endifCODE16.thumb:AND:<ORG.ltorg:SHL:<<SPACE.zeroRN.regENTRY.entryGLBA.globalldrpc,[pc,#&10]ldrpc,[pc,#0x10]BUSWIDTHSETA16.equBUSWIDTH,16ldrpc,[pc,#&-10]ldrpc,[pc,#-0x10]483.ADS與GNU環(huán)境下程序代碼的比較與移植(續(xù))注意:ADS環(huán)境下的操作符與表達(dá)式在4.1.6節(jié)已經(jīng)介紹;GNU環(huán)境下的操作符有:“~”表示取數(shù)的補(bǔ)碼,“-”表示取負(fù),只有“<>”表示不等于,其它的符號如+、-、*、/、%、<、<<、>、>>、|、&、^、!、==、>=、<=、&&、||,與C語言中的用法相似。實(shí)際上,目前GNU環(huán)境下的許多操作符和表達(dá)式在ADS環(huán)境下也可以使用,以后將會看到。494.3ARM匯編語言與C語言混合編程在ARM的應(yīng)用系統(tǒng)中,匯編語言編程主要用于系統(tǒng)的啟動與初始化,之后通過調(diào)用C語言main()函數(shù)后基本進(jìn)入C語言的編程模式,關(guān)鍵涉及到的是它們在各自環(huán)境中定義的標(biāo)號(在C語言中可以是一個(gè)函數(shù))、變量、函數(shù)之間的相互使用問題。匯編語言和C/C++的混合編程通常有以下幾種方式:①在匯編語言程序中調(diào)用C程序。②在C語言程序中調(diào)用匯編程序。③在C語言程序中內(nèi)嵌匯編語句。④在匯編語言程序中訪問C語言程序變量。504.3.1基本的ATPCS基本的ATPCS(ARMThumbProcedureCallStandard)規(guī)定了在混合編程時(shí)子程序調(diào)用的一些基本規(guī)則,主要有:寄存器的使用;堆棧的使用;參數(shù)傳遞;子程序結(jié)果的返回等方面的規(guī)則。511.寄存器的使用規(guī)則①程序通過寄存器R0~R3來傳遞參數(shù),此時(shí)這些寄存器可以記作A0~A3,被調(diào)用的子程序在返回前無需恢復(fù)寄存器R0~R3的內(nèi)容。②在子程序中使用R4~R11來保存局部變量,此時(shí)這些寄存器可以記作V1~V8。③寄存器R12用作子程序間scratch寄存器,記作ip,在子程序的連接代碼段中經(jīng)常會有這種使用規(guī)則。Scratch寄存器用于保存SP寄存器,在函數(shù)返回時(shí)使用該寄存器出棧。④寄存器R13用作數(shù)據(jù)棧指針,記做SP,在子程序中寄存器R13不能用做其他用途。⑤寄存器R14用作連接寄存器,記作LR,它用于保存子程序的返回地址。⑥寄存器R15是程序計(jì)數(shù)器,記作PC,它不能用作其他用途。⑦ATPCS中的各寄存器在ARM編譯器和匯編器中都是預(yù)定義的。522.堆棧的使用規(guī)則堆對棧指針通??梢灾赶虿煌奈恢?,如果當(dāng)前堆棧指針指定的單元中存在有效數(shù)據(jù)時(shí),稱為FULL棧(滿棧)。如果當(dāng)前堆棧指針指定的單元中不存在有效數(shù)據(jù)時(shí),稱為Empty棧(空棧)。堆棧的增長方向也可以不同,當(dāng)堆棧向內(nèi)存減小的地址方向增長時(shí),稱為Descending棧(遞減棧);反之稱為Ascending棧(遞增棧)。注意:ATPCS規(guī)定堆棧使用FD(滿棧遞減型)類型,并要求堆棧的操作是8字節(jié)對齊的。也就是說在應(yīng)用系統(tǒng)的程序設(shè)計(jì)中,均使用的是該種類型的堆棧。533.參數(shù)的傳遞規(guī)則根據(jù)參數(shù)個(gè)數(shù)是否固定,可以將子程序分為參數(shù)個(gè)數(shù)固定的子程序和參數(shù)個(gè)數(shù)可變的子程序,這兩種子程序的參數(shù)傳遞規(guī)則是不同的。

第一,參數(shù)個(gè)數(shù)可變的子程序參數(shù)傳遞規(guī)則。對于參數(shù)個(gè)數(shù)可變的子程序,當(dāng)參數(shù)不超過4個(gè)時(shí),可以使用寄存器R0~R3來傳遞參數(shù);當(dāng)參數(shù)個(gè)數(shù)超過4個(gè)時(shí),可以使用堆棧來傳遞參數(shù)。

第二,參數(shù)個(gè)數(shù)固定的子程序參數(shù)傳遞規(guī)則。對于參數(shù)個(gè)數(shù)固定的子程序,參數(shù)傳遞與參數(shù)個(gè)數(shù)可變的子程序參數(shù)傳遞規(guī)則不同。如果系統(tǒng)包含浮點(diǎn)運(yùn)算的硬件部件,浮點(diǎn)參數(shù)將按照下面的規(guī)則傳遞:各個(gè)浮點(diǎn)參數(shù)按順序處理;為每個(gè)浮點(diǎn)參數(shù)分配FP寄存器;分配的方法是,滿足該浮點(diǎn)參數(shù)需要的且編號最小的一組連續(xù)的FP寄存器。第1個(gè)整數(shù)參數(shù)通過寄存器R0~R3來傳遞,其他參數(shù)通過堆棧來傳遞.544.子程序結(jié)果返回規(guī)則結(jié)果為一個(gè)32位的整數(shù)時(shí),可通過寄存器R0返回。結(jié)果為一個(gè)64位整數(shù)時(shí),可以通R0和R1返回,依此類推。結(jié)果為一個(gè)浮點(diǎn)數(shù)時(shí),可以通過浮點(diǎn)運(yùn)算部件的寄存器f0,d0或者s0來返回。結(jié)果為一個(gè)復(fù)合的浮點(diǎn)數(shù)時(shí),可以通過寄存器f0-fN或者d0~dN來返回。對于位數(shù)更多的結(jié)果,則需要通過調(diào)用內(nèi)存來傳遞。554.3.2匯編語言程序調(diào)用C語言程序在匯編語言中調(diào)用C語言,需要使用IMPORT對C函數(shù)進(jìn)行說明;然后將C的代碼放在一個(gè)獨(dú)立的C文件中進(jìn)行編譯,剩下的工作由連接器完成。應(yīng)用示例:該項(xiàng)目由1個(gè)匯編語言文件和1個(gè)C語言文件組成,以下是它們的代碼內(nèi)容。1.匯編語言文件:

AREAasmfile,CODE,READONLY

IMPORTcFun;聲明在C語言中定義的函數(shù)

ENTRY

;匯編程序入口

MOVR0,#0;傳遞函數(shù)cFun第1參數(shù)

MOVR1,#1;傳遞函數(shù)cFun第2參數(shù)

MOVR2,#2;傳遞函數(shù)cFun第3參數(shù)

blcFun;調(diào)用C語言函數(shù)

MOVR3,R0;將調(diào)用C語言函數(shù)的結(jié)果保存在R3中

END

;匯編結(jié)束偽指令562.C語言文件/*Cfile,calledbyasmfile*/intcFun(inta,intb,intc)/*C語言函數(shù)定義,形參分別對應(yīng)R0、R1、R2寄存器*/{returna+b+c;}注意:在匯編語言程序中聲明C語言函數(shù)時(shí)只使用函數(shù)名,C語言中的函數(shù)名是一個(gè)常量地址;由于C語言中函數(shù)使用的形參是整型變量,所以在匯編語言傳遞參數(shù)時(shí)使用的是寄存器,即對應(yīng)于寄存器尋址;這里的參數(shù)傳遞是利用寄存器R0~R2。需要指出的是當(dāng)函數(shù)的參數(shù)個(gè)數(shù)大于4時(shí)就要借助于堆棧。57

4.3.3C語言程序中調(diào)用匯編語言程序在匯編程序中使用EXPORT偽指令聲明程序(是一個(gè)標(biāo)號),使得本程序可以被其他的程序調(diào)用;在C語言中使用EXTERN關(guān)鍵詞聲明該匯編程序,這樣就可以在C中使用該函數(shù)了。從C的角度,并不知道該函數(shù)的實(shí)現(xiàn)是用C語言還是匯編語言。應(yīng)用示例:該項(xiàng)目由1個(gè)C語言文件和1個(gè)匯編語言文件組成,以下是它們的代碼內(nèi)容。581.C語言文件#include<stdio.h>

externvoidasm_strcpy(constchar*src,char*dest);/*將匯編語言中的子程序聲明為C語言函數(shù)*/intmain(){constchar*s=“hello,world!”;chard[32];asm_strcpy(s,d);/*調(diào)用聲明的函數(shù)*/printf(“source,%s”,s);printf(“destination:%d”,d);return0;}2.匯編語言文件AREAasmfile,CODE,READONLY;定義一個(gè)名為asmfile的代碼段EXPORTasm_strcpy;聲明匯編程序標(biāo)號,在C語言中可以調(diào)用并且將作為一個(gè)函數(shù)名asm_strcpy;匯編程序入口標(biāo)號,C語言中的程序名loopldrbr4,[r0],#1;r0在C函數(shù)中作為第1個(gè)參數(shù)。r4←[r0],r0←r0+1cmpr4,#0beqover;如果是字符串結(jié)尾,eq=1,程序跳轉(zhuǎn)到標(biāo)號over處strbr4,[r1],#1;r1在C函數(shù)中作為第2個(gè)參數(shù)。[r0]←r4,r1←r1+1bloopovermovpc,lr;pc←lr,子程序返回END594.3.4C語言程序中內(nèi)嵌匯編語言程序在C程序中內(nèi)嵌的匯編指令支持大部分的ARM和Thumb指令,不過其使用與匯編文件中的指令有些不同,存在一些限制,主要有下面幾個(gè)方面:①不能直接向PC賦值,程序跳轉(zhuǎn)要使用B或者BL指令;②在使用物理寄存器時(shí),不要使用過于復(fù)雜的C表達(dá)式,避免物理寄存器沖突;③R12和R13可能被編譯器用來存放中間編譯結(jié)果;④一般不要直接指定物理寄存器,而讓編譯器進(jìn)行分配;601.內(nèi)嵌匯編語言標(biāo)記內(nèi)嵌匯編語言標(biāo)記是__asm或者asm關(guān)鍵字,用法如下:__asm{

指令1[;注釋]……

指令n}

或:在關(guān)鍵字asm后使用圓括號“()”將關(guān)鍵字為__asm中的花括號“{}”代換也可。2.應(yīng)用示例#include<stdio.h>voidmy_strcpy(constchar*src,char*dest)/*定義字符串拷貝函數(shù)*/{charch;/*定義字符串變量,在匯編中有系統(tǒng)指定寄存器替換*/__asm/*使用內(nèi)嵌匯編關(guān)鍵字*/{loopldrbch,[src],#1;src寄存器間接尋址,編譯時(shí)系統(tǒng)指定R0。ch←[src],src←src+1

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論