1. 程式人生 > >ARM函式呼叫過程分析

ARM函式呼叫過程分析

1.  ARM的棧幀     先來看看ARM的棧幀佈局圖:          上圖描述的是ARM的棧幀佈局方式,main stack frame為呼叫函式的棧幀,func1 stack frame為當前函式(被呼叫者)的棧幀,棧底在高地址,棧向下增長。圖中FP就是棧基址,它指向函式的棧幀起始地址;SP則是函式的棧指標,它指向棧頂的位置。ARM壓棧的順序很是規矩,依次為當前函式指標PC、返回指標LR、棧指標SP、棧基址FP、傳入引數個數及指標、本地變數和臨時變數。如果函式準備呼叫另一個函式,跳轉之前臨時變數區先要儲存另一個函式的引數。     ARM也可以用棧基址和棧指標明確標示棧幀的位置,棧指標SP一直移動,相比於x86,ARM更為鮮明的特點是,兩個棧空間內的地址(SP+FP)前面,必然有兩個程式碼地址(PC+LR)明確標示著呼叫函式位置內的某個地址。

2.  ARM的彙編指令和棧操作     ARM微處理器共有37個暫存器,其中31個為通用暫存器,6個為狀態暫存器。但是這些暫存器不能被同時訪問,具體哪些暫存器是可程式設計訪問的,取決於微處理器的工作狀態及具體的執行模式。但在任何時候,通用暫存器R0~R15、一個或兩個狀態暫存器都是可訪問的。有三個特殊的通用暫存器:   暫存器R13:在ARM指令中常用作堆疊指標SP   暫存器R14:也稱作子程式連線暫存器(Subroutine Link Register)即連線暫存器LR   暫存器R15:也稱作程式計數器PC     ARM進行函式內壓棧和出棧往往使用如下的語句:   stmfd sp!, {r0-r9, lr}    ; 滿遞減入棧,給暫存器r0-r9,lr壓棧,sp不斷減4   ldmfd sp!, {r0-r9, pc}    ; 滿遞減出棧,給暫存器r0-r9出棧,並使程式跳轉回函式的呼叫點,sp不斷增4     常用的函式內外跳轉指令有mov和BL,ARM有兩種跳轉方式:   (1)mov pc, <跳轉地址〉     這種向程式計數器PC直接寫跳轉地址,能在4GB連續空間內任意跳轉。   (2)通過 B BL BLX BX 可以完成在當前指令向前或者向後32MB的地址空間的跳轉(為什麼是32MB呢?暫存器是32位的,此時的值是24位有符號數,所以32MB?後面再查檢視)。B是最簡單的跳轉指令。要注意的是,跳轉指令的實際值不是絕對地址,而是相對地址——是相對當前PC值的一個偏移量,它的值由彙編器計算得出。BL很常用,它在跳轉之前會在暫存器LR(R14)中儲存PC的當前內容。BL的經典用法如下:     bl NEXT       ; 跳轉到NEXT      ……      NEXT      ……      mov pc, lr    ; 從子程式返回。

 看程式碼:

int func(int a, int b, int c, int d)
{
	
	return 1;
}


int main()
{
	int i = 1, j = 2;
	func(i, j, 3, 4);
	return 0;
}

使用arm-linux-gcc編譯後,使用ida開啟:

.text:000083D0                 EXPORT main
.text:000083D0 main                                    ; DATA XREF: .text:000082C4o
.text:000083D0                                         ; .text:off_82DCo
.text:000083D0
.text:000083D0 b               = -0x14
.text:000083D0 a               = -0x10
.text:000083D0
.text:000083D0 IP = R12
.text:000083D0 FP = R11
.text:000083D0                 MOV     IP, SP
.text:000083D4                 STMFD   SP!, {FP,IP,LR,PC}
.text:000083D8                 SUB     FP, IP, #4
.text:000083DC                 SUB     SP, SP, #8
.text:000083E0                 MOV     R3, #1
.text:000083E4                 STR     R3, [FP,#a]
.text:000083E8                 MOV     R3, #2
.text:000083EC                 STR     R3, [FP,#b]
.text:000083F0                 LDR     R0, [FP,#a]
.text:000083F4                 LDR     R1, [FP,#b]
.text:000083F8                 MOV     R2, #3
.text:000083FC                 MOV     R3, #4
.text:00008400                 BL      func
.text:00008404                 MOV     R3, #0
.text:00008408                 MOV     R0, R3
.text:0000840C                 SUB     SP, FP, #0xC
.text:00008410                 LDMFD   SP, {FP,SP,PC}
.text:00008410 ; End of function main

可以發現,在main函式中,使用IP(R12)暫時儲存棧指標sp,然後使用堆疊操作指令stmfd將棧幀(FP)、IP、程式返回地址(LR)、程式計數器(PC)壓棧,以保護現場,然後使用sub fp,ip,#4使fp指向當前函式棧幀的棧底,sub sp,sp,#8,為當前函式區域性變數分配看空間。接下來通過暫存器傳遞引數r1,r2,r3,r4。使用BL指令呼叫函式,BL指令同時也會將當前指令的下一條指令地址賦給LR,以跳轉回來。最後使用ldmfd恢復現場。

.text:000083A0 ; =============== S U B R O U T I N E =======================================
.text:000083A0
.text:000083A0 ; Attributes: bp-based frame
.text:000083A0
.text:000083A0                 EXPORT func
.text:000083A0 func                                    ; CODE XREF: main+30p
.text:000083A0
.text:000083A0 var_1C          = -0x1C
.text:000083A0 var_18          = -0x18
.text:000083A0 var_14          = -0x14
.text:000083A0 var_10          = -0x10
.text:000083A0
.text:000083A0                 MOV     R12, SP
.text:000083A4                 STMFD   SP!, {R11,R12,LR,PC}
.text:000083A8                 SUB     R11, R12, #4
.text:000083AC                 SUB     SP, SP, #0x10
.text:000083B0                 STR     R0, [R11,#var_10]
.text:000083B4                 STR     R1, [R11,#var_14]
.text:000083B8                 STR     R2, [R11,#var_18]
.text:000083BC                 STR     R3, [R11,#var_1C]
.text:000083C0                 MOV     R3, #1
.text:000083C4                 MOV     R0, R3
.text:000083C8                 SUB     SP, R11, #0xC
.text:000083CC                 LDMFD   SP, {R11,SP,PC}
.text:000083CC ; End of function func
.text:000083CC
.text:000083D0
.text:000083D0 ; =============== S U B R O U T I N E =======================================

參考:
http://blog.chinaunix.net/uid-16459552-id-3364761.html
http://m.blog.csdn.net/blog/u011405813/41899197