最近在分析一下ARM架构linux环境中的应用态,内核态中相关的调试方法,其中一个重要的方面就是分析函数调用的调用栈。ARM架构函数调用栈遵循APCS规则,下面通过一个例子分析一下ARM调用栈的结构。
int callfunctionA(int aa, int bb, int c, int d, int e, int f)
{
8480: e92d4800 push {fp, lr}
8484: e28db004 add fp, sp, #4
8488: e24dd018 sub sp, sp, #24
848c: e50b0010 str r0, [fp, #-16]
8490: e50b1014 str r1, [fp, #-20]
8494: e50b2018 str r2, [fp, #-24]
8498: e50b301c str r3, [fp, #-28]
int a = 0;
849c: e3a03000 mov r3, #0
84a0: e50b3008 str r3, [fp, #-8]
int b = 0;
84a4: e3a03000 mov r3, #0
84a8: e50b300c str r3, [fp, #-12]
printf("the a is %i, the b is %i\n", a, b);
84ac: e59f001c ldr r0, [pc, #28] ; 84d0
84b0: e51b1008 ldr r1, [fp, #-8]
84b4: e51b200c ldr r2, [fp, #-12]
84b8: ebffff89 bl 82e4 <_init+0x20>
callfunctionB();
84bc: ebffffe0 bl 8444
return 0;
84c0: e3a03000 mov r3, #0
}
84c4: e1a00003 mov r0, r3
84c8: e24bd004 sub sp, fp, #4
84cc: e8bd8800 pop {fp, pc}
84d0: 000085cc .word 0x000085cc
callfunctionA(1, 2, 3, 4, 5, 6);
8518: e3a03005 mov r3, #5
851c: e58d3000 str r3, [sp]
8520: e3a03006 mov r3, #6
8524: e58d3004 str r3, [sp, #4]
8528: e3a00001 mov r0, #1
852c: e3a01002 mov r1, #2
8530: e3a02003 mov r2, #3
8534: e3a03004 mov r3, #4
8538: ebffffd0 bl 8480
从汇编来看,调用栈分为三个部分,最开始部分是部分行参,就是要传递到调用函数中的参数。然后第二部分是返回地址,和上一帧栈位置的地址
第三部分是函数局部变量的地址,但是ARM是用寄存器来传递参数的,如果传递参数超过了4个,超过的采用调用栈来传递参数。
阅读(5318) | 评论(0) | 转发(0) |