stm32汇编与C接口/软件性能效率提升问题

方法:

1、先切换到ArmCC.exe所在文件夹

cd D:\Keil_v5\ARM\ARMCC\bin

2、使用ARMCC编译main.c文件,输出main_armcc.s汇编文件

.\ArmCC.exe --arm -S .\main.c -o main_armcc.s

------------------------------------------------------------------------------------------------------------------------------------------

如下两段C代码和其对应的汇编,逻辑相同,区别在于变量类型,一个使用8bit char一个使用32bit int,对应的汇编代码却不相同,使用char型会多出几步操作。

所以在编程时如果没有特殊需求,尽量使用32位的类型

int test_main(int a0,char a1, char a2,char a3,char a4)
{
	a1 = a1*a2;
	a3 = a3*a4;
	a0 = a1+a3;
	return a0;
}
test_main PROC
        MUL      r0,r1,r2
        LDR      r12,[sp,#0]
        AND      r0,r0,#0xff
        MUL      r1,r3,r12
        AND      r1,r1,#0xff
        ADD      r0,r0,r1
        BX       lr
        ENDP

 

int test_main(int a0,int a1, int a2,int a3,int a4)
{
	a1 = a1*a2;
	a3 = a3*a4;
	a0 = a1+a3;
	return a0;
}
test_main PROC
        MUL      r0,r1,r2
        LDR      r12,[sp,#0]
        MLA      r0,r3,r12,r0
        BX       lr
        ENDP

 以下内容引自其他博客

对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS主要是定义了函数呼叫时参数的传递规则以及如何从函数返回,关于ATPCS请搜索。另外还有AAPCS (ARM Archtecture Procedure Call Standard),是ATPCS的改进版。

有了这些规则之后,单独编译的C语言程序就可以和汇编程序相互调用。

2. 寄存器使用规则

  • 子程序间通过寄存器R0~R3来传递参数。这时,寄存器R0~R3可记作a0~a3。被调用的子程序在返回前无需恢复寄存器R0~R3的内容。
  • 在子程序中,使用寄存器R4~R11来保存局部变量。这时,寄存器R4~R11可以记作v1~v8。如果在子程序中使用了寄存器v1~v8中的某些寄存器,则子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值。在Thumb程序中,通常只能使用寄存器R4~R7来保存局部变量。
  • 寄存器R12用作过程调用中间临时寄存器,记作IP。在子程序之间的连接代码段中常常有这种使用规则。
  • 寄存器R13用作堆栈指针,记作SP。在子程序中寄存器R13不能用作其他用途。寄存器SP在进入子程序时的值和退出子程序时的值必须相等。
  • 寄存器R14称为连接寄存器,记作LR。它用于保存子程序的返回地址。如果在子程序中保存了返回地址,寄存器R14则可以用作其他用途。
  • 寄存器R15是程序计数器,记作PC。它不能用作其它用途。

3. 堆栈使用规则

  • ATPCS规定堆栈为FD(Full Descending: sp指向最后一个压入的值,数据栈由高地址向低地址生长)类型,即满递减堆栈,并且对堆栈的操作是8字节对齐。所以经常使用的指令就有STMFD和LDMFD。
  • 对于汇编程序来说,如果目标文件中包含了外部调用,则必须满足下列条件:

    外部接口的堆栈必须是8字节对齐的。
    在汇编程序中使用PRESERVE8伪指令告诉连接器,本汇编程序数据是8字节对齐的。

4. 参数传递规则

  • 根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变化的子程序。
  • 这两种子程序的参数传递规则是不一样的。

4.1 参数个数可变子程序参数传递规则

  • 对于参数个数可变的子程序,当参数个数不超过4个时,可以使用寄存器R0~R3来传递参数;当参数超过4个时,还可以使用堆栈来传递参数。
  • 在传递参数时,将所有参数看作是存放在连续的内存字单元的字数据。然后,依次将各字数据传递到寄存器R0,R1,R2和R3中。如果参数多于4个,则将剩余的字数据传递到堆栈中。入栈的顺序与参数传递顺序相反,即最后一个字数据先入栈。

4.2 参数个数固定子程序参数传递规则

  • 如果系统不包含浮点运算的硬件部件,浮点参数会通过相应的规则转换成整数参数(若没有浮点参数,此步省略),然后依次将各字数据传送到寄存器R0~R3中。如果参数多于4个,将剩余的字数据传送堆栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈。在参数传递时,将所有参数看作是存放在连续的内存字单元的字数据。

5. 子程序结果返回规则

子程序中结果返回的规则如下:

结果为一个32位整数时,可以通过寄存器R0返回;
结果为一个64位整数时,可以通过寄存器R0和R1返回;
结果为一个浮点数时,可以通过浮点运算部件的寄存器f0、d0或s0来返回;
结果为复合型浮点数(如复数)时,可以通过寄存器f0~fn或d0~dn来返回;
对于位数更多的结果,需要通过内存来传递。

以下摘自Cortex-M3权威指南

汇编与 C 的接口 
  在很多情况下,都需要让 C 程序模块与汇编程序模块互相交互,它们包括: 

  • 在 C 代码中使用了嵌入式汇编(或者是在 GNU 工具下,使用了内联汇编) 
  • C 程序呼叫了汇编程序,这些汇编程序是在独立的汇编源文件中实现的 
  • 汇编程序调用了C程序 

在这些情况下,必须知晓参数是如何传递的,以及值是如何返回的,才能在主调函数与子程序之间协同工作。这些交互的机制在ARM中有明确的规定,由文档《ARM Architecture Procedure Call Standard(AAPCS, Ref5)》给出。 
不过,在大多数场合下的情况都比较简单:当主调函数需要传递参数(实参)时,它们使用R0‐R3。其中R0传递第一个,R1传递第2个……在返回时,把返回值写到R0中。在子程序中,可以随心所欲地使用R0‐R3,以及R12(回顾第9章,想想为什么会PUSH它们)。但若使用R4‐R11,则必须在使用之前先PUSH它们,使用后POP回来。 可见,汇编程序使用R0‐R3, R12时会很舒服。但是如果换个立场——汇编要呼叫C函数,则考虑问题的方式就有所不同:必须意识到子程序可以随心所欲地改写R0‐R3, R12,却决不会改变R4‐R11。因此,如果在调用后还需要使用R0‐R3,R12,则在调用之前,必须先PUSH,从C函数返回后再POP它们,对R4‐R11则不用操心。在本章的示例程序中,绝大多数只是调用汇编子程序,它们只影响少量寄存器,或者会在返回前恢复寄存器的内容,所以往往没有严格遵守AAPCS。这主要是为了突出其它重点,简化程序,请读者不要钻牛角尖。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值