R0-R9:一般用于存储数据。R0-R3用于存储函数参数。
R10(sl):堆栈限制寄存器。
R11(fp):帧指针,指向栈顶。
R12(ip):内部过程调用寄存器。在函数分析和调用时暂时存储数据。
R13(sp):栈指针,指向栈底。
R14(lr):链接寄存器,保存函数返回地址。
R15(pc):程序计数器。
使用下面的测试程序来分析一下函数调用过程中的栈帧变化。
#include
int test(int p){
int a = p;
return a;
}
int main(void){
int a=1;
test(a);
return 0;
}
经过反汇编后得到下面这一段汇编代码。直接从汇编代码中来分析函数栈帧的变化过程。
00008460 :
8460: e1a0c00d mov ip, sp ;sp地址保存至ip
8464: e92dd800 stmdb sp!, {fp, ip, lr, pc} ;将 pc lr ip fp 依次入栈
8468: e24cb004 sub fp, ip, #4 ; 0x4
846c: e24dd008 sub sp, sp, #8 ; 分配栈空间
8470: e50b0010 str r0, [fp, #-16] ; 函数参数p R0入栈
8474: e51b3010 ldr r3, [fp, #-16]
8478: e50b3014 str r3, [fp, #-20] ; 变量a 入栈
847c: e51b3014 ldr r3, [fp, #-20] ; 变量a 出栈
8480: e1a00003 mov r0, r3 ; 变量a作为返回值赋给R0
8484: e24bd00c sub sp, fp, #12
8488: e89da800 ldmia sp, {fp, sp, pc} ; 将栈中保存的main函数的栈帧恢复到fp和sp,将lr赋给pc,返回main函数
0000848c :
848c: e1a0c00d mov ip, sp ;sp地址保存至ip
8490: e92dd800 stmdb sp!, {fp, ip, lr, pc} ;将 pc lr ip fp 依次入栈
8494: e24cb004 sub fp, ip, #4 ; 0x4
8498: e24dd004 sub sp, sp, #4 ; 分配栈空间
849c: e3a03001 mov r3, #1 ; 0x1
84a0: e50b3010 str r3, [fp, #-16] ; 变量a入栈
84a4: e51b0010 ldr r0, [fp, #-16] ; 把a的值弹出给R0作为函数参数
84a8: ebffffec bl 8460 ; 调用test函数,bl执行时会自动把pc+4赋给lr寄存器
84ac: e3a03000 mov r3, #0 ; 0x0
84b0: e1a00003 mov r0, r3 ; 0 作为返回值赋给R0
84b4: e89da808 ldmia sp, {r3, fp, sp, pc} ; 依次出栈,返回到init代码