C函数与汇编函数之间参数及返回值传递方法

发布者:TranquilDreams最新更新时间:2018-12-01 来源: eefocus关键字:C函数  汇编函数  参数  返回值  传递方法 手机看文章 扫描二维码
随时随地手机看文章

AAPCS对ARM结构的一些标准做了定义,在这里我们只重点介绍函数调用部分,如图8所示,AAPCS为ARM的R0~R15寄存器做了定义,明确了它们在函数中的职责:


这里写图片描述 

图 8 AAPCS关于ARM寄存器的定义

一、函数调用时的规则如下: 

1、 父函数与子函数间的入口参数依次通过R0~R3这4个寄存器传递。父函数在调用子函数前先将参数存入到R0~R3中,若只有一个参数则使用R0传递,2个则使用R0和R1传递,依次类推,当超过4个参数时,其它参数通过栈传递。当子函数运行时,根据自身参数个数自动从R0~R3或者栈中读取参数。 

2、子函数通过R0寄存器将返回值传递给父函数。子函数返回时,将返回值存入R0,当返回到父函数时,父函数读取R0获得返回值。 

3、发生函数调用时,R0~R3是传递参数的寄存器,即使是父函数没有参数需要传递,子函数也可以任意更改R0~R3寄存器,无需考虑会破坏它们在父函数中保存的数值,返回父函数前无需恢复其值。AAPCS规定,发生函数调用前,由父函数将R0~R3中有用的数据压栈,然后才能调用子函数,以防止父函数R0~R3中的有用数据被子函数破坏。 

4、 R4~R11为普通的通用寄存器,若子函数需要使用这些寄存器,则需要将这些寄存器先压栈然后再使用,以免破坏了这些寄存器中保存的父函数的数值,子函数返回父函数前需要先出栈恢复其数值,然后再返回父函数。AAPCS规定,发生函数调用时,父函数无需对这些寄存器进行压栈处理,若子函数需要使用这些寄存器,则由子函数负责压栈,以防止父函数R4~R11中的数据被破坏。 

5、编译器在编译时就确定了函数间的调用关系,它会使函数间的调用遵守3、4条规定。但编译器无法预知中断函数的调用,被中断的函数无法提前对R0~R3进行压栈处理,因此需要在中断函数里对它所使用的R0~R11压栈。对于中断函数,不遵守第3条规定,遵守第5条规定。 

6、R12寄存器在某些版本的编译器下另有它用,用户程序不能使用,因此我们在编写汇编函数时也必须对它进行压栈处理,确保它的数值不能被破坏。 

7、R13寄存器是堆栈寄存器(SP),用来保存堆栈的当前指针。 

8、R14寄存器是链接寄存器(LR),用来保存函数的返回地址。 

9、R15寄存器是程序寄存器(PC),指向程序当前的地址。 

上述只介绍了本手册中使用到的情形,具体的情况在编写操作系统代码时会涉及到,其它规则请请读者自行查找资料。


二、例子 

接下来我们再通过几个小例子熟悉一下C函数与汇编函数的调用过程。下面的C函数TestFunc1与汇编函数TestFunc2的功能是一样的。 


U8 TestFunc1(void) 

U8 ucPara1; 
U8 ucPara2; 
U8 ucPara3; 
U8 ucPara4; 
U8 ucPara5; 
U8 ucPara6;

ucPara1 = 1;
ucPara2 = 2;
ucPara3 = 3;
ucPara4 = 4;
ucPara5 = 5;
ucPara6 = 6;

return ucPara1 + ucPara2 + ucPara3 + ucPara4 + ucPara5 + ucPara6;12345678

}

.func TestFunc2 
TestFunc2:

STMDB R13!, {R5 - R6, R10}    @R5,R6,R10寄存器压栈
LDR R1, =1
LDR R3, =2
LDR R4, =3
LDR R5, =4
LDR R6, =5
LDR R10, =6

ADD R0, R1, R3
ADD R0, R0, R4
ADD R0, R0, R5
ADD R0, R0, R6
ADD R0, R0, R10

LDMIA R13!, {R5 - R6, R10}    @R5,R6,R10寄存器出栈

.endfunc1234567891011121314151617


TestFunc2函数使用了R0、R1、R3、R4、R5、R6、R10共7个寄存器,遵循AAPCS规则,在使用R0、R1和R3之前并没有对它们压栈,但对R5、R6和R10寄存器进行了压栈保存,在函数返回前又出栈还原了这3个寄存器,这样TestFunc2函数返回到它的父函数之后,R5、R6和R10寄存器的数值是没有改变的,而R0、R1和R3则分别被改写为了1、2和3。


下面我们再来看看C函数TestFunc3调用汇编函数TestFunc4完成1+2的运算。 


U8 TestFunc3(void) 

return TestFunc4(1, 2); 
}

.func TestFunc41

TestFunc4:

