调用函数所用信息
- 函数的返回地址
- 函数的参数
- 临时变量
- 保存的上下文:包括在函数调用前后需要保持不变的寄存器
//函数从左到右,还是从右向左压栈
int fun(int a,int b )
{
int t_a = a;
int t_b = b;
return t_a + t_b;
}
int main()
{
int ret = 0;
ret = fun(10,20);
printf("ret = %d\n",ret);
}
当频繁调用的时候,宏函数没有压栈入栈的开销,只是预处理器进行简单的文本替换。
实际遇到的ARM函数调用过程分析
Bug描述
遇到Bus Fault错误,错误产生原因:
- 总线Fault:在取址、数据读/写、取中断向量、进入/退出中断时寄存器堆栈操作(入栈/出栈)时检测到内存访问错误。
- 实际调试发现是栈溢出的问题
看到SUB.W SP, SP, #66560共大约66K。占用66K堆栈
运行到这里时出错,在任务中分配的堆栈不够用了。
ARM函数调用过程分析
函数内外跳转的指令mov和BL
- (1)mov pc,<跳转地址>
向程序计数器PC(寄存器R15一般用做PC)直接写跳转地址,4GB连续空间内任意跳转。 - (2)B,BL,BLX, BX完成在当前指令向前或向后32MB的地址空间跳转。跳转的是一个相对当前PC值的一个偏移量,它的值由汇编器计算得出。BL常用,带返回地址的跳转,跳转之前在LR(连接寄存器)中保存当前PC的内容,为返回做准备。BL的用法:
1. BL NEXT; //跳转到NEXT
2. ...
3.
4. NEXT;
5. ...
6.
7. MOV PC,LR; //从被调用函数返回
1. int func(int a, int b, int c, int d)
2. {
3. return 1;
4. }
5.
6. int main()
7. {
8. int i = 1, j = 2;
9. func(i, j, 3, 4);
10. return 0;
11. }
main函数开辟的栈区和堆区
main函数内的栈区和堆区(没有free)的情况下,子函数都能使用。
栈的生长方向和内存存放的方向
- 栈往地址小的地方生长
int test(void)
{
int a=10;
int b=20;
int c=30;
int d=40;
printf("%x\n",&a); //0xa000 FFFF //高地址
printf("%x\n",&b); //0xa000 FFFC
printf("%x\n",&c); //0xa000 FFF8
printf("%x\n",&d); //0xa000 FFF4 //低地址
}
- 内存生长方向
小端模式:高位放在高地址,低位放在低地址