為了使單獨(dú)編譯的C語(yǔ)言程序和匯編程序之間能夠相互調(diào)用,必須為子程序之間的調(diào)用規(guī)定一定的規(guī)則,ATPCS就是ARM程序和THUMB程序中子程序調(diào)用的基本規(guī)則。
1. ATPCS
ATPCS即ARM Thumb Procedure Call Standard(ARM-Thumb過(guò)程調(diào)用標(biāo)準(zhǔn))的簡(jiǎn)稱(chēng),ATPCS規(guī)定了一些調(diào)用和被調(diào)用程序之間調(diào)用的基本規(guī)則,這些基本規(guī)則包括子程序調(diào)用過(guò)程中寄存器的使用規(guī)則、數(shù)據(jù)棧的使用規(guī)則、參數(shù)的傳遞規(guī)則。為適應(yīng)一些特定的需要,對(duì)這些基本的調(diào)用規(guī)則進(jìn)行一些修改得到幾種不同的子程序調(diào)用規(guī)則,這些特定的調(diào)用規(guī)則包括:
-
支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS
-
支持只讀段位置無(wú)關(guān)的ATPCS
-
支持可讀寫(xiě)段位置無(wú)關(guān)的ATPCS
-
支持ARM程序和THUMB程序混合使用的ATPCS
有調(diào)用關(guān)系的所有子程序必須遵守同一種ATPCS,編譯器或者匯編器在ELF格式的目標(biāo)文件中設(shè)置相應(yīng)的屬性,標(biāo)識(shí)用戶(hù)選定的ATPCS類(lèi)型。對(duì)應(yīng)不同類(lèi)型的ATPCS規(guī)則,有相應(yīng)的C語(yǔ)言庫(kù),連接器根據(jù)用戶(hù)指定的ATPCS類(lèi)型連接相應(yīng)的C語(yǔ)言庫(kù)。使用ADS的C語(yǔ)言編譯器編譯的C語(yǔ)言子程序滿(mǎn)足用戶(hù)指定的ATPCS類(lèi)型。而對(duì)于匯編語(yǔ)言程序來(lái)說(shuō),完全要依賴(lài)用戶(hù)來(lái)保證各子程序滿(mǎn)足選定的ATPCS類(lèi)型。具體來(lái)說(shuō),匯編語(yǔ)言子程序必須滿(mǎn)足下面三個(gè)條件:在子程序編寫(xiě)時(shí)必須遵守相應(yīng)的ATPCS規(guī)則;數(shù)據(jù)棧的使用要遵守ATPCS規(guī)則;在匯編編譯器中使用“--apcs”選項(xiàng),使用“--apcs”選項(xiàng)并不影響代碼的產(chǎn)生,編譯器只是在各段中放置相應(yīng)的屬性,標(biāo)識(shí)用戶(hù)選定的屬性。
2. ATPCS基本規(guī)則
基本ATPCS規(guī)定了在子程序調(diào)用時(shí)的一些基本規(guī)則,包括以下四個(gè)方面的內(nèi)容:
-
各寄存器的使用規(guī)則及其相應(yīng)的名字
-
數(shù)據(jù)棧的使用規(guī)則
-
參數(shù)傳遞的規(guī)則
-
函數(shù)結(jié)果返回的規(guī)則
相對(duì)于其他類(lèi)型的TPCS,滿(mǎn)足基本ATPCS的程序的執(zhí)行速度更快,所占用的內(nèi)存更少。但是它不能提供以下的支持:ARM程序和THUMB程序相互調(diào)用;數(shù)據(jù)以及代碼的位置無(wú)關(guān)的支持;子程序的可重入性;數(shù)據(jù)棧檢查的支持。而派生的其他幾種特定的ATPCS就是在基本ATPCS的基礎(chǔ)上再添加其他的規(guī)則而形成的 ,其目的就是提供上述的功能。
2.1 寄存器的使用規(guī)則
?前四個(gè)寄存器R0~R3用于將參數(shù)值傳遞到例程中并將結(jié)果值傳遞出例程,并在例程中保存中間值(但通常僅在子例程調(diào)用之間),子程序通過(guò)寄存器R0~R3來(lái)傳遞參數(shù),這時(shí)寄存器可以記作:A1~A4,被調(diào)用的子程序在返回前無(wú)需恢復(fù)寄存器R0~R3的內(nèi)容。在子程序中,使用R4~R11來(lái)保存局部變量,這時(shí)寄存器R4~R11可以記作:V1~V8 。如果在子程序中使用到V1~V8的某些寄存器,子程序進(jìn)入時(shí)必須保存這些寄存器的值,在返回前必須恢復(fù)這些寄存器的值,對(duì)于子程序中沒(méi)有用到的寄存器則不必執(zhí)行這些操作。在THUMB程序中,通常只能使用寄存器R4~R7來(lái)保存局部變量。寄存器R12用作子程序間暫存寄存器,記作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.2 數(shù)據(jù)棧的使用規(guī)則
棧指針通??梢灾赶虿煌奈恢?,當(dāng)棧指針指向棧頂元素(即最后一個(gè)入棧的數(shù)據(jù)元素)時(shí),稱(chēng)為Full棧。當(dāng)棧指針指向與棧頂元素相鄰的一個(gè)元素時(shí),稱(chēng)為Empty棧。數(shù)據(jù)棧的增長(zhǎng)方向也可以不同,當(dāng)數(shù)據(jù)棧向內(nèi)存減小的地址方向增長(zhǎng)時(shí),稱(chēng)為Descending棧。當(dāng)數(shù)據(jù)棧向著內(nèi)存地址增加的方向增長(zhǎng)時(shí),稱(chēng)為Ascending棧。綜合這兩種特點(diǎn)可以由以下4種數(shù)據(jù)棧:FD(FULL Descending):遞增滿(mǎn)棧 ED(Empty Descending):遞增空棧 FA(FULL Ascending):遞減滿(mǎn)棧 EA(Empty Ascending):遞減空棧
ATPCS規(guī)定數(shù)據(jù)棧為FD類(lèi)型,并對(duì)數(shù)據(jù)棧的操作是8字節(jié)對(duì)齊的,下面是一個(gè)數(shù)據(jù)棧的示例及相關(guān)的名詞:-
數(shù)據(jù)棧棧指針,stack pointer指向最后一個(gè)寫(xiě)入棧的數(shù)據(jù)的內(nèi)存地址。
-
數(shù)據(jù)棧的基地址,stack base是指數(shù)據(jù)棧的最高地址。由于ATPCS中的數(shù)據(jù)棧是FD類(lèi)型的,實(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ù)棧棧指針對(duì)應(yīng)的內(nèi)存單元。
-
數(shù)據(jù)棧中的數(shù)據(jù)幀(stack frames) 是指在數(shù)據(jù)棧中,為子程序分配的用來(lái)保存寄存器和局部變量的區(qū)域。
VAL(SP) <= stack base, VAL(SP) >= VAL(SL) >= stack limit + 256, VAL(LR) = return address
異常中斷的處理程序可以使用被中斷程序的數(shù)據(jù)棧,這時(shí)用戶(hù)要保證中斷的程序數(shù)據(jù)棧足夠大。使用ADS編譯器產(chǎn)生的目標(biāo)代碼中包含了DRFAT2格式的數(shù)據(jù)幀。在調(diào)試過(guò)程中,調(diào)試器可以使用這些數(shù)據(jù)幀來(lái)查看數(shù)據(jù)棧中的相關(guān)信息。而對(duì)于匯編語(yǔ)言來(lái)說(shuō),用戶(hù)必須使用FRAME偽操作來(lái)描述數(shù)據(jù)棧中的數(shù)據(jù)幀。ARM匯編器根據(jù)這些偽操作在目標(biāo)文件中產(chǎn)生相應(yīng)的DRFAT2格式的數(shù)據(jù)幀。在ARMv5TE中,批量傳送指令LDRD/STRD要求數(shù)據(jù)棧是8字節(jié)對(duì)齊的,以提高數(shù)據(jù)的傳送速度。用ADS編譯器產(chǎn)生的目標(biāo)文件中,外部接口的數(shù)據(jù)棧都是8字節(jié)對(duì)齊的,并且編譯器將告訴連接器:本目標(biāo)文件中的數(shù)據(jù)棧是8字節(jié)對(duì)齊的。而對(duì)于匯編程序來(lái)說(shuō),如果目標(biāo)文件中包含了外部調(diào)用,則必須滿(mǎn)足以下條件:外部接口的數(shù)據(jù)棧一定是8位對(duì)齊的,也就是要保證在進(jìn)入該匯編代碼后,直到該匯編程序調(diào)用外部代碼之間,數(shù)據(jù)棧的棧指針變化為偶數(shù)個(gè)字;在匯編程序中使用PRESERVE8偽操作告訴連接器,本匯編程序是8字節(jié)對(duì)齊的。2.3 參數(shù)的傳遞規(guī)則
根據(jù)參數(shù)個(gè)數(shù)是否固定,可以將子程序分為參數(shù)個(gè)數(shù)固定的子程序和參數(shù)個(gè)數(shù)可變的子程序。這兩種子程序的參數(shù)傳遞規(guī)則是不同的。參數(shù)個(gè)數(shù)可變的子程序參數(shù)傳遞規(guī)則,對(duì)于參數(shù)個(gè)數(shù)可變的子程序,當(dāng)參數(shù)不超過(guò)4個(gè)時(shí),可以使用寄存器R0~R3來(lái)進(jìn)行參數(shù)傳遞,當(dāng)參數(shù)超過(guò)4個(gè)時(shí),還可以使用數(shù)據(jù)棧來(lái)傳遞參數(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ù)可以通過(guò)寄存器傳遞,也可以通過(guò)數(shù)據(jù)棧傳遞,也可能一半通過(guò)寄存器傳遞,另一半通過(guò)數(shù)據(jù)棧傳遞。參數(shù)個(gè)數(shù)固定的子程序參數(shù)傳遞規(guī)則,對(duì)于參數(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寄存器;分配的方法是,滿(mǎn)足該浮點(diǎn)參數(shù)需要的且編號(hào)最小的一組連續(xù)的FP寄存器。第一個(gè)整數(shù)參數(shù)通過(guò)寄存器R0~R3來(lái)傳遞,其他參數(shù)通過(guò)數(shù)據(jù)棧傳遞。2.4 子程序結(jié)果返回規(guī)則
-
結(jié)果為一個(gè)32位的整數(shù)時(shí)或小于32位的整數(shù)值以保留符號(hào)和符號(hào)的方式擴(kuò)展為32位值的范圍,可以通過(guò)寄存器R0返回。
-
結(jié)果為一個(gè)64位整數(shù)時(shí),一個(gè)64位整數(shù)值被視為兩個(gè)32位整數(shù)值,可以通過(guò)R0和R1返回,依此類(lèi)推。
-
對(duì)于位數(shù)更多的結(jié)果,需要通過(guò)調(diào)用內(nèi)存來(lái)傳遞,任何其它類(lèi)型的值(例如結(jié)構(gòu)化值)將轉(zhuǎn)換為32位整數(shù)字序列,通過(guò)將其復(fù)制到連續(xù)的內(nèi)存字中。
?根據(jù)上面簡(jiǎn)單的測(cè)試可以看出:
MOVS r2,#0x03 MOVS r1,#0x02 MOVS r0,#0x01
通過(guò)寄存器R0~R3來(lái)傳遞參數(shù):ADDS r0,r3,r1 ADDS r0,r0,r2
通過(guò)寄存器R0返回。3. 特定的ATPCS
3.1 支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS
如果在程序設(shè)計(jì)期間能夠準(zhǔn)確地計(jì)算出程序所需的內(nèi)存總量,就不需要進(jìn)行數(shù)據(jù)棧的檢查,但是在通常情況下這是很難做到的,這時(shí)需要進(jìn)行數(shù)據(jù)棧的檢查。在進(jìn)行數(shù)據(jù)棧的檢查時(shí),使用寄存器R10作為數(shù)據(jù)棧限制指針,這時(shí)寄存器R10又記作SL。用戶(hù)在程序中不能控制該寄存器。具體來(lái)說(shuō),支持?jǐn)?shù)據(jù)棧限制的ATPCS要滿(mǎn)足下面的規(guī)則:在已經(jīng)占有的棧的最低地址和SL之間必須有256字節(jié)的空間,也就是說(shuō),SL所指的內(nèi)存地址必須比已經(jīng)占用的棧的最低地址低256個(gè)字節(jié)。當(dāng)中斷處理程序可以使用用戶(hù)的數(shù)據(jù)棧時(shí),在已經(jīng)占用的棧的最低地址和SL之間除了必須保留的256個(gè)字節(jié)的內(nèi)存單元外,還必須為中斷處理預(yù)留足夠的內(nèi)存空間;用戶(hù)在程序中不能修改SL的值;數(shù)據(jù)棧棧指針SP的值必須不小于SL的值。與支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS相關(guān)的編譯/匯編選項(xiàng)有下面幾種:選項(xiàng)./ swst (編譯過(guò)程中對(duì)輸入文件使用堆棧檢測(cè))指示編譯器生成的代碼遵守支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS,用戶(hù)在程序設(shè)計(jì)期間不能夠準(zhǔn)確計(jì)算程序所需的數(shù)據(jù)棧大小時(shí),需要指定該選項(xiàng);選項(xiàng)./ noswst (編譯過(guò)程中對(duì)輸入文件不使用堆棧檢測(cè),這是編譯器默認(rèn)選項(xiàng))指示編譯器生成的代碼不支持?jǐn)?shù)據(jù)棧限制檢查的功能,用戶(hù)在程序設(shè)計(jì)期間能夠準(zhǔn)確計(jì)算出程序所需的數(shù)據(jù)棧大小,可以指定該選項(xiàng);選項(xiàng)./ swst如果匯編程序?qū)τ谑欠襁M(jìn)行數(shù)據(jù)棧檢查無(wú)所謂,而與該匯編程序連接的其他程序指定了選項(xiàng)./ swst。對(duì)于256字節(jié)或更少的幀,可以按如下方式檢查:
CMP sp, sl BHS no_ovf BL |__16__rt_stkovf_split_small| no_ovf
對(duì)于大于 256 字節(jié)的幀,可以如下方式檢查:LDR wr, framesize ADD wr, sp CMP wr, sl BHS no_ovf BL |__16__rt_stkovf_split_big| no_ovf MOV sp,wr ; ... ALIGN Framesize DCD –Framesize
3.2 編寫(xiě)遵守支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS的匯編語(yǔ)言程序
對(duì)于C程序和C++程序來(lái)說(shuō),如果在編譯時(shí)指定了選項(xiàng)./swst,生成的目標(biāo)代碼將遵守支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS。對(duì)于匯編語(yǔ)言程序來(lái)說(shuō),如果要遵守支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS,用戶(hù)在編寫(xiě)程序時(shí)必須滿(mǎn)足支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS所要求的規(guī)則,然后指定選項(xiàng)./swst,下面介紹用戶(hù)編寫(xiě)匯編語(yǔ)言程序時(shí)的一些要求。3.3 葉子子程序是指不調(diào)用別的程序的子程序
數(shù)據(jù)棧小于256字節(jié)的葉子子程序不許要進(jìn)行數(shù)據(jù)棧檢查,如果幾個(gè)子程序組合起來(lái)構(gòu)成的葉子子程序數(shù)據(jù)棧也小于256字節(jié),這個(gè)規(guī)則同樣適用;數(shù)據(jù)棧小于256字節(jié)的非葉子子程序可以使用下面的代碼段來(lái)進(jìn)行數(shù)據(jù)棧檢查。ARM程序使用:SUB sp,sp,#size ; #size 為sp和sl之間必須保留的空間大小 CMP sp,sl; BLLO _ARM_stack_overflow
THUMB程序使用:ADD sp,#-size ; #size為sp和sl之間必須保留的空間大小 CMP sp,sl; BLLO _THUMB_stack_overflow
數(shù)據(jù)棧大于256字節(jié)的子程序,為了保證SP的值不小于數(shù)據(jù)??捎玫膬?nèi)存單元最小的地址值,需要引入相應(yīng)的寄存器。在使用超過(guò) 256 字節(jié)堆??臻g的例程中檢查溢出更為復(fù)雜,不能簡(jiǎn)單地從SP減去幀大小。在這種情況下,必須使用如下序列向限制檢查代碼建議SP的新值:ARM程序使用下列代碼:SUB ip,sp,#size; CMP ip,sl; BLLO _ARM_stack_overflow
THUMB程序使用下列代碼:LDR wr,#-size; ADD wr,sp; CMP wr,sl; BLLO _THUMB_stack_overflow
在編譯或匯編時(shí),/interwork (指定輸入文件符合ARM/Thumb交互標(biāo)準(zhǔn))告訴編譯器或匯編器生成的目標(biāo)代碼遵守支持ARM-THUMB的ATPCS,它用在以下場(chǎng)合:-
程序中存在ARM程序調(diào)用THUMB程序的情況
-
程序中存在THUMB程序調(diào)用ARM程序的情況
-
需要連接器來(lái)進(jìn)行ARM狀態(tài)和THUMB狀態(tài)切換的情況
審核編輯 :李倩
-
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7614瀏覽量
137541 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4345瀏覽量
62911 -
系統(tǒng)控制
+關(guān)注
關(guān)注
0文章
33瀏覽量
16255
原文標(biāo)題:技術(shù)分享 | Cortex-M0中斷控制和系統(tǒng)控制(七)
文章出處:【微信號(hào):Ithingedu,微信公眾號(hào):安芯教育科技】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論