您的位置 首页 电源

DSP编程技巧—了解函数的调用进程

在我们使用C/C++对DSP进行编程的时候,函数无疑是功能模块划分的重要组成部分,这些函数之间则通过显式地调用或者中断等方式来共同工作。除了对特定的RTS库中的函数(例如某些数学函数)的调用按照它们内

  在咱们运用C/C++DSP进行编程的时分,函数无疑是功用模块区分的重要组成部分,这些函数之间则经过显式地调用或许中止等方法来一起作业。除了对特定的RTS库中的函数(例如某些数学函数)的调用依照它们内置规矩进行分配外,咱们自定义的函数之间的调用则需求遵从必定的规矩,了解这一进程对了解程序的履行和调试也是十分有协助的,下面咱们就来解读一下函数的调用进程,而且能够从其间了解到CPU寄存器、FPU寄存器以及栈(stack)在这一进程中的效果。


  一.父函数调用子函数

  在父函数调用子函数(被调函数)时,通常会履行以下的过程:

  1.假如寄存器不是SOE类型的(进口保存,save on entry),即它的值没有被被调用函数占用,可是在被调用函数回来值之后又会用到该寄存器的值的话,则该寄存器的值被保存在栈中。

  2.假如被调函数回来一个结构体,则调用函数会为结构体分配空间,而且把这段空间的地址作为第一个参数传递给被调函数,被调函数需求创立一个该结构体的本地副本。

  3.传递给被调函数的参数一般情况下会保存在寄存器中,在必要的情况下则会保存在栈中,由于寄存器的数量有限;详细的规矩是:

  (1)假如方针器材是FPU,而且传递的有32位的浮点从那时,则前4个浮点参数被保存在R0H-R3H这4个FPU寄存器中(留意与CPU寄存器AR0H-AR3H相差异)。

  (2)假如有64位的整形(longlong)参数,则第一个64位整形参数的高32位存入ACC寄存器中,低32位存入P寄存器中,其它的64位整形参数依照逆序(函数声明中参数列表里最左面的参数最终被压入栈中)保存在栈中。

  此外,假如P寄存器被用于参数传递,则对该函数的装入(prolog)和排空(epilog)的提取的优化功用(经过减小功用到达减小程序尺度)被制止。

  (3)假如参数中有任何的32位长整形或许浮点型,则第一个会放入ACC寄存器中,其它的32位参数则依照逆序保存在栈中。

  (4)指针参数被放入CPU寄存器XAR4和XAR5中,其它的指针则存入栈中。

  (5)剩下的16位的参数在CPU寄存器AL,AH,XAR4和XAR5可用的情况下,依照这一寄存器的次序被保存在它们中。

  4.任何没有被存入寄存器的参数都会被以逆序压入栈中,一切的32位参数在压入栈中时都会对齐到偶数地址。

  假如一个函数的参数中运用了省略号,即参数个数是可变的,则最终一个显式声明的参数在压入栈中之后,它在栈中的地址能够用来定位未显式声明的参数。

  5.栈指针SP有必要在父函数调用子函数之前偶对齐。假如不是偶对齐,则需求把SP加1.

  6.父函数运用LCR指令(运用回来程序指针寄存器RPC的方法来进行22位的长调用)来调用子函数,在调用时RPC寄存器的值会被压入栈中,然后能够把回来地址保存在RPC寄存器中。

  7.最终,栈被对齐到函数的鸿沟上。

  二.子函数呼应父函数

  在子函数被调用时,通常会履行以下的过程:

  1.假如被调函数修改了XAR1、XAR2或许XAR3的值,则有必要保存它们的值,由于在调用前后,父函数假定这3个寄存器的值在被回来之前是被保存的。假如方针是FPU,而且在被调函数中修改了R4H-R8H的值,则相同需求保存它们的值。

  2.被调用的函数需求在栈中为一切的本地变量、暂时存储区域现已任何被调用的参数分配满足的空间。在经过为SP寄存器加偏移量跳转到被调函数之后,这段存储空间就马上被分配了。

  3.栈被对齐到函数的鸿沟上。

  4.假如被调用的函数参数中有结构体,则它实践接收到的是该结构体的指针。假如在被调函数中对该结构体进行了写操作,则有必要在栈中分配空间以创立该结构体的副本,在完结操作之后把本地结构体经过指针仿制回原有的结构体。假如在被调函数中不对传入的结构体参数进行写操作,则能够经过对其指针的操作来完结参数的引证。

  5.完结参数传入之后,被调函数履行它本身的代码。

  6.功用履行完结之后,被调函数回来值,依据回来值的类型,它们值的保存方位分别为:

  16位整数:AL寄存器

  32位整数:ACC寄存器

  64位整数:ACC和P寄存器

  16位或许22位指针:XAR4寄存器

  FPU下的32位浮点数:R0H寄存器

  结构体:其指针保存在XAR4寄存器中

  在回来结构体的情况下,例如s=f(x),其间s为结构体,f为函数,则能够直接用f(&s,x)的方法在父函数中调用子函数f,经过结构体指针,被调函数能够主动回来结构体的值了。

  7.经过把SP中减去调用子函数时加的偏移量,SP寄存器能够从头指向父函数。

  8.被调函数康复一切在第一步中保存的建城七队值。

  9.被调函数运用LRETR(运用PC指针回来)指令回来,PC寄存器的值被置为RPC寄存器中的值,即回来地址,然后RPC寄存器中的原有值被推出栈并从头保存在RPC寄存器中。

  经过以上的描绘,能够看出栈在函数调用前后起着十分要害的中继效果。所以,假如在调用时传递的参数十分多,例如传递了一个很长的数组,或许有多个64位的参数,则栈很有或许没有满足的空间来完结参数的暂存,形成栈的溢出,乃至形成程序运转成果的反常或许过错的输出成果,由于编译器无法查看栈的溢出过错(除非咱们自己编写某些代码来检测),所以要为栈分配一个相对较大的存储空间,它的默认值是1K字。即使是十分小的程序,常用例程里栈的长度也往往能到达0x400这样的长度。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/dianyuan/226807.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部