ARM体系下函数形参调用寄存器详解
文章目录前言一、编写代码二、调试分析三.流程归纳总结前言在ARM体系下C和汇编语言混合编程的学习过程中,了解到关于函数形参在x86平台与ARM平台所调用的寄存器有一定的区别。64位程序根据参数的个数而不同, 当参数1~6个,使用寄存器传递;参数大于6个,多出来的参数使用栈传递。对于ARM平台,结论是:参数值传递按顺序存放在寄存器r0,r1,r2,r3里,超过4个参数值传递则放栈里。于是我就在MDK
前言
在ARM体系下C和汇编语言混合编程的学习过程中,了解到关于函数形参在x86平台与ARM平台所调用的寄存器有一定的区别。
64位程序根据参数的个数而不同, 当参数1~6个,使用寄存器传递;参数大于6个,多出来的参数使用栈传递。
对于ARM平台,结论是:参数值传递按顺序存放在寄存器r0,r1,r2,r3里,超过4个参数值传递则放栈里。
于是我就在MDK环境下用main
函数调用子函数,仿真来观察其具体过程,让我们一起来看看在ARM体系下关于调用函数的一些细节。
一、编写代码
-
新建工程,创建一个main.c文件
-
编写main函数和一个子函数sub
#include <stdio.h>
void sub(int a1,int a2,int a3,int a4,int a5,int a6);
int main()
{
sub(0x11,0x22,0x33,0x44,0x55,0x66);//16进制是为了方便调试时便于观察,在仿真时数据是以16进制显示的
return 0;
}
void sub(int a1,int a2,int a3,int a4,int a5,int a6)
{
a3=a1+a2; //此函数体可以为空
a5=(a3+a4);
}
- 设置断点
- 开始仿真
- 打开反汇编窗口
- 运行程序至断点
二、调试分析
- 单步执行
每点击这个按钮,程序只运行1步,单步执行观察程序执行结果
-
开始调试
-
查看界面左侧寄存器状态栏的值
可以看到寄存器r0的值变为0x66
- 继续单步执行
当反汇编窗口中的黄色指针指向上图情况,停下来稍微分析一下
此时注意仔细看寄存器状态栏中R0
,R1
,R2
,R3
的值,发现分别为0x66
,0x55
,0x33
,0x44
,是函数sub传入的参数
个人认为,MOV指令可以相当于c语言中的赋值,执行以上语句分别就是
将R0
赋值为0x66
,R1
赋值为0x55
,R3
赋值为0x44
,R2
赋值为0x33
我们再来看这条语句
STRD r1,r0,[sp,#0]
STRD的作用: 将数据加载到指定内存地址
所以这句话的意思应该是将r1,r0寄存器中的数据写到(sp指针+0)的内存地址中去。
-
继续执行
当程序执行到上图所示时,我们可以发现原来R0
的值为0x66
,R1
的值为0x55
,最后R0
被0x11
覆盖,R1
被0x22
覆盖。 -
小结
经过以上步骤,我发现当函数参数多于4个时,其余参数是使用内存中的栈传递的。以本题为例,a1,a2,a3,a4分别用R0
,R1
,R2
,R3
寄存器传递,a5,a6 则被写入内存,调用栈来进行传递。
调用子函数间的参数依次通过R0~R3
这4个寄存器传递。父函数在调用子函数前先将参数存入到R0~R3
中,若只有一个参数则使用R0传递,2个则使用R0和R1传递,依次类推,当超过4个参数时,其它参数通过栈传递。当子函数运行时,根据自身参数个数自动从R0~R3或者栈中读取参数。
三.流程归纳
- 从最后一个参数开始写入,写入四个参数
这里为什么在会先执行写入数据到R3,再执行写入数据到R2呢,难不成这指令还流行插队的?别急,马上我们就知道答案了。
- 将多余参数加载到内存中
仔细观察寄存器中的值,会发现从R0,R1,R2,R3中的值顺序刚好为函数传入参数中的第一个到第四个,原来上一步先执行将数据加载到R3寄存器中,再执行加载数据到R2寄存器的指令,是“早有预谋”,是不是很神奇呢,哈哈。
- 关于嵌套调用子函数
如果只有R0~R3
4个寄存器,那么当发生嵌套调用时,原有的函数参数值是被丢弃了吗?
参考这篇文章,我找到了答案
ARM 编程:C语言与汇编间互相调用,参数与返回值的传递方式详解
原来发生函数调用时,即使是父函数有参数需要传递,子函数也可以任意更改R0~R3寄存器,无需考虑会破坏它们在父函数中保存的数值,返回父函数前无需恢复其值。AAPCS规定,发生函数调用前,由父函数将R0~R3
中有用的数据压栈,然后才能调用子函数,以防止父函数R0~R3
中的有用数据被子函数破坏。
调用完子函数后,将原有数据弹栈,数据即可恢复。
总结
这篇博客是我学习关于ARM体系下调用函数参数是寄存器的状态心得,在分析函数参数调用过程中时,遇到了很多困难,不过,发现问题并解决问题的过程总是很快乐的,也让我对ARM处理器中的寄存器有了更多了解,如果有机会,我会写写关于其余寄存器的一些心得,也算是一个收尾吧。
不过因为没有系统的学过汇编语言,编译原理等,所以上述分析过程可能存在许多问题。若有问题,希望大家能不吝指教,一起学习进步。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)