呼叫c ARM匯程式設計序呼叫 C 程式

2021-10-25 12:34:28 字數 4627 閱讀 5324

在arm 匯程式設計序和c 程式之間相互呼叫時必須遵守 atpcs 規則,atpcs 規定了一些函式間呼叫的基本規則。

一、atpcs 規則

atpcs 即 arm-thumb procedure call standard(arm-thumb過程呼叫標準)的簡稱,是基於arm指令集和thumb指令集過程呼叫的規範,規定了呼叫函式如何傳遞引數,被呼叫函式如何獲取引數,以何種方式傳遞函式返回值。基本的atpcs規則包括暫存器使用規則、資料棧使用規則、引數傳遞規則。

1. 暫存器使用規則

atpcs中arm暫存器的使用規則及其名稱:

暫存器別名

使用規則

r15pc

程式計數器

r14lr

鏈結暫存器

r13sp

資料棧暫存器

r12ip

子程式內部呼叫的scratch暫存器

r11v8、fp

arm狀態區域性變數暫存器8、幀指標

r10v7、sl

arm狀態區域性變數暫存器7、棧限制

r9v6

arm狀態區域性變數暫存器6

r8v5

arm狀態區域性變數暫存器5

r7v4

arm狀態區域性變數暫存器4

r6v3

arm狀態區域性變數暫存器3

r5v2

arm狀態區域性變數暫存器2

r4v1

arm狀態區域性變數暫存器1

r3a4

引數/結果/scratch暫存器4

r2a3

引數/結果/scratch暫存器3

r1a2

引數/結果/scratch暫存器2

r0a1

引數/結果/scratch暫存器1

暫存器 r0~r15 在 atpcs 規則中的使用總結如下:

2. 資料棧使用規則

所謂資料棧的增長就是移動棧指標。當棧指標指向棧頂元素(最後乙個入棧的資料)時,稱為full棧;當棧指標指向棧頂元素(最後乙個入棧的資料)相鄰的乙個空的資料單元時,稱為empty棧。

綜合以上這兩個特點,資料棧可以分為以下4種:

縮寫名稱

指令含義

fd滿遞減

stmfd/ldmfd

堆疊通過減小儲存器的位址向下增長,堆疊指標指向內含有效資料項的最低位址

ed空遞減

stmed/ldmed

堆疊通過減小儲存器的位址向下增長,堆疊指標指向堆疊下的第乙個空位置

fa滿遞增

stmfa/ldmfa

堆疊通過增大儲存器的位址向上增長,堆疊指標指向內含有效資料項的最高位址

ea空遞增

stmea/ldmea

堆疊通過增大村吃器的位址向上增長,堆疊指標指向堆疊上的第乙個空位置

atpcs規定資料棧為fd型別,並且對資料棧的操作是8位元組對齊的。使用s***b/ldmia批量記憶體訪問指令來操作fd資料棧。

使用s***b命令往資料棧中儲存內容時,"先遞減sp指標,再儲存資料";

使用ldmia命令從資料棧中恢復資料時,"先獲得資料,再遞增sp指標";

sp指標總是指向棧頂元素,這剛好是fd棧的定義。

3. 引數傳遞規則

一般來說,當引數個數不超過4個時,使用r0~r3這4個暫存器來傳遞引數;如果引數個數超過4個,剩餘的引數通過資料棧來傳遞。

二、匯程式設計序如何向 c 程式的函式傳遞引數

三、c 程式如何返回結果給匯程式設計序

四、c 函式為何要用棧

總的來說,棧的作用就是: 儲存現場/上下文,傳遞引數。

1. 儲存現場/上下文

儲存現場,也叫儲存上下文。

現場,相當於案發現場,總有一些現場的情況,要記錄下來的,否則被別人破壞掉之後,你就無法恢復現場了。而此處說的現場,就是指 cpu 執行的時候,用到了一些暫存器,比如 r0~r3,lr 等等,對於這些暫存器的值,如果你不儲存而直接跳轉到函式中去執行,那麼很可能會被破壞了,因為函式執行需要用到這些暫存器。

因此在函式呼叫之前,應該將這些暫存器等現場,暫時儲存起來,等呼叫函式執行完畢返回後,再恢復現場,這樣 cpu 就可以正確的繼續執行了。

儲存暫存器的值,一般用的是 push 指令,將對應的某些暫存器的值,乙個個放到棧中,即所謂的入棧。

然後待被呼叫的子函式執行完畢的時候,再呼叫 pop,把棧中的乙個個的值,賦值給對應的入棧的暫存器,即所謂的出棧。

2. 傳遞引數

當函式被呼叫並且引數大於 4 個時,(不包括第 4 個引數)第 4 個引數後面的引數就儲存在棧中。

五、分析乙個例項

匯程式設計序:

