第三章 ARM汇编语言程序设计——ARM
1.ARM匯編的語句格式
匯編語言都具有一些相同的基本特征。
-
一條指令一行。
-
使用標(biāo)號(label)給內(nèi)存單元提供名稱,從第1列開始書寫。
-
指令必須從第2列或能區(qū)分標(biāo)號的地方開始書寫。
-
注釋跟在指定的注釋字符后面(ARM使用的是“;”),一直書寫到行尾。
{symbol} {instruction |directive | pseudo-instruction} {;comment} 符號 指令、偽指令或偽操作 [; 注釋]
ARM匯編語言基本的的語句格式如下:
(1)符號命名規(guī)則:
- 符號由大小寫字母、數(shù)字及下畫線組成,符號不能用數(shù)字開頭。
- 符號區(qū)分大小寫,同名的大、小寫符號會(huì)被編譯器認(rèn)為是兩個(gè)不同的符號。
- 符號在其作用范圍內(nèi)必須唯一。
- 自定義的符號名不能與系統(tǒng)的保留字相同。
- 符號名不應(yīng)與指令或偽指令同名。
(2)偽操作
偽操作(Directive)是ARM匯編語言程序里的一些特殊的指令助記符,其作用主要是為完成匯編程序做各種準(zhǔn)備工作,對源程序運(yùn)行匯編程序處理,而不是在計(jì)算機(jī)運(yùn)行期間由處理器執(zhí)行。
常用偽操作列表:
介紹:
-
ENTRY 和 END
- 定義程序入口點(diǎn)偽指令 ENTRY用于指定匯編程序的入口點(diǎn)
- 匯編結(jié)束偽指令 END 用于通知編譯器匯編工作到此結(jié)束,不再往下匯編了
-
EXPORT(或GLOBAL)和 IMPORT(或EXTERN)
格式:EXPORT 符號 {[WEAK]}符號在程序中區(qū)分大小寫[WEAK] 選項(xiàng)聲明其他的同名符號優(yōu)先于該符號被引用
外部可引用符號聲明偽指令EXPORT(或GLOBAL)可以聲明一個(gè)其他源文件可引用的符號,這種符號也叫做外部可引用符號。
當(dāng)在一個(gè)源文件中需要使用另外一個(gè)源文件的外部可引用符號時(shí),在被引用的符號前面必須使用偽指令 IMPORT 對其進(jìn)行聲明
格式:IMPORT 符號 {[WEAK]} [WEAK] 選項(xiàng)表示當(dāng)前所有的源文件都沒有定義這樣一個(gè)符號時(shí),編譯器也不報(bào)錯(cuò),并在多數(shù)情況下將該符號置為0如果源文件聲明了一個(gè)引用符號,則無論當(dāng)前源文件中程序是否真正地使用了該符號,該符號均會(huì)被加入到當(dāng)前源文件的符號表中
(3)偽指令
偽指令是ARM處理器支持的匯編語言程序里的特殊助記符,它不在處理器運(yùn)行期間由機(jī)器執(zhí)行,只是在匯編時(shí)將被合適的機(jī)器指令代替成ARM或Thumb指令,從而實(shí)現(xiàn)真正的指令操作。
①段定義偽指令
②符號定義偽指令
符號的命名由編程者決定,但有以下約定:
符號區(qū)分大小寫,同名的大、小寫符號會(huì)被編譯器認(rèn)為是兩個(gè)不同的符號 符號在其作用范圍內(nèi)必須唯一 自定義的符號不能與系統(tǒng)保留字相同 符號不應(yīng)與指令或偽指令同名-
全局變量偽指令(GBLA、GBLL、GBLS):
例如:GBLA Test1 ;定義一個(gè)全局?jǐn)?shù)字變量,變量名為Test1,默認(rèn)初值為0GBLL Test2 ;定義一個(gè)全局邏輯變量,變量名為Test2,默認(rèn)初值為FGBLS Test3 ;定義一個(gè)全局字符串變量,變量名為Test3,默認(rèn)初值為空
GBLA、GBLL 和 GBLS 偽指令用于定義一個(gè)ARM程序中的全局變量,并將其初始化。全局變量的變量名在整個(gè)程序范圍內(nèi)必須具有唯一性。
-
局部變量偽指令(LCLA、LCLL、LCLS )
例如:LCLA Test4 ;定義一個(gè)局部數(shù)字變量,變量名為Test4,默認(rèn)初值為0LCLL Test5 ;定義一個(gè)局部邏輯變量,變量名為Test5,默認(rèn)初值為FLCLS Test6 ;定義一個(gè)局部字符串變量,變量名為Test6,默認(rèn)初值為空
LCLA、LCLL 和 LCLS 偽指令用于定義一個(gè)ARM程序中的局部變量,并將其初始化
局部變量的變量名在變量作用范圍內(nèi)必須具有唯一性。默認(rèn)情況下,局部變量只在定義該變量的程序段內(nèi)有效
-
變量賦值偽指令(SETA、SETL、SETS)
例如: Test1 SETA 0xAA ;將Test1變量賦值為0xAATest2 SETL {TRUE} ;將Test2變量賦值為真Test3 SETS "Testing" ;將Test3變量賦值為“Testing”
SETA、SETL 和 SETS 偽指令用于給一個(gè)已經(jīng)定義的全局變量或局部變量進(jìn)行賦值 -
定義寄存器列表偽指令 RLIST
格式: <name> RLIST <{list}>name :為表名稱{list} :為寄存器列表,列表中的寄存器訪問次序根據(jù)寄存器的編號由低到高,而與列表中的寄存器排列次序無關(guān)例如:RegList RLIST {R0-R5,R8,R10} ;將寄存器列表名稱定義為RegList
指令 LDM/STM 需要使用一個(gè)比較長的寄存器列表,使用偽指令 RLIST 可對一個(gè)列表定義一個(gè)統(tǒng)一的名稱
③程序中的標(biāo)號
在匯編語言中用來表示地址的符號就叫做標(biāo)號
根據(jù)用途不同標(biāo)號主要有以下2種:
- 目標(biāo)地址標(biāo)號:寫在一條指令前面的標(biāo)號
- 數(shù)據(jù)或數(shù)據(jù)區(qū)首地址標(biāo)號:寫在數(shù)據(jù)或數(shù)據(jù)區(qū)定義偽指令前面的標(biāo)號
④數(shù)據(jù)定義偽指令
該指令的功能就是為指定的數(shù)據(jù)分配存儲(chǔ)單元,以及用該數(shù)據(jù)對已分配存儲(chǔ)單元進(jìn)行初始化。
-
DCB(可用“=”代替)
格式: {<label>} DCB <expr> label 為標(biāo)號,為存儲(chǔ)區(qū)域的首地址(可選)expr 為表達(dá)式,為從標(biāo)號開始存放的數(shù)據(jù)。該表達(dá)式可以為0~255的數(shù)字或字符串
用于分配一片連續(xù)的以字節(jié)為單位的存儲(chǔ)區(qū)域(操作數(shù)可以為-128~255的數(shù)值或字符串),并用指定的表達(dá)式對其進(jìn)行初始化。 -
DCW(或DCWU)
格式:<label> DCW(或DCWU) <expr>表達(dá)式可以為程序標(biāo)號或數(shù)字表達(dá)式
用于為數(shù)據(jù)分配一片連續(xù)的半字存儲(chǔ)單元(操作數(shù)是16位二進(jìn)制數(shù)),并用表達(dá)式對其進(jìn)行初始化。用 DCW 分配的半字存儲(chǔ)單元是嚴(yán)格按半字對齊的,而用DCWU 分配的半字存儲(chǔ)單元并不嚴(yán)格按半字對齊。
-
DCD(或DCDU)(可用“&”代替)
格式:<label> DCD(或DCDU) <expr>表達(dá)式可以為程序標(biāo)號或數(shù)字表達(dá)式
用于分配一片連續(xù)的字存儲(chǔ)單元(操作數(shù)可以是32位的數(shù)字表達(dá)式),并用偽指令中指定的表達(dá)式初始化。用 DCD 分配的字存儲(chǔ)單元是字對齊的,而用 DCDU 分配的字存儲(chǔ)單元并不嚴(yán)格要求字對齊。
-
DCFD(或DCFDU)
格式:<label> DCFD(或DCFDU) <expr>
用于為雙精度的浮點(diǎn)數(shù)分配一片連續(xù)的字存儲(chǔ)單元,并用偽指令中指定的表達(dá)式初始化每個(gè)雙精度的浮點(diǎn)數(shù)占據(jù)兩個(gè)字單元用 DCFD 分配的字存儲(chǔ)單元是字對齊的而用 DCFDU 分配的字存儲(chǔ)單元并不嚴(yán)格字對齊
-
DCFS(或DCFSU)
格式:<label> DCFS(或DCFSU) <expr>
用于為單精度的浮點(diǎn)數(shù)分配一片連續(xù)的字存儲(chǔ)單元,并用偽指令中指定的表達(dá)式初始化每個(gè)單精度浮點(diǎn)數(shù)占據(jù)一個(gè)字單元用 DCFS 分配的字存儲(chǔ)單元是字對齊的而用 DCFSU 分配的字存儲(chǔ)單元并不嚴(yán)格字對齊
-
DCQ(或DCQU)
格式:label> DCQ(或DCQU) <expr>
用于分配一片以8字節(jié)為單位的連續(xù)存儲(chǔ)區(qū)域,并用偽指令中指定的表達(dá)式初始化用 DCQ 分配的存儲(chǔ)單元是字對齊的,而用 DCQU 分配的字存儲(chǔ)單元并不嚴(yán)格字對齊
-
SPACE(可用“%”代替)
格式:<label> SPACE <expr>
用于分配一片連續(xù)的存儲(chǔ)區(qū)域并初始化為0 -
LTORG
例如:AREA example, CODE, READONLYStart BL Func1…Func1 LDR R1,=0x800MOV PC,LRLTORG ;定義數(shù)據(jù)緩沖池的開始位置Date SPACE 40 ;數(shù)據(jù)緩沖池有40個(gè)被初始化為0的字節(jié) END
來說用明某個(gè)存儲(chǔ)區(qū)域?yàn)橐粋€(gè)用來暫存數(shù)據(jù)的數(shù)據(jù)緩沖區(qū),也叫文字池或數(shù)據(jù)緩沖池。
大的代碼段也可以使用多個(gè)數(shù)據(jù)緩沖池。當(dāng)程序中使用 LDR 之類的指令訪問數(shù)據(jù)緩沖池時(shí),為防止越界發(fā)生,通常把數(shù)據(jù)緩沖池放在代碼段的最后面,或放在無條件轉(zhuǎn)移指令或子程序返回指令之后,這樣處理器就不會(huì)錯(cuò)誤地將數(shù)據(jù)緩沖池中的數(shù)據(jù)當(dāng)作指令來執(zhí)行。
-
MAP 和 FIELD
-
MAP 用于定義一個(gè)結(jié)構(gòu)化的內(nèi)存表的首地址
格式:MAP <expr> {,<baseregister>}expr 為結(jié)構(gòu)化表首地址,可以為標(biāo)號或數(shù)字表達(dá)式baseregister 為基址寄存器(可選項(xiàng))基址寄存器的值與 expr 的值之和就是表首地址
-
FIELD 偽指令用于定義一個(gè)結(jié)構(gòu)化內(nèi)存表中的數(shù)據(jù)域
格式:<label> FIELD <expr> label 為標(biāo)號(為數(shù)據(jù)域指定一個(gè)標(biāo)號供其他指令引用)expr 為表達(dá)式,它的值為數(shù)據(jù)域所占的字節(jié)數(shù)FIELD 偽指令與 MAP 偽指令配合使用來定義結(jié)構(gòu)化的內(nèi)存表。
只用于定義數(shù)據(jù)結(jié)構(gòu),不分配存儲(chǔ)單元。
-
⑤匯編控制偽指令
-
IF、ELSE 和 ENDIF
例如:GBLL Test ;聲明一個(gè)全局邏輯變量Test...IF Test = TRUE程序段1 ELSE程序段2ENDIF
根據(jù)條件的成立與否決定是否執(zhí)行某個(gè)程序段
IF、ELSE、ENDIF 偽指令可以嵌套使用 -
WHILE 和 WEND
例如:GBLA Counter ;聲明一個(gè)全局?jǐn)?shù)字變量CounterCounter SETA 3 ;賦值...WHILE Counter < 10程序段WEND
根據(jù)條件的成立與否決定是否重復(fù)匯編一個(gè)程序段
若 WHILE 后面的邏輯表達(dá)式為真,則重復(fù)匯編該程序段,直到邏輯表達(dá)式為假
WHILE 和 WEND 偽指令可以嵌套使用
⑥其他常用的偽指令
偽指令列表偽指令 語法格式 功能ADR ADR{cond} register,=expression 它將基于PC相對偏移的地址值或基于寄存器相對偏移的地址值讀取到寄存器中ADRL ADRL{cond} register,=expression 它將基于PC相對偏移的地址值或基于寄存器相對偏移的地址值讀取到寄存器中LDR LDR{cond} register,=expression 將一個(gè)32位的常數(shù)或者一個(gè)地址值讀取到寄存器中,可以看做是加載寄存器的內(nèi)容NOP NOP 是空操作偽指令,在匯編時(shí)將會(huì)被替代成ARM中的空操作-
ADR偽指令————小范圍的地址讀取
當(dāng)?shù)刂分凳亲止?jié)對齊時(shí),其取指范圍為?255B~255B;當(dāng)?shù)刂分凳亲謱R時(shí),其取指范圍為?1020B~1020B。
在匯編編譯器編譯源程序時(shí),ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來實(shí)現(xiàn)該ADR偽指令的功能,若不能用一條指令實(shí)現(xiàn),則產(chǎn)生錯(cuò)誤,編譯失敗。ADR偽指令中的地址是基于PC或寄存器的,當(dāng)ADR偽指令中的地址是基于PC時(shí),該地址與ADR偽指令必須在同一個(gè)代碼段中。
地址表達(dá)式expr的取值范圍如下: -
ADRL偽指令————中等范圍的地址讀取
當(dāng)?shù)刂分凳亲止?jié)對齊時(shí),其取指范圍為?64KB~64KB;當(dāng)?shù)刂分凳亲謱R時(shí),其取指范圍為?256KB~256KB。
ADRL比ADR偽指令可以讀取更大范圍的地址。在匯編編譯器編譯源程序時(shí),ADRL偽指令被編譯器替換成兩條合適的指令。若不能用兩條指令實(shí)現(xiàn),則產(chǎn)生錯(cuò)誤,編譯失敗。
地址表達(dá)式expr的取值范圍如下: -
LDR偽指令————大范圍的地址讀取
格式:LDR{cond} reg,={expr | label - expr}reg:目標(biāo)寄存器名稱expr:32位常數(shù)label – expr:為基于PC地址表達(dá)式程序經(jīng)常用這條指令把一個(gè)地址傳遞到寄存器 reg 中
在匯編編譯源程序時(shí),LDR偽指令被編譯器替換成一條合適的指令。若加載的常數(shù)未超出MOV或MVN的范圍,則使用MOV或MVN指令代替該LDR偽指令,否則匯編器將常量放入文字池,并使用一條程序相對偏移的LDR指令從文字池讀出常量。匯編器在對這種指令進(jìn)行匯編時(shí),會(huì)根據(jù)指令中 expr 的值的大小來把這條指令替換為合適的指令
- 當(dāng)expr的值未超過MOV或MVN指令所限定的取值范圍時(shí),匯編器用ARM的MOV或MVN指令來取代宏指令LDR
- 當(dāng)expr的值超過MOV或MVN指令所限定的取值范圍時(shí),匯編器將常數(shù)expr放在由LTORG定義的文字緩沖池,同時(shí)用一條ARM的裝載指令LDR來取代宏指令LDR,而這條裝載LDR指令則用PC加偏移量的方法到文字緩沖池中把該常數(shù)讀取到指令指定的寄存器。
2.ARM匯編的程序結(jié)構(gòu)
在 ARM ( Thumb )匯編語言程序中,以程序段為單位組織代碼。段是相對獨(dú)立的指令或數(shù)據(jù)序列,具有特定的名稱。
段可以分為代碼段和數(shù)據(jù)段,代碼段的內(nèi)容為執(zhí)行代碼,數(shù)據(jù)段存放代碼運(yùn)行時(shí)需要用到的數(shù)據(jù)。
一個(gè)匯編程序至少應(yīng)該有一個(gè)代碼段,當(dāng)程序較長時(shí),可以分割為多個(gè)代碼段和數(shù)據(jù)段,多個(gè)段在程序編譯鏈接時(shí)最終形成一個(gè)可執(zhí)行的映象文件。
可執(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è)段安排在存儲(chǔ)器中的相應(yīng)位置。因此源程序中段之間的相對位置與可執(zhí)行的映象文件中段的相對位置一般不會(huì)相同。
(1)順序程序設(shè)計(jì)
沒有分支、循環(huán)等架構(gòu)的程序,會(huì)順序執(zhí)行匯編指令;
AREA EXAMPLE,CODE,READONLY ; 定義段的名稱和屬性,表示了一個(gè)段的開始ENTRY ; 標(biāo)識(shí)程序的入口點(diǎn) start ; 以下為具體指令MOV R0,#10 MOV R1,#3ADD R0,R0,R1END ; 標(biāo)識(shí)源文件的結(jié)束(2)分支程序設(shè)計(jì)
ARM匯編中大部分的指令都支持條件執(zhí)行,類似C語言中的if-else分支。
ADD指令可以根據(jù)已執(zhí)行代碼對狀態(tài)寄存器的影響來決定是否執(zhí)行,從而構(gòu)成簡單的分支結(jié)構(gòu)。
B、BL可以條件執(zhí)行,從而構(gòu)成復(fù)雜的分支架構(gòu)。
例如: CMP R1,#3 ; 比較R1和#3BHI END ; if R1>3 then ENDADD R0,R0,#3 ; R0=R0+3END(3)循環(huán)程序設(shè)計(jì)
用預(yù)先設(shè)定的行標(biāo)與B、BL結(jié)合可以設(shè)計(jì)各種循環(huán)結(jié)構(gòu)。
例如: LOOP ADD R0,R0,R1 ; R0=R0+R1CMP R0,#3 ; 比較R0和#3 BLS LOOP ; if R0<3 then 跳轉(zhuǎn)到LOOP 循環(huán)END(4)子程序
在ARM匯編語言程序中,子程序的調(diào)用一般是通過BL指令來實(shí)現(xiàn)的。
在程序中,使用指令:
BL子程序名,即可完成子程序的調(diào)用。
該指令在執(zhí)行時(shí)完成如下操作:
將子程序的返回地址存放在連接寄存器LR中,同時(shí)將程序計(jì)數(shù)器PC指向子程序的入口點(diǎn),當(dāng)子程序執(zhí)行完畢需要返回調(diào)用處時(shí),只需要將存放在LR中的返回地址重新復(fù)制給程序計(jì)數(shù)器PC即可。在調(diào)用子程序的同時(shí),也可以完成參數(shù)的傳遞和從子程序返回運(yùn)算的結(jié)果,通常可以使用寄存器R0~R3完成。
以下是使用BL指令調(diào)用子程序的匯編語言源程序的基本結(jié)構(gòu):
3.ATPCS[ARM-Thumb Procedure Call Standard(PCS,Procedure Call Standard(過程調(diào)用規(guī)范))]
(1)寄存器的使用規(guī)則
ATPCS中定義的寄存器寄存器 R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15sysnonym a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 special WR SB SL FP IP SP LR PC 其中:R0~R3:用于傳參,r0用于返回值。R4~R11:通用變量寄存器。 R12:用作過程調(diào)用中間臨時(shí)過渡寄存器IP。R13:堆棧指針。R14:連接寄存器。R15:PC。另外,R9、R10和R11還有一個(gè)特殊作用,分別記為:靜態(tài)基址寄存器SB,數(shù)據(jù)棧限制指針SL和楨指針FP。
- 子程序通過寄存器R0~R3來傳遞參數(shù),這時(shí)寄存器可以記作A0~A3,被調(diào)用的子程序在返回前無須恢復(fù)寄存器R0~R3的內(nèi)容。
- 在子程序中,使用R4~R11來保存局部變量,這時(shí)寄存器R4~R11可以記作V1~V8。
如果在子程序中使用到V1~V8的某些寄存器,子程序進(jìn)入時(shí)必須保存這些寄存器的值,在返回前必須恢復(fù)這些寄存器的值,對于子程序中沒有用到的寄存器則不必執(zhí)行這些操作。在Thumb程序中,通常只能使用寄存器R4~R7來保存局部變量。 - 寄存器R12用作子程序間臨時(shí)過渡寄存器,記作IP,在子程序的連接代碼段中經(jīng)常會(huì)有這種使用規(guī)則。
- 寄存器R13用作數(shù)據(jù)棧指針,記做SP,在子程序中寄存器R13不能用作其他用途。寄存器SP在進(jìn)入子程序時(shí)的值和退出子程序時(shí)的值必須相等。
- 寄存器R14用作連接寄存器,記作LR。它用于保存子程序的返回地址,如果在子程序中保存了返回地址,則R14可用作其他的用途。
- 寄存器R15是程序計(jì)數(shù)器,記作PC,它不能用作其他用途。
- ATPCS中的各寄存器在ARM編譯器和匯編器中都是預(yù)定義的。
(2)數(shù)據(jù)棧的使用規(guī)則
- 數(shù)據(jù)棧指針(stack pointer):指向最后一個(gè)寫入棧的數(shù)據(jù)的內(nèi)存地址。
- 數(shù)據(jù)棧的基地址(stack base):指數(shù)據(jù)棧的最高地址。由于ATPCS中的數(shù)據(jù)棧是FD類型的,實(shí)際上數(shù)據(jù)棧中最早入棧數(shù)據(jù)占據(jù)的內(nèi)存單元是基地址的下一個(gè)內(nèi)存單元。
- 數(shù)據(jù)棧界限(stack limit):數(shù)據(jù)棧中可以使用的最低的內(nèi)存單元地址。
- 已占用的數(shù)據(jù)棧(used stack):數(shù)據(jù)棧的基地址和數(shù)據(jù)棧棧指針之間的區(qū)域,其中包括數(shù)據(jù)棧棧指針對應(yīng)的內(nèi)存單元。
- 數(shù)據(jù)棧中的數(shù)據(jù)幀(stack frames):在數(shù)據(jù)棧中,為子程序分配的用來保存寄存器和局部變量的區(qū)域。
(3)參數(shù)的傳遞規(guī)則
- 參數(shù)個(gè)數(shù)可變的子程序參數(shù)傳遞規(guī)則
對于參數(shù)個(gè)數(shù)可變的子程序,當(dāng)參數(shù)不超過4個(gè)時(shí),可以使用寄存器R0~R3來進(jìn)行參數(shù)傳遞;當(dāng)參數(shù)超過4個(gè)時(shí),還可以使用數(shù)據(jù)棧來傳遞參數(shù)。在參數(shù)傳遞時(shí),將所有參數(shù)看做是存放在連續(xù)的內(nèi)存單元中的字?jǐn)?shù)據(jù)。然后,依次將各名字?jǐn)?shù)據(jù)傳送到寄存器R0,R1,R2,R3;如果參數(shù)多于4個(gè),將剩余的字?jǐn)?shù)據(jù)傳送到數(shù)據(jù)棧中,入棧的順序與參數(shù)順序相反,即最后一個(gè)字?jǐn)?shù)據(jù)先入棧。按照上面的規(guī)則,一個(gè)浮點(diǎn)數(shù)參數(shù)可以通過寄存器傳遞,也可以通過數(shù)據(jù)棧傳遞,也可能一半通過寄存器傳遞,另一半通過數(shù)據(jù)棧傳遞。 - 參數(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ù)通過數(shù)據(jù)棧傳遞。
(4)子程序結(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)存來傳遞。
4.C語言及匯編語言混合編程
(1)在C / C++程序中使用內(nèi)嵌的匯編指令
在ARM C語言程序中,使用關(guān)鍵字__asm來標(biāo)識(shí)一段匯編指令程序。
程序格式如下所示:
其中一條指令占據(jù)多行的時(shí)候,要使用續(xù)行符號( \ )。必須小心使用物理寄存器,如R0 ~ R3、SP、LR和CPSR中的N、Z、C、V標(biāo)志位,因?yàn)橛?jì)算匯編代碼中的C表達(dá)式時(shí),可能會(huì)使用這些物理寄存器,并修改N、Z、C、V標(biāo)志位。
(2)從匯編程序中訪問C程序變量
在C程序中的聲明的全局變量可以被匯編程序通過地址間接訪問。
具體訪問方法如下:
-
使用IMPORT偽指令聲明這個(gè)全局變量。
-
使用LDR指令讀取該全局變量的內(nèi)存地址,通常該全局變量的內(nèi)存地址存放在程序的數(shù)據(jù)緩沖池中。
-
根據(jù)該數(shù)據(jù)類型,使用相應(yīng)的LDR指令讀取該全局變量的值,使用相應(yīng)的STR指令修改該全局變量的值。
AREA globals, CODE, READONPYEXPORT asmsubIMPORT glovbver ;聲明外部變量glovbverasmsubLDR R1, =glovbver ;裝載變量地址LDR R0, [R1] ;讀出數(shù)據(jù)ADDR R0, R0, #1 ;加1操作STR R0, [R1] ;保存變量值MOV PC, LREND
(3)C程序與匯編程序相互調(diào)用規(guī)則
-
寄存器的使用規(guī)則:
- 子程序間通過寄存器R0 ~ R3來傳遞參數(shù)。
- 在子程序中,使用寄存器R4 ~ R11來保存局部變量。
- 寄存器R12用于保存SP,在函數(shù)返回時(shí)使用該寄存器出棧,記作IP。
- 寄存器R13用于數(shù)據(jù)棧指針,記作SP,寄存器SP在進(jìn)入子程序時(shí)的值和退出寄存器時(shí)的值必須相等。
- 寄存器R14稱為鏈接寄存器,記作LR,它用于保存子程序的返回地址。
- 寄存器R15是程序計(jì)數(shù)器,記作PC。
-
堆棧的使用規(guī)則:
堆棧采用滿遞減類型(FD,Full Descending),即堆棧通過減小存儲(chǔ)器地址而向下增長,堆棧指針指向內(nèi)含有效數(shù)據(jù)項(xiàng)的最低地址。 -
參數(shù)的傳遞規(guī)則:
整數(shù)參數(shù)的前4個(gè)使用r0~r3傳遞,其他參數(shù)使用堆棧傳遞;
子程序的返回結(jié)果為一個(gè)32位整數(shù)時(shí),通過r0返回;
返回結(jié)果為一個(gè)64位整數(shù)時(shí),通過r0和r1返回;
依此類推。
總結(jié)
以上是生活随笔為你收集整理的第三章 ARM汇编语言程序设计——ARM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 24个笔画顺序表_小学一年级语文26个汉
- 下一篇: llvm编译linux,在Linux上编