為了使單獨編譯的C語言程序和匯編程序之間能夠相互調用,必須為子程序之間的調用規定一定的規則,ATPCS就是ARM程序和THUMB程序中子程序調用的基本規則。
1. ATPCS
ATPCS即ARM Thumb Procedure Call Standard(ARM-Thumb過程調用標準)的簡稱,ATPCS規定了一些調用和被調用程序之間調用的基本規則,這些基本規則包括子程序調用過程中寄存器的使用規則、數據棧的使用規則、參數的傳遞規則。為適應一些特定的需要,對這些基本的調用規則進行一些修改得到幾種不同的子程序調用規則,這些特定的調用規則包括:
-
支持數據棧限制檢查的ATPCS
-
支持只讀段位置無關的ATPCS
-
支持可讀寫段位置無關的ATPCS
-
支持ARM程序和THUMB程序混合使用的ATPCS
有調用關系的所有子程序必須遵守同一種ATPCS,編譯器或者匯編器在ELF格式的目標文件中設置相應的屬性,標識用戶選定的ATPCS類型。對應不同類型的ATPCS規則,有相應的C語言庫,連接器根據用戶指定的ATPCS類型連接相應的C語言庫。使用ADS的C語言編譯器編譯的C語言子程序滿足用戶指定的ATPCS類型。而對于匯編語言程序來說,完全要依賴用戶來保證各子程序滿足選定的ATPCS類型。具體來說,匯編語言子程序必須滿足下面三個條件:在子程序編寫時必須遵守相應的ATPCS規則;數據棧的使用要遵守ATPCS規則;在匯編編譯器中使用“--apcs”選項,使用“--apcs”選項并不影響代碼的產生,編譯器只是在各段中放置相應的屬性,標識用戶選定的屬性。
2. ATPCS基本規則
基本ATPCS規定了在子程序調用時的一些基本規則,包括以下四個方面的內容:
-
各寄存器的使用規則及其相應的名字
-
數據棧的使用規則
-
參數傳遞的規則
-
函數結果返回的規則
相對于其他類型的TPCS,滿足基本ATPCS的程序的執行速度更快,所占用的內存更少。但是它不能提供以下的支持:ARM程序和THUMB程序相互調用;數據以及代碼的位置無關的支持;子程序的可重入性;數據棧檢查的支持。而派生的其他幾種特定的ATPCS就是在基本ATPCS的基礎上再添加其他的規則而形成的 ,其目的就是提供上述的功能。
2.1 寄存器的使用規則
?前四個寄存器R0~R3用于將參數值傳遞到例程中并將結果值傳遞出例程,并在例程中保存中間值(但通常僅在子例程調用之間),子程序通過寄存器R0~R3來傳遞參數,這時寄存器可以記作:A1~A4,被調用的子程序在返回前無需恢復寄存器R0~R3的內容。在子程序中,使用R4~R11來保存局部變量,這時寄存器R4~R11可以記作:V1~V8 。如果在子程序中使用到V1~V8的某些寄存器,子程序進入時必須保存這些寄存器的值,在返回前必須恢復這些寄存器的值,對于子程序中沒有用到的寄存器則不必執行這些操作。在THUMB程序中,通常只能使用寄存器R4~R7來保存局部變量。寄存器R12用作子程序間暫存寄存器,記作IP;在子程序的連接代碼段中經常會有這種使用規則。寄存器R13用作數據棧指針,記做SP,在子程序中寄存器R13不能用做其他用途。寄存器SP在進入子程序時的值和退出子程序時的值必須相等。寄存器R14用作連接寄存器,記作LR;它用于保存子程序的返回地址,如果在子程序中保存了返回地址,則R14可用作其它的用途。寄存器R15是程序計數器,記作PC;它不能用作其它用途。ATPCS中的各寄存器在ARM編譯器和匯編器中都是預定義的。2.2 數據棧的使用規則
棧指針通常可以指向不同的位置,當棧指針指向棧頂元素(即最后一個入棧的數據元素)時,稱為Full棧。當棧指針指向與棧頂元素相鄰的一個元素時,稱為Empty棧。數據棧的增長方向也可以不同,當數據棧向內存減小的地址方向增長時,稱為Descending棧。當數據棧向著內存地址增加的方向增長時,稱為Ascending棧。綜合這兩種特點可以由以下4種數據棧:FD(FULL Descending):遞增滿棧 ED(Empty Descending):遞增空棧 FA(FULL Ascending):遞減滿棧 EA(Empty Ascending):遞減空棧 ATPCS規定數據棧為FD類型,并對數據棧的操作是8字節對齊的,下面是一個數據棧的示例及相關的名詞:-
數據棧棧指針,stack pointer指向最后一個寫入棧的數據的內存地址。
-
數據棧的基地址,stack base是指數據棧的最高地址。由于ATPCS中的數據棧是FD類型的,實際上數據棧中最早入棧數據占據的內存單元是基地址的下一個內存單元。
-
數據棧界限,stack limit是指數據棧中可以使用的最低的內存單元地址。
-
已占用的數據棧,used stack是指數據棧的基地址和數據棧棧指針之間的區域,其中包括數據棧棧指針對應的內存單元。
-
數據棧中的數據幀(stack frames) 是指在數據棧中,為子程序分配的用來保存寄存器和局部變量的區域。
VAL(SP) <= stack base, VAL(SP) >= VAL(SL) >= stack limit + 256, VAL(LR) = return address
異常中斷的處理程序可以使用被中斷程序的數據棧,這時用戶要保證中斷的程序數據棧足夠大。使用ADS編譯器產生的目標代碼中包含了DRFAT2格式的數據幀。在調試過程中,調試器可以使用這些數據幀來查看數據棧中的相關信息。而對于匯編語言來說,用戶必須使用FRAME偽操作來描述數據棧中的數據幀。ARM匯編器根據這些偽操作在目標文件中產生相應的DRFAT2格式的數據幀。在ARMv5TE中,批量傳送指令LDRD/STRD要求數據棧是8字節對齊的,以提高數據的傳送速度。用ADS編譯器產生的目標文件中,外部接口的數據棧都是8字節對齊的,并且編譯器將告訴連接器:本目標文件中的數據棧是8字節對齊的。而對于匯編程序來說,如果目標文件中包含了外部調用,則必須滿足以下條件:外部接口的數據棧一定是8位對齊的,也就是要保證在進入該匯編代碼后,直到該匯編程序調用外部代碼之間,數據棧的棧指針變化為偶數個字;在匯編程序中使用PRESERVE8偽操作告訴連接器,本匯編程序是8字節對齊的。
2.3 參數的傳遞規則
根據參數個數是否固定,可以將子程序分為參數個數固定的子程序和參數個數可變的子程序。這兩種子程序的參數傳遞規則是不同的。參數個數可變的子程序參數傳遞規則,對于參數個數可變的子程序,當參數不超過4個時,可以使用寄存器R0~R3來進行參數傳遞,當參數超過4個時,還可以使用數據棧來傳遞參數。在參數傳遞時,將所有參數看做是存放在連續的內存單元中的字數據。然后,依次將各名字數據傳送到寄存器R0,R1,R2,R3;如果參數多于4個,將剩余的字數據傳送到數據棧中,入棧的順序與參數順序相反,即最后一個字數據先入棧。按照上面的規則,一個浮點數參數可以通過寄存器傳遞,也可以通過數據棧傳遞,也可能一半通過寄存器傳遞,另一半通過數據棧傳遞。參數個數固定的子程序參數傳遞規則,對于參數個數固定的子程序,參數傳遞與參數個數可變的子程序參數傳遞規則不同,如果系統包含浮點運算的硬件部件,浮點參數將按照下面的規則傳遞:各個浮點參數按順序處理;為每個浮點參數分配FP寄存器;分配的方法是,滿足該浮點參數需要的且編號最小的一組連續的FP寄存器。第一個整數參數通過寄存器R0~R3來傳遞,其他參數通過數據棧傳遞。2.4 子程序結果返回規則
-
結果為一個32位的整數時或小于32位的整數值以保留符號和符號的方式擴展為32位值的范圍,可以通過寄存器R0返回。
-
結果為一個64位整數時,一個64位整數值被視為兩個32位整數值,可以通過R0和R1返回,依此類推。
-
對于位數更多的結果,需要通過調用內存來傳遞,任何其它類型的值(例如結構化值)將轉換為32位整數字序列,通過將其復制到連續的內存字中。
?根據上面簡單的測試可以看出:MOVS r2,#0x03 MOVS r1,#0x02 MOVS r0,#0x01 通過寄存器R0~R3來傳遞參數:ADDS r0,r3,r1 ADDS r0,r0,r2 通過寄存器R0返回。3. 特定的ATPCS
3.1 支持數據棧限制檢查的ATPCS
如果在程序設計期間能夠準確地計算出程序所需的內存總量,就不需要進行數據棧的檢查,但是在通常情況下這是很難做到的,這時需要進行數據棧的檢查。在進行數據棧的檢查時,使用寄存器R10作為數據棧限制指針,這時寄存器R10又記作SL。用戶在程序中不能控制該寄存器。具體來說,支持數據棧限制的ATPCS要滿足下面的規則:在已經占有的棧的最低地址和SL之間必須有256字節的空間,也就是說,SL所指的內存地址必須比已經占用的棧的最低地址低256個字節。當中斷處理程序可以使用用戶的數據棧時,在已經占用的棧的最低地址和SL之間除了必須保留的256個字節的內存單元外,還必須為中斷處理預留足夠的內存空間;用戶在程序中不能修改SL的值;數據棧棧指針SP的值必須不小于SL的值。與支持數據棧限制檢查的ATPCS相關的編譯/匯編選項有下面幾種:選項./ swst (編譯過程中對輸入文件使用堆棧檢測)指示編譯器生成的代碼遵守支持數據棧限制檢查的ATPCS,用戶在程序設計期間不能夠準確計算程序所需的數據棧大小時,需要指定該選項;選項./ noswst (編譯過程中對輸入文件不使用堆棧檢測,這是編譯器默認選項)指示編譯器生成的代碼不支持數據棧限制檢查的功能,用戶在程序設計期間能夠準確計算出程序所需的數據棧大小,可以指定該選項;選項./ swst如果匯編程序對于是否進行數據棧檢查無所謂,而與該匯編程序連接的其他程序指定了選項./ swst。對于256字節或更少的幀,可以按如下方式檢查:
CMP sp, sl BHS no_ovf BL |__16__rt_stkovf_split_small| no_ovf 對于大于 256 字節的幀,可以如下方式檢查: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 編寫遵守支持數據棧限制檢查的ATPCS的匯編語言程序
對于C程序和C++程序來說,如果在編譯時指定了選項./swst,生成的目標代碼將遵守支持數據棧限制檢查的ATPCS。對于匯編語言程序來說,如果要遵守支持數據棧限制檢查的ATPCS,用戶在編寫程序時必須滿足支持數據棧限制檢查的ATPCS所要求的規則,然后指定選項./swst,下面介紹用戶編寫匯編語言程序時的一些要求。
3.3 葉子子程序是指不調用別的程序的子程序
數據棧小于256字節的葉子子程序不許要進行數據棧檢查,如果幾個子程序組合起來構成的葉子子程序數據棧也小于256字節,這個規則同樣適用;數據棧小于256字節的非葉子子程序可以使用下面的代碼段來進行數據棧檢查。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 數據棧大于256字節的子程序,為了保證SP的值不小于數據棧可用的內存單元最小的地址值,需要引入相應的寄存器。在使用超過 256 字節堆棧空間的例程中檢查溢出更為復雜,不能簡單地從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 在編譯或匯編時,/interwork (指定輸入文件符合ARM/Thumb交互標準)告訴編譯器或匯編器生成的目標代碼遵守支持ARM-THUMB的ATPCS,它用在以下場合:-
程序中存在ARM程序調用THUMB程序的情況
-
程序中存在THUMB程序調用ARM程序的情況
-
需要連接器來進行ARM狀態和THUMB狀態切換的情況
?\_\_asm 關鍵字用于調用內聯匯編程序,可以用在C或C++源碼中內嵌匯編語言,如下所示:
?ATPCS規則就是定義了函數傳參以及返回數據的標準,定義了寄存器在函數調用時的作用。審核編輯 :李倩
-
C語言
+關注
關注
183文章
7644瀏覽量
145588 -
函數
+關注
關注
3文章
4417瀏覽量
67504 -
系統控制
+關注
關注
0文章
34瀏覽量
16536
原文標題:技術分享 | Cortex-M0中斷控制和系統控制(七)
文章出處:【微信號:Ithingedu,微信公眾號:安芯教育科技】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
Jtti防火墻規則配置指南:從入門到精通的全面解析
貞光科技代理品牌 | 三星電容物料編碼規則
厚聲電阻標簽的命名規則
KiCad 中的自定義規則(KiCon 演講)
時源芯微 PCB 布線規則詳解
旺詮合金電阻的命名規則
MISRA C:2025新標準解析:新增規則、優化點與靜態代碼分析工具支持(Perforce QAC、Klocwork)
Altium Designer中PCB設計規則設置
2025年村田電感型號命名規則深度解析
如何在特定區域設置線寬、線距規則
ATPCS基本規則
評論