.text.global _start_start:        ldr sp, =4096        /* 呼叫main */        bl mainhalt:        b halt
c程式:

int main()
將上面程式進行反彙編:

disassembly of section .text:00000000 <_start>:   0:  e3a0da01   mov  sp, #4096  ; 0x1000   4:  eb000000   bl  c 00000008 :   8:  eafffffe   b  8 0000000c :   c:  e1a0c00d   mov  ip, sp  10:  e92dd800   s***b  sp!,   14:  e24cb004   sub  fp, ip, #4  ; 0x4  18:  e24dd008   sub  sp, sp, #8  ; 0x8  1c:  e3a03456   mov  r3, #1442840576  ; 0x56000000  20:  e2833050   add  r3, r3, #80  ; 0x50  24:  e50b3010   str  r3, [fp, #-16]  28:  e3a03456   mov  r3, #1442840576  ; 0x56000000  2c:  e2833054   add  r3, r3, #84  ; 0x54  30:  e50b3014   str  r3, [fp, #-20]  34:  e51b2010   ldr  r2, [fp, #-16]  38:  e3a03c01   mov  r3, #256  ; 0x100  3c:  e5823000   str  r3, [r2]  40:  e51b2014   ldr  r2, [fp, #-20]  44:  e3a03000   mov  r3, #0  ; 0x0  48:  e5823000   str  r3, [r2]  4c:  e3a03000   mov  r3, #0  ; 0x0  50:  e1a00003   mov  r0, r3  54:  e24bd00c   sub  sp, fp, #12  ; 0xc  58:  e89da800   ldmia  sp, 
簡單分析下上面的反彙編:

mov  sp, #4096:設定棧位址在4k ram的最高處,sp=4096;bl    c :調到c位址處的main函式,並儲存下一行**位址到lr,即lr=8;mov  ip, sp:給ip賦值sp的值,ip=sp=4096s***b  sp!, :按高編號暫存器存在高位址,依次將pc、lr、ip、fp存入sp-4中;sub  fp, ip, #4:fp的值為ip-4=4096-4=4092;sub  sp, sp, #8:sp的值為sp-8=(4096-4x4)-8=4072;mov  r3, #1442840576:r3賦值0x5600 0000; add  r3, r3, #80:r3的值加0x50,即r3=0x5600 0050;str  r3, [fp, #-16]:r3存入[fp-16]所在的位址,即位址4076處存放0x5600 0050;mov  r3, #1442840576:r3賦值0x5600 0000; add  r3, r3, #84:r3的值加0x54,即r3=0x5600 0054;str  r3, [fp, #-20]:r3存入[fp-20]所在的位址,即位址4072處存放0x5600 0054;ldr  r2, [fp, #-16]:r2取[fp-16]位址處的值,即[4076]位址的值,r2=0x5600 0050;mov  r3, #256:r3賦值為0x100;str  r3, [r2]:將r3寫到r2內容所對應的位址,即0x5600 0050位址處的值為0x100;;對應c語言*pgpfcon = 0x100;;ldr  r2, [fp, #-20]:r2取[fp-20]位址處的值,即[4072]位址的值,r2=0x5600 0054;mov  r3, #0:r3賦值為0x00;str  r3, [r2]:將r3寫到r2內容所對應的位址,即0x5600 0054位址處的值為0x00;對應c語言*pgpfdat = 0;mov  r3, #0:r3賦值為0x00;mov  r0, r3:r0=r3=0x00;sub  sp, fp, #12:sp=fp-12=4092-12=4080;ldmia  sp, :從棧中恢復暫存器,fp=4080位址處的值=原來的fp,sp=4084位址處的值=4096,pc=4088位址處的值=8,隨後調到0x08位址處繼續執行。
記憶體資料情況:

匯程式設計序呼叫c程式

首先是匯程式設計序,還是前面的例子,只是加了2行程式 extern main 說明這個函式從外面程式獲得 section data charact db a section text global start start mov ecx,charact push ecx call usestack ...

匯程式設計序 呼叫C庫函式

當我們在vs環境下學習組合語言的時候,呼叫win32的api函式進行控制台的輸入和輸出是非常麻煩的。但是c的庫函式怎麼呼叫又好像不清楚,以下是在vs2017環境下呼叫c庫函式printf和scanf函式實現控制台輸入輸出.includelib kernel32.lib 這個庫用於呼叫win32的ex...

ARM彙編程式設計之C程式呼叫匯程式設計序

編寫乙個彙編子程式,實現兩個字資料的加法運算,編寫乙個c程式來呼叫該彙編子程式,並將運算結果使用printf 函式顯示出來。示例如下 為解決這個問題,分別編寫滿足需求的c程式和匯程式設計序。c程式源 define uint32 unsigned int extern uint32 add uint3...