- 论坛徽章:
- 0
|
本帖最后由 crifan 于 2011-04-16 11:02 编辑
关于“使用BL 调用C程序中的函数时,如何把C程序中的参数传递给汇编”:
关于汇编中,类似bl的跳转去调用C函数的话,其中参数传递,是依据一定规则,不同的编译器,不同的平台,对应不同的规则。
对于arm来说,一般是依据APCS(ARM Procedure Call Standard),其更多细节,参见附件:
ARM中文指令集.chm
(151.04 KB, 下载次数: 118)
其中,此处和参数调用相关的内容是:
“实际参数
APCS没有定义记录、数组、和类似的格局。这样语言可以自由的定义如何进行这些活动。但是,如果你自己的实现实际上不符合 APCS 的精神,那么将不允许来自你的编译器的代码与来自其他编译器的代码连接在一起。典型的,使用 C 语言的惯例。 - 前 4 个整数实参(或者更少!)被装载到 a1 - a4。
- 前 4 个浮点实参(或者更少!)被装载到 f0 - f3。
- 其他任何实参(如果有的话)存储在内存中,用进入函数时紧接在 sp 的值上面的字来指向。换句话说,其余的参数被压入栈顶。所以要想简单。最好定义接受 4 个或更少的参数的函数。
”
其中a1-a4就是r0-r4,f0-f3:
http://blog.csdn.net/yyt7529/archive/2009/08/02/4401897.aspx
"
a1-a4代表R0-R3,在使用汇编语言写函数时,这四个寄存器在结束时不需要恢复成原值,因此在进入函数时不需要保存
R14~R11通常保存程序的局部变量,也可以用V1~V8表示,但是V1~V4只能在Thumb状态下使用。 R12~R15一般有特殊用途,也通常称为IP,SP,LR,PC。
定义的浮点数寄存器名 f0~f7 F0~F7
定义的协处理器名 p0~p15 寄存器c0~c15,具体参考给定的协处理器。
"
所以,简单解释就是,你用bl调用C的函数时候,传递的参数:
(1)小于等于4个参数时,分别是放在arm的寄存器r0,r1,r2,r3里面的。
(2)大于4个,前四个放在r0-r3,剩下的,以此放到堆栈里面,即用push指令把参数压栈
也正因此,才有这样的说法“最好定义接受 4 个或更少的参数的函数”,即写C程序的时候,最好函数参数不超过4个,否则其生成汇编代码,就有额外利用堆栈来传递你的参数,那肯定没有直接用寄存器传递参数效率高。
关于你的参数是结构体的话,那么传递参数有两种方式:
(1)直接传递整个结构体变量,即整个传递参数的大小,和你结构体一样大,对于小的结构体还算合理,对于大的结构体,就不是个好方法,因为也会涉及到参数太大,寄存器放不下,要利用堆栈传递整个结构体。
(2)只是传递结构体变量所对应的指针,而指针只有4个字节,所以就相当于传递普通一个4字节的变量,对应汇编就可以只需要r0来传递此参数即可,相对上面利用堆栈的方式,效率较高。
总的来说,对于结构体,推荐用传递结构体指针的方式来传递参数。
关于函数返回值的传递,引用附件中的内容:
“函数退出通过把返回连接值传送到程序计数器中来退出函数,并且: - 如果函数返回一个小于等于一个字大小的值,则把这个值放置到 a1 中。
- 如果函数返回一个浮点值,则把它放入 f0 中。
- sp、fp、sl、v1-v6、和 f4-f7 应当被恢复(如果被改动了)为包含在进入函数时它所持有的值。
我测试了故意的破坏寄存器,而结果是(经常在程序完全不同的部分)出现不希望的和奇异的故障。 - ip、lr、a2-a4、f1-f3 和入栈的这些实参可以被破坏。
在 32 位模式下,不需要对 PSR 标志进行跨越函数调用的保护。在 26 位模式下必须这样,并通过传送 lr 到 pc 中(MOVS、或 LDMFD xxx^)来暗中恢复。必须从 lr 重新装载 N、Z、C 和 V,跨越函数保护这些标志不是足够的。 ”
简单说,也就是通过r0传递函数的返回值。
其他关于软中断的事情,不太了解。 |
|