ADD R0, R0, R1
BX R14;

.endfunc1234


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的运算。


.func TestFunc5 
TestFunc5:

MOV R0, #1
MOV R1, #2
SUB R13, R13, #4
STR R14, [R13]
BL TestFunc6
LDR R14, [R13]
ADD R13, R13, #4
BX R14

.endfunc12345678910

U8 TestFunc6(U8 ucPara1, U8 ucpara2) 

return ucPara1 + ucPara2; 


TestFunc5函数先将参数1和2存入R0和R1寄存器,准备调用TestFunc6函数并传递入口参数,然后将R14寄存器压栈,以防止使用BL指令时存入的R14返回地址破坏R14原有的数据,然后调用TestFunc6函数。在调用TestFunc6函数时BL指令会自动将“LDR R14, [R13]”这条指令的地址存入R14,这样就开始运行TestFunc6函数了。TestFunc6函数会自动从R0和R1寄存器中取出参数,将计算结果存入R0,通过R0将返回值返回给TestFunc5函数。TestFunc6函数跳转回TestFunc5函数后,TestFunc5函数从栈中恢复原有的R14寄存器,完成函数调用,此时R0中的数值就是TestFunc6函数的计算结果。


当函数比较简单,不需要压栈仅使用寄存器便可以完成运算的时候,那么下面的TestFunc7函数,它的返回值是多少? 


