作者gen2linux (晚宴行动如期举行)
标题[心得] ARM Procedure Call GCC/G++ 4.1.1
时间Tue Nov 21 19:26:29 2006
※ [本文转录自 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)