第2章第3节 ARM7芯片的函数调用标…
来源:互联网 发布:top域名有什么用 编辑:程序博客网 时间:2024/05/23 14:28
目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档
第3节 ARM7芯片的函数调用标准
在上节,我们最后用汇编语言写了一个函数,但该函数没有入口参数,那么C语言函数、汇编函数之间是如何传递参数和返回值的?函数在执行过程中是如何使用栈的?它们需要遵守什么规则?本节我们将介绍这方面的内容。
如果我们不是在编写操作系统,只是编写正常的C函数,那么我们是不需要关心函数调用的细节,编译器会遵守一定的函数调用规则编译成二进制代码,当所有不同类型的编译器都遵守这个相同的规则时,各种编译器编译出来的程序就可以互相配合运行了。这个规则就是AAPCS——Procedure
AAPCS对ARM结构的一些标准做了定义,在这里我们只重点介绍函数调用部分,如图9所示,AAPCS为ARM的R0~R15寄存器做了定义,明确了它们在函数中的职责:
图
函数调用时的规则如下:
1.
2.
3.
4.
5.
6.
7.
8.
9.
上述只介绍了本手册中使用到的情形,具体的情况在编写操作系统代码时会涉及到,其它规则请请读者自行查找资料。
接下来我们再通过几个小例子熟悉一下C函数与汇编函数的调用过程。下面的C函数TestFunc1与汇编函数TestFunc2的功能是一样的。
U8
{
}
TestFunc2:
TestFunc2函数使用了R0、R1、R3、R4、R5、R6、R10共7个寄存器,遵循AAPCS规则,在使用R0、R1和R3之前并没有对它们压栈,但对R5、R6和R10寄存器进行了压栈保存,在函数返回前又出栈还原了这3个寄存器,这样TestFunc2函数返回到它的父函数之后,R5、R6和R10寄存器的数值是没有改变的,而R0、R1、R3和R4则分别被改写为了21、1、2和3。
下面我们再来看看C函数TestFunc3调用汇编函数TestFunc4完成1+2的运算。
U8
{
}
TestFunc4:
TestFunc3函数在调用TestFunc4函数前已经将参数1和2分别存入R0和R1,并将返回地址存入到R14中,然后才跳转到TestFunc4函数,发生函数调用。这时程序将运行TestFunc4函数,它将R0和R1相加,将结果放入R0,需要通过R0将返回值返回给TestFunc3函数。此时R14中保存的就是返回TestFunc3函数的返回地址,最后TestFunc4函数跳转到R14就返回到了TestFunc3函数,TestFunc3函数从R0就可以取出TestFunc4函数计算的结果了。
下面我们再来看看汇编函数TestFunc5调用C函数TestFunc6完成1+2的运算。
TestFunc5:
U8
{
}
TestFunc5函数先将参数1和2存入R0和R1寄存器,准备调用TestFunc6函数并传递入口参数,然后将R14寄存器压栈,以防止使用BL指令时存入的R14返回地址破坏R14原有的数据,然后调用TestFunc6函数。在调用TestFunc6函数时BL指令会自动将“LDR
当函数比较简单,不需要压栈仅使用寄存器便可以完成运算的时候,那么下面的TestFunc7函数,它的返回值是多少?
U8*
{
}
按照上面的分析,对于这个简单的函数,编译器是不会为局部变量ucPara1分配内存空间的,ucPara1只会保存在寄存器中,因此无从谈起它的地址。但这个这么简单的函数却偏偏要获取这个仅在寄存器中的局部变量的地址,遇到这种情况,编译器在编译时会特别为ucPara1专门在栈中分配内存,因此也就可以获取到它的地址了。
当然,这个函数没有任何意义,仅是举一个例子,而且写C语言时要避免发生这种情况,因为TestFunc7函数返回的是栈内局部变量的地址,当TestFunc7函数运行完后,ucPara1这个局部变量所在的栈空间已经被释放,这个栈空间很可能已经被其它变量占用,如果这时候还使用这个地址的话就可能会导致系统崩溃,新手要避免产生这个错误。
- 第2章第3节 ARM7芯片的函数调用标…
- 第2章第1节 ARM7芯片基本结构
- 第2章第2节 ARM7汇编语言简介
- 第1章第2节 操作系统的分类
- 第3章第1节 两个固定任务之间的切…
- 第4章第3节 实时事件触发的实时抢…
- 第4章第3节 实时事件触发的实时抢…
- 第4章第3节 实时事件触发的实时抢…
- 第4章第2节 定时器触发的实时抢占…
- 第4章第2节 定时器触发的实时抢占…
- 第3章第2节 任意任务间的切换
- 第3帖:稳压芯片的电容器
- 第3章第5节 发布Wanlix操作系统
- 第2章第4节 Wanlix的文件组织结构
- 第2章第5节 Wanlix的开发环境
- Dive into python 第4章 自省的威…
- 第3章第3节 用户代码入口——根任务…
- 第3章第4节 使用Wanlix编写交通红…
- 第1章第1节 为什么要使用操作系统
- 第1章第2节 操作系统的分类
- 第2章 写操作系统前的预备知识
- 第2章第1节 ARM7芯片基本结构
- 第2章第2节 ARM7汇编语言简介
- 第2章第3节 ARM7芯片的函数调用标…
- iRet和iRetCode导致的bug
- 第2章第4节 Wanlix的文件组织结构
- 第2章第5节 Wanlix的开发环境
- 第3章 Wanlix操作系统
- 第3章第1节 两个固定任务之间的切…
- spring mvc(注解)上传文件的简单例子
- 第3章第2节 任意任务间的切换
- 第3章第3节 用户代码入口——根任务…