U8* TestFunc7(void) 
{

U8 ucPara1;

ucPara1 = 1;

return &ucPara1;123



按照上面的分析,对于这个简单的函数,编译器是不会为局部变量ucPara1分配内存空间的,ucPara1只会保存在寄存器中,因此无从谈起它的地址。但这个这么简单的函数却偏偏要获取这个仅在寄存器中的局部变量的地址,遇到这种情况,编译器在编译时会特别为ucPara1专门在栈中分配内存,因此也就可以获取到它的地址了。 

当然,这个函数没有任何意义,仅是举一个例子,而且写C语言时要避免发生这种情况,因为TestFunc7函数返回的是栈内局部变量的地址,当TestFunc7函数运行完后,ucPara1这个局部变量所在的栈空间已经被释放,这个栈空间很可能已经被其它变量占用,如果这时候还使用这个地址的话就可能会导致系统崩溃,新手要避免产生这个错误。


关键字:C函数  汇编函数  参数  返回值  传递方法 引用地址:C函数与汇编函数之间参数及返回值传递方法

上一篇:关于中断服务函数带来返回值的思考
下一篇:vxWorks内核解读四--中断

推荐阅读最新更新时间:2024-03-16 16:19

在线纸张水分测试仪参数介绍和注意事项
在线纸张水分测试仪此款产品广泛应用于纸张,煤炭,奶粉,人造板等行业,对生产线上的产品进行实时检测,由于生产流程和工艺需要,在线监测产品的水分含量成为重要的环节。在线纸张水分测试仪利用红外光漫反射原理对产品进行水分检测,并将水分实时数据传输到先视频上,为技术部门提供检测参数指导。纸张含水量约为5%或6%而如果要求保存的话纸张含水量需要控制在3%-4%,在线纸张水分测试仪测量精度准确,产品质量和稳定性好。得到广大行业客户的认可和好评,以亲民的价格征服众多企业。 红外在线纸张水分测试仪使用注意事项: 在线水分仪红外灯直径 8cm 光源照射厚度:5mm 3cm 管子挂光圈(绝缘) 3、检测如有安装玻璃罩:玻璃选取普通透光、与光源有2
[测试测量]
关于STM32 通用定时器初始化参数的理解
定时器初始化结构体定义为 typedef struct { uint16_t TIM_Prescaler; uint16_t TIM_CounterMode; uint16_t TIM_Period; uint16_t TIM_ClockDivision; uint8_t TIM_RepetitionCounter; } TIM_TimeBaseInitTypeDef; 其中: TIM_Prescaler为预分频因子,取值范围为0x0000 到 0xFFFF,决定了定时器时钟频率。定时器时钟频率 = 定时器时钟源频率 /
[单片机]
关于STM32 通用定时器初始化<font color='red'>参数</font>的理解
了解示波器探头参数
探头是我们观测波形的第一步,它是连接被测设备与示波器输入端的电子部件,工程师每天都会使用它捕获波形,进行测试分析。但是你了解探头的那些重要参数吗? 01带宽 在我们选择探头时,首先要看的参数就是带宽,探头和示波器的带宽定义是一样的。如图1所示,带宽所指的频率是正弦波信号衰减到-3dB(即高频处增益下降到0.707)时的频率。 图1 -3dB衰减示意图 那么如果我们如何根据被测信号的频率来选择合适带宽的探头呢? 以1MHz的方波为例,由于1MHz的方波是由1MHz、3MHz、5MHz、7MHz......等正弦波叠加而成,想要得到较为完整的方波信息,最少需要5次谐波
[测试测量]
了解示波器探头<font color='red'>参数</font>
氧化锌避雷器直流参数测试仪的功能介绍
TKBLQ避雷器测试仪又称氧化锌避雷器直流参数测试仪及避雷器直流参数测试仪,氧化锌避雷器直流参数测试仪用于检测10kV及以下电力系统用无间隙氧化锌避雷器MOA阀电间接触不良的内部缺陷,氧化锌避雷器直流参数测试仪测量MOA的直流参考电压(U1mA)和0.75U1mA下的泄漏电流。 TKBLQ氧化锌避雷器直流参数测试仪是专门用于检测10kV及以下电力系统用无间隙氧化锌避雷器MOA阀电间接触不良的内部缺陷,测量MOA的直流参考电压(U1mA)和0.75U1mA下的泄漏电流。该氧化锌避雷器直流参数测试仪将直流高压电源、测量和控制系统组成一体,全部元件浓缩在一个机箱内,具有体积小,重量轻等特点,氧化锌避雷器直流参数测试仪是电力系统以及氧
[测试测量]
太阳能环境参数测试仪的系统电路设计
  为了确保太阳能发电系统能够正常的工作,需要对太阳能发电系统的各项环境参数进行测量,从而有效地控制其运行。本文介绍了一种基于单片机的太阳能参数测试仪,提供了3种参数的测量功能和通信接口,以及2种供电方式,既可作为手持设备使用,又能安装在发电系统中,具有较高的实用价值。该测试仪以AT89S52单片机为核心,外接温湿度传感器SHTll、照度传感器TSL2561、四位共阴数码管、RS485总线通信接口以及显示切换按键。单片机上电工作后,对当前温度、湿度、光强度进行实时测量,通过按键切换将测得的3种参数通过LED 数码管进行轮流显示;此外,还可以通过RS485总线与PC 机进行通信,将参数值传送到上位机,以达到远程监测的目的。   测量模
[测试测量]
太阳能环境<font color='red'>参数</font>测试仪的系统电路设计
基于测量数据的电磁兼容性能参数建模的研究
随着社会信息化水平发展的不断提高,各行各业对电子系统电磁兼容性能的认识不断深入,重视程度也不断提高。但是,现实中许多电子系统存在比较严重的电磁兼容问题,已经严重影响到其性能的发挥。因此归纳综合电子系统电磁参数及电磁兼容性变化规律就显得尤为重要。本文对模型建立过程及具体实现进行了阐述。   1 参数模型建立过程   电磁兼容测试数据主要指系统进行电磁兼容测试产生的原始数据和其经过整理得到的数据,如发射设备的峰值功率、杂散电平、功率大于设定门限的谐波数量等。在对测量数据进行数据建模的过程中,从不同的研究角度可以得到不同的结论。例如在研究参数特性的时候,可以进行某个参数和另一参数的相关分析,研究参数之间变化的相关规律;可以建立多元回归模
[模拟电子]
基于测量数据的电磁兼容性能<font color='red'>参数</font>建模的研究
小米11部分镜头参数爆料:超大底50MP主摄,长焦为12MP或48MP
数码博主 @数码闲聊站 今日爆料称,他拿到了一款工程机,通过近期爆料风格以及对网友的回复来看,预计为小米旗下下一款旗舰机型小米 11,但也不排除是 Redmi K40 Pro 系列旗舰的可能。   虽然该博主拿到了真机,但无奈该机背部全部遮盖保密,因此看不到实机镜头排列情况。   他从该机系统内发现,主摄像头通过 4 合 1 折算出来约等于 5000 万像素,而长焦镜头显示为 12MP,暂不确定是直出的 12MP 镜头还是 4 合一的 48MP 镜头。   IT之家提醒,虽然 50 MP镜头不常见,但之前华为推出的 P40 即采用了5000 万像素(RYYB、23mm、F1.9 光圈)的主摄镜头。   此外,他手中的这款是高配
[手机便携]
小米11部分镜头<font color='red'>参数</font>爆料:超大底50MP主摄,长焦为12MP或48MP
LED洗墙灯及其基础参数介绍
   LED 洗墙灯又叫线型LED投光灯等等,因为其外形为长条形,也有人将之称为LED线条灯,主要也是用来做建筑装饰照明之用,还有用来勾勒大型建筑的轮廓,其技术参数与LED投光灯大体相似,相对於LED投光灯的圆形结构,LED洗墙灯的条形结构的散热装置显得更加好处理一点。      LED洗墙灯和护栏管有很多的相同点,让我们来对它的参数进行介绍:       1)电压:      LED洗墙灯的电压为220V,110V,24V,12V,几种,所以我们在选择 电源 时候就要注意相对应的电压.另外还有18V,36V,由于这两款变压器在市场上相对少,不好配变压器,故一般低压采用24V或12V。       2)工作温度:      因
[电源管理]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved