[心得] ARM Procedure Call GCC/G++ 4.1.1
※ [本文轉錄自 gen2linux 信箱]
作者: gen2linux (晚宴行動如期舉行) 看板: LinuxDev
標題: [心得] ARM Procedure Call GCC/G++ 4.1.1
時間: Mon Nov 20 23:40:05 2006
ARM Procedure Call with g++(gcc) 4.1.1
這是一個一般情況下有關 g++(gcc)如何在 ARM平台上實作 procedure call的心得memo
,用的機會雖少,但應該還是可以參考,可運用的場合有二:
1. invoke a C/C++ function in assembly
2. ARM Exploit development
參考文件
Procedure Call Standard for the ARM Architecture
http://www.arm.com/miscPDFs/8031.pdf
Tool:
gcc/g++ 4.1.1,
gdb
ARM926EJ-S
Procedure call規則:
1. R0,R1,R2,R3為傳遞參數的暫存器
2. 若參數超過四個,則再利用stack來傳遞參數
a. Compiler在compile time就決定是否要用stack來傳遞參數
b. 若是,則會將其加入決定caller stack空間的考量(也就是決定caller 之
SP暫存器的位置之時)
3. R11用來作為存取區域變數、函式參數的基準(類似x86的EBP)
4. 32bit和64bit參數(如long long、double)傳遞方式原理相同,只差在一個64bit
參數需要用兩個register或兩個DWord的memory來傳遞,以下是規則
–SP mod 4 = 0(from APCS, Arm Procedure Call Stardard)
–32bit參數位址 mod 4 = 0
–64bit參數位址 mod 8 = 0
5. 底下的討論都是在沒有加上最佳化(-O)的情況下, 討論參數為 32bit或 64bit時
的情況
=== 參數全為 32bit ===
int object::func(char c, int i, float f){…}
--= Caller方 =--
Caller呼叫某物件的funciton時
1.取得該function位址並存於Rn
a、將物件的指標存在R0
b、由指標取得該物件之vtable指標(offset為 0)
c、跟據vtable和該函式之索引以取得該函式位址,將該位址存放在空閒的Rn暫存器
2.設定參數,R1~R3為前三個參數
3.把第四個參數設定在[SP], 第五個設在[SP+4], 第六個設在[SP+8]…
4.將PC搬給LR
5.BX Rn,呼叫該函式
6.返回值位於R0
--= Callee方 =--
-Prolog段-
1. 將R11、IP、LR、PC暫存器壓入堆疊,形成所謂的Activation Record。
2. 將有用到的通用暫存器壓入堆疊(optional)
3. 設定R11為SP-4,R11在此函式其間不會再改變
4. 移動SP以空出區域變數、函式參數的空間
5. 將處在R0~R3的函式參數搬移至stack中,以空出R0~R3來利用。往後要存取函式參
數亦如同在存取區域變數,需以R11來參考。
-Code段-
1. 如要存取參數時,亦同存取區域變數的方式,例如第一個參數位於 [r11, #-n]
(n由compiler視當時callee區域變數大小決定),則第二個參數位於[r11, #-n-4],
第三個參數位於[r11, #-n-8],第四個參數位於[r11, #-n-16]。
2. 第五個參數以後位在Caller的stack中,故第五個參數則位於[r11, #n+4],
第六個參數位於[r11, #n+8]…
-Epilog段-
1. 將結果搬至 R0
2. 移動SP,以縮減掉區域變數/函式參數區,使得SP指向Activation Record。
3. 將Activation Record中的值覆蓋回暫存器,包括R11、SP、LR(無PC)。
4. BX LR,返回原來的的函式
=== 參數全為 64bit ===
int object::func(long long l, double d){…}
-- Caller方 --
1. 流程不變,R0依然指向該物件
2. R1空出,挪為它用 <<< 注意!!
3. R2與R3共同裝填第一個參數,第二個參數填至 [SP]與[SP+4],第三個填至[SP+8]與
[SP+12]…
-- Callee 規則不變,只差在每一個函式參數為兩個DWord。
=== 參數為 32bit與64bit混合 ===
int object::func(long long l, int i, double d){…}
-- Caller方 --
需注意要符合規則:64bit參數位址 mod 8 = 0,意即所有64bit參數位址需對齊8,
因為64bit參數和32bit參數一同排列在記憶體中時,很有可能出現64bit參數之位址
不對齊 8,如下圖,0x104 mod 8 != 0,
0x0100 0x104 0x112
[ 1st arg:32bit ][ 2nd argu: 64bit ]
故需增加一無意義的DWord來使得64bit參數與8對齊
0x0100 0x104 x108 0x116
[ 1st arg:32bit ][ dummy:32bit ][ 2nd argu: 64bit ]
-- Callee方 --
存取參數時的規則亦同上面caller方
--
Red Shirt located. Do you have in sight?
Red Shirt confirmed.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.96.111.56
※ 編輯: gen2linux 來自: 140.96.111.56 (11/21 19:29)
LinuxDev 近期熱門文章
PTT數位生活區 即時熱